1e169cfbeSGrant Likely /* 2e169cfbeSGrant Likely * Functions for working with the Flattened Device Tree data format 3e169cfbeSGrant Likely * 4e169cfbeSGrant Likely * Copyright 2009 Benjamin Herrenschmidt, IBM Corp 5e169cfbeSGrant Likely * benh@kernel.crashing.org 6e169cfbeSGrant Likely * 7e169cfbeSGrant Likely * This program is free software; you can redistribute it and/or 8e169cfbeSGrant Likely * modify it under the terms of the GNU General Public License 9e169cfbeSGrant Likely * version 2 as published by the Free Software Foundation. 10e169cfbeSGrant Likely */ 11e169cfbeSGrant Likely 12606ad42aSRob Herring #define pr_fmt(fmt) "OF: fdt:" fmt 13606ad42aSRob Herring 1408d53aa5SArd Biesheuvel #include <linux/crc32.h> 1541f88009SGrant Likely #include <linux/kernel.h> 16f7b3a835SGrant Likely #include <linux/initrd.h> 17a1727da5SGrant Likely #include <linux/memblock.h> 18f8062386SGuenter Roeck #include <linux/mutex.h> 19e169cfbeSGrant Likely #include <linux/of.h> 20e169cfbeSGrant Likely #include <linux/of_fdt.h> 213f0c8206SMarek Szyprowski #include <linux/of_reserved_mem.h> 22e8d9d1f5SMarek Szyprowski #include <linux/sizes.h> 234ef7b373SJeremy Kerr #include <linux/string.h> 244ef7b373SJeremy Kerr #include <linux/errno.h> 25fe140423SStephen Neuendorffer #include <linux/slab.h> 26e6a6928cSRob Herring #include <linux/libfdt.h> 27b0a6fb36SRob Herring #include <linux/debugfs.h> 28fb11ffe7SRob Herring #include <linux/serial_core.h> 2908d53aa5SArd Biesheuvel #include <linux/sysfs.h> 3051975db0SGrant Likely 31c89810acSFabio Estevam #include <asm/setup.h> /* for COMMAND_LINE_SIZE */ 324ef7b373SJeremy Kerr #include <asm/page.h> 334ef7b373SJeremy Kerr 34704033ceSLaura Abbott /* 35704033ceSLaura Abbott * of_fdt_limit_memory - limit the number of regions in the /memory node 36704033ceSLaura Abbott * @limit: maximum entries 37704033ceSLaura Abbott * 38704033ceSLaura Abbott * Adjust the flattened device tree to have at most 'limit' number of 39704033ceSLaura Abbott * memory entries in the /memory node. This function may be called 40704033ceSLaura Abbott * any time after initial_boot_param is set. 41704033ceSLaura Abbott */ 42704033ceSLaura Abbott void of_fdt_limit_memory(int limit) 43704033ceSLaura Abbott { 44704033ceSLaura Abbott int memory; 45704033ceSLaura Abbott int len; 46704033ceSLaura Abbott const void *val; 47704033ceSLaura Abbott int nr_address_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT; 48704033ceSLaura Abbott int nr_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT; 49704033ceSLaura Abbott const uint32_t *addr_prop; 50704033ceSLaura Abbott const uint32_t *size_prop; 51704033ceSLaura Abbott int root_offset; 52704033ceSLaura Abbott int cell_size; 53704033ceSLaura Abbott 54704033ceSLaura Abbott root_offset = fdt_path_offset(initial_boot_params, "/"); 55704033ceSLaura Abbott if (root_offset < 0) 56704033ceSLaura Abbott return; 57704033ceSLaura Abbott 58704033ceSLaura Abbott addr_prop = fdt_getprop(initial_boot_params, root_offset, 59704033ceSLaura Abbott "#address-cells", NULL); 60704033ceSLaura Abbott if (addr_prop) 61704033ceSLaura Abbott nr_address_cells = fdt32_to_cpu(*addr_prop); 62704033ceSLaura Abbott 63704033ceSLaura Abbott size_prop = fdt_getprop(initial_boot_params, root_offset, 64704033ceSLaura Abbott "#size-cells", NULL); 65704033ceSLaura Abbott if (size_prop) 66704033ceSLaura Abbott nr_size_cells = fdt32_to_cpu(*size_prop); 67704033ceSLaura Abbott 68704033ceSLaura Abbott cell_size = sizeof(uint32_t)*(nr_address_cells + nr_size_cells); 69704033ceSLaura Abbott 70704033ceSLaura Abbott memory = fdt_path_offset(initial_boot_params, "/memory"); 71704033ceSLaura Abbott if (memory > 0) { 72704033ceSLaura Abbott val = fdt_getprop(initial_boot_params, memory, "reg", &len); 73704033ceSLaura Abbott if (len > limit*cell_size) { 74704033ceSLaura Abbott len = limit*cell_size; 75704033ceSLaura Abbott pr_debug("Limiting number of entries to %d\n", limit); 76704033ceSLaura Abbott fdt_setprop(initial_boot_params, memory, "reg", val, 77704033ceSLaura Abbott len); 78704033ceSLaura Abbott } 79704033ceSLaura Abbott } 80704033ceSLaura Abbott } 81704033ceSLaura Abbott 829706a36eSStephen Neuendorffer /** 839706a36eSStephen Neuendorffer * of_fdt_is_compatible - Return true if given node from the given blob has 849706a36eSStephen Neuendorffer * compat in its compatible list 859706a36eSStephen Neuendorffer * @blob: A device tree blob 869706a36eSStephen Neuendorffer * @node: node to test 879706a36eSStephen Neuendorffer * @compat: compatible string to compare with compatible list. 88a4f740cfSGrant Likely * 89a4f740cfSGrant Likely * On match, returns a non-zero value with smaller values returned for more 90a4f740cfSGrant Likely * specific compatible values. 919706a36eSStephen Neuendorffer */ 92c972de14SRob Herring int of_fdt_is_compatible(const void *blob, 939706a36eSStephen Neuendorffer unsigned long node, const char *compat) 949706a36eSStephen Neuendorffer { 959706a36eSStephen Neuendorffer const char *cp; 969d0c4dfeSRob Herring int cplen; 979d0c4dfeSRob Herring unsigned long l, score = 0; 989706a36eSStephen Neuendorffer 99e6a6928cSRob Herring cp = fdt_getprop(blob, node, "compatible", &cplen); 1009706a36eSStephen Neuendorffer if (cp == NULL) 1019706a36eSStephen Neuendorffer return 0; 1029706a36eSStephen Neuendorffer while (cplen > 0) { 103a4f740cfSGrant Likely score++; 1049706a36eSStephen Neuendorffer if (of_compat_cmp(cp, compat, strlen(compat)) == 0) 105a4f740cfSGrant Likely return score; 1069706a36eSStephen Neuendorffer l = strlen(cp) + 1; 1079706a36eSStephen Neuendorffer cp += l; 1089706a36eSStephen Neuendorffer cplen -= l; 1099706a36eSStephen Neuendorffer } 1109706a36eSStephen Neuendorffer 1119706a36eSStephen Neuendorffer return 0; 1129706a36eSStephen Neuendorffer } 1139706a36eSStephen Neuendorffer 114a4f740cfSGrant Likely /** 115cc783786SKevin Cernekee * of_fdt_is_big_endian - Return true if given node needs BE MMIO accesses 116cc783786SKevin Cernekee * @blob: A device tree blob 117cc783786SKevin Cernekee * @node: node to test 118cc783786SKevin Cernekee * 119cc783786SKevin Cernekee * Returns true if the node has a "big-endian" property, or if the kernel 120cc783786SKevin Cernekee * was compiled for BE *and* the node has a "native-endian" property. 121cc783786SKevin Cernekee * Returns false otherwise. 122cc783786SKevin Cernekee */ 123cc783786SKevin Cernekee bool of_fdt_is_big_endian(const void *blob, unsigned long node) 124cc783786SKevin Cernekee { 125cc783786SKevin Cernekee if (fdt_getprop(blob, node, "big-endian", NULL)) 126cc783786SKevin Cernekee return true; 127cc783786SKevin Cernekee if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && 128cc783786SKevin Cernekee fdt_getprop(blob, node, "native-endian", NULL)) 129cc783786SKevin Cernekee return true; 130cc783786SKevin Cernekee return false; 131cc783786SKevin Cernekee } 132cc783786SKevin Cernekee 133cc783786SKevin Cernekee /** 134a4f740cfSGrant Likely * of_fdt_match - Return true if node matches a list of compatible values 135a4f740cfSGrant Likely */ 136c972de14SRob Herring int of_fdt_match(const void *blob, unsigned long node, 1377b482c83SUwe Kleine-König const char *const *compat) 138a4f740cfSGrant Likely { 139a4f740cfSGrant Likely unsigned int tmp, score = 0; 140a4f740cfSGrant Likely 141a4f740cfSGrant Likely if (!compat) 142a4f740cfSGrant Likely return 0; 143a4f740cfSGrant Likely 144a4f740cfSGrant Likely while (*compat) { 145a4f740cfSGrant Likely tmp = of_fdt_is_compatible(blob, node, *compat); 146a4f740cfSGrant Likely if (tmp && (score == 0 || (tmp < score))) 147a4f740cfSGrant Likely score = tmp; 148a4f740cfSGrant Likely compat++; 149a4f740cfSGrant Likely } 150a4f740cfSGrant Likely 151a4f740cfSGrant Likely return score; 152a4f740cfSGrant Likely } 153a4f740cfSGrant Likely 15444856819SGrant Likely static void *unflatten_dt_alloc(void **mem, unsigned long size, 155bbd33931SGrant Likely unsigned long align) 156bbd33931SGrant Likely { 157bbd33931SGrant Likely void *res; 158bbd33931SGrant Likely 15944856819SGrant Likely *mem = PTR_ALIGN(*mem, align); 16044856819SGrant Likely res = *mem; 161bbd33931SGrant Likely *mem += size; 162bbd33931SGrant Likely 163bbd33931SGrant Likely return res; 164bbd33931SGrant Likely } 165bbd33931SGrant Likely 166dfbd4c6eSGavin Shan static void populate_properties(const void *blob, 167dfbd4c6eSGavin Shan int offset, 168dfbd4c6eSGavin Shan void **mem, 169dfbd4c6eSGavin Shan struct device_node *np, 170dfbd4c6eSGavin Shan const char *nodename, 1715063e25aSGrant Likely bool dryrun) 172bbd33931SGrant Likely { 173dfbd4c6eSGavin Shan struct property *pp, **pprev = NULL; 174dfbd4c6eSGavin Shan int cur; 175dfbd4c6eSGavin Shan bool has_name = false; 176dfbd4c6eSGavin Shan 177dfbd4c6eSGavin Shan pprev = &np->properties; 178dfbd4c6eSGavin Shan for (cur = fdt_first_property_offset(blob, offset); 179dfbd4c6eSGavin Shan cur >= 0; 180dfbd4c6eSGavin Shan cur = fdt_next_property_offset(blob, cur)) { 181dfbd4c6eSGavin Shan const __be32 *val; 182dfbd4c6eSGavin Shan const char *pname; 183dfbd4c6eSGavin Shan u32 sz; 184dfbd4c6eSGavin Shan 185dfbd4c6eSGavin Shan val = fdt_getprop_by_offset(blob, cur, &pname, &sz); 186dfbd4c6eSGavin Shan if (!val) { 187606ad42aSRob Herring pr_warn("Cannot locate property at 0x%x\n", cur); 188dfbd4c6eSGavin Shan continue; 189dfbd4c6eSGavin Shan } 190dfbd4c6eSGavin Shan 191dfbd4c6eSGavin Shan if (!pname) { 192606ad42aSRob Herring pr_warn("Cannot find property name at 0x%x\n", cur); 193dfbd4c6eSGavin Shan continue; 194dfbd4c6eSGavin Shan } 195dfbd4c6eSGavin Shan 196dfbd4c6eSGavin Shan if (!strcmp(pname, "name")) 197dfbd4c6eSGavin Shan has_name = true; 198dfbd4c6eSGavin Shan 199dfbd4c6eSGavin Shan pp = unflatten_dt_alloc(mem, sizeof(struct property), 200dfbd4c6eSGavin Shan __alignof__(struct property)); 201dfbd4c6eSGavin Shan if (dryrun) 202dfbd4c6eSGavin Shan continue; 203dfbd4c6eSGavin Shan 204dfbd4c6eSGavin Shan /* We accept flattened tree phandles either in 205dfbd4c6eSGavin Shan * ePAPR-style "phandle" properties, or the 206dfbd4c6eSGavin Shan * legacy "linux,phandle" properties. If both 207dfbd4c6eSGavin Shan * appear and have different values, things 208dfbd4c6eSGavin Shan * will get weird. Don't do that. 209dfbd4c6eSGavin Shan */ 210dfbd4c6eSGavin Shan if (!strcmp(pname, "phandle") || 211dfbd4c6eSGavin Shan !strcmp(pname, "linux,phandle")) { 212dfbd4c6eSGavin Shan if (!np->phandle) 213dfbd4c6eSGavin Shan np->phandle = be32_to_cpup(val); 214dfbd4c6eSGavin Shan } 215dfbd4c6eSGavin Shan 216dfbd4c6eSGavin Shan /* And we process the "ibm,phandle" property 217dfbd4c6eSGavin Shan * used in pSeries dynamic device tree 218dfbd4c6eSGavin Shan * stuff 219dfbd4c6eSGavin Shan */ 220dfbd4c6eSGavin Shan if (!strcmp(pname, "ibm,phandle")) 221dfbd4c6eSGavin Shan np->phandle = be32_to_cpup(val); 222dfbd4c6eSGavin Shan 223dfbd4c6eSGavin Shan pp->name = (char *)pname; 224dfbd4c6eSGavin Shan pp->length = sz; 225dfbd4c6eSGavin Shan pp->value = (__be32 *)val; 226dfbd4c6eSGavin Shan *pprev = pp; 227dfbd4c6eSGavin Shan pprev = &pp->next; 228dfbd4c6eSGavin Shan } 229dfbd4c6eSGavin Shan 230dfbd4c6eSGavin Shan /* With version 0x10 we may not have the name property, 231dfbd4c6eSGavin Shan * recreate it here from the unit name if absent 232dfbd4c6eSGavin Shan */ 233dfbd4c6eSGavin Shan if (!has_name) { 234dfbd4c6eSGavin Shan const char *p = nodename, *ps = p, *pa = NULL; 235dfbd4c6eSGavin Shan int len; 236dfbd4c6eSGavin Shan 237dfbd4c6eSGavin Shan while (*p) { 238dfbd4c6eSGavin Shan if ((*p) == '@') 239dfbd4c6eSGavin Shan pa = p; 240dfbd4c6eSGavin Shan else if ((*p) == '/') 241dfbd4c6eSGavin Shan ps = p + 1; 242dfbd4c6eSGavin Shan p++; 243dfbd4c6eSGavin Shan } 244dfbd4c6eSGavin Shan 245dfbd4c6eSGavin Shan if (pa < ps) 246dfbd4c6eSGavin Shan pa = p; 247dfbd4c6eSGavin Shan len = (pa - ps) + 1; 248dfbd4c6eSGavin Shan pp = unflatten_dt_alloc(mem, sizeof(struct property) + len, 249dfbd4c6eSGavin Shan __alignof__(struct property)); 250dfbd4c6eSGavin Shan if (!dryrun) { 251dfbd4c6eSGavin Shan pp->name = "name"; 252dfbd4c6eSGavin Shan pp->length = len; 253dfbd4c6eSGavin Shan pp->value = pp + 1; 254dfbd4c6eSGavin Shan *pprev = pp; 255dfbd4c6eSGavin Shan pprev = &pp->next; 256dfbd4c6eSGavin Shan memcpy(pp->value, ps, len - 1); 257dfbd4c6eSGavin Shan ((char *)pp->value)[len - 1] = 0; 258dfbd4c6eSGavin Shan pr_debug("fixed up name for %s -> %s\n", 259dfbd4c6eSGavin Shan nodename, (char *)pp->value); 260dfbd4c6eSGavin Shan } 261dfbd4c6eSGavin Shan } 262dfbd4c6eSGavin Shan 263dfbd4c6eSGavin Shan if (!dryrun) 264dfbd4c6eSGavin Shan *pprev = NULL; 265dfbd4c6eSGavin Shan } 266dfbd4c6eSGavin Shan 267dddc33e5SGavin Shan static unsigned int populate_node(const void *blob, 268dfbd4c6eSGavin Shan int offset, 269dfbd4c6eSGavin Shan void **mem, 270dfbd4c6eSGavin Shan struct device_node *dad, 271dddc33e5SGavin Shan unsigned int fpsize, 272dfbd4c6eSGavin Shan struct device_node **pnp, 273dfbd4c6eSGavin Shan bool dryrun) 274dfbd4c6eSGavin Shan { 275bbd33931SGrant Likely struct device_node *np; 276e6a6928cSRob Herring const char *pathp; 277bbd33931SGrant Likely unsigned int l, allocl; 278bbd33931SGrant Likely int new_format = 0; 279bbd33931SGrant Likely 280dfbd4c6eSGavin Shan pathp = fdt_get_name(blob, offset, &l); 281dfbd4c6eSGavin Shan if (!pathp) { 282dfbd4c6eSGavin Shan *pnp = NULL; 283dfbd4c6eSGavin Shan return 0; 284dfbd4c6eSGavin Shan } 285e6a6928cSRob Herring 28605f4647bSRicky Liang allocl = ++l; 287bbd33931SGrant Likely 288bbd33931SGrant Likely /* version 0x10 has a more compact unit name here instead of the full 289bbd33931SGrant Likely * path. we accumulate the full path size using "fpsize", we'll rebuild 290bbd33931SGrant Likely * it later. We detect this because the first character of the name is 291bbd33931SGrant Likely * not '/'. 292bbd33931SGrant Likely */ 293bbd33931SGrant Likely if ((*pathp) != '/') { 294bbd33931SGrant Likely new_format = 1; 295bbd33931SGrant Likely if (fpsize == 0) { 296bbd33931SGrant Likely /* root node: special case. fpsize accounts for path 297bbd33931SGrant Likely * plus terminating zero. root node only has '/', so 298bbd33931SGrant Likely * fpsize should be 2, but we want to avoid the first 299bbd33931SGrant Likely * level nodes to have two '/' so we use fpsize 1 here 300bbd33931SGrant Likely */ 301bbd33931SGrant Likely fpsize = 1; 302bbd33931SGrant Likely allocl = 2; 3030fca5deaSCatalin Marinas l = 1; 304e6a6928cSRob Herring pathp = ""; 305bbd33931SGrant Likely } else { 306bbd33931SGrant Likely /* account for '/' and path size minus terminal 0 307bbd33931SGrant Likely * already in 'l' 308bbd33931SGrant Likely */ 309bbd33931SGrant Likely fpsize += l; 310bbd33931SGrant Likely allocl = fpsize; 311bbd33931SGrant Likely } 312bbd33931SGrant Likely } 313bbd33931SGrant Likely 314dfbd4c6eSGavin Shan np = unflatten_dt_alloc(mem, sizeof(struct device_node) + allocl, 315bbd33931SGrant Likely __alignof__(struct device_node)); 3165063e25aSGrant Likely if (!dryrun) { 317c22618a1SGrant Likely char *fn; 3180829f6d1SPantelis Antoniou of_node_init(np); 319c22618a1SGrant Likely np->full_name = fn = ((char *)np) + sizeof(*np); 320bbd33931SGrant Likely if (new_format) { 321bbd33931SGrant Likely /* rebuild full path for new format */ 322bbd33931SGrant Likely if (dad && dad->parent) { 323bbd33931SGrant Likely strcpy(fn, dad->full_name); 324bbd33931SGrant Likely #ifdef DEBUG 325bbd33931SGrant Likely if ((strlen(fn) + l + 1) != allocl) { 326bbd33931SGrant Likely pr_debug("%s: p: %d, l: %d, a: %d\n", 327bbd33931SGrant Likely pathp, (int)strlen(fn), 328bbd33931SGrant Likely l, allocl); 329bbd33931SGrant Likely } 330bbd33931SGrant Likely #endif 331bbd33931SGrant Likely fn += strlen(fn); 332bbd33931SGrant Likely } 333bbd33931SGrant Likely *(fn++) = '/'; 334c22618a1SGrant Likely } 335bbd33931SGrant Likely memcpy(fn, pathp, l); 336c22618a1SGrant Likely 337bbd33931SGrant Likely if (dad != NULL) { 338bbd33931SGrant Likely np->parent = dad; 33970161ff3SGrant Likely np->sibling = dad->child; 340bbd33931SGrant Likely dad->child = np; 341bbd33931SGrant Likely } 342bbd33931SGrant Likely } 343bbd33931SGrant Likely 344dfbd4c6eSGavin Shan populate_properties(blob, offset, mem, np, pathp, dryrun); 3455063e25aSGrant Likely if (!dryrun) { 346bbd33931SGrant Likely np->name = of_get_property(np, "name", NULL); 347bbd33931SGrant Likely np->type = of_get_property(np, "device_type", NULL); 348bbd33931SGrant Likely 349bbd33931SGrant Likely if (!np->name) 350bbd33931SGrant Likely np->name = "<NULL>"; 351bbd33931SGrant Likely if (!np->type) 352bbd33931SGrant Likely np->type = "<NULL>"; 353bbd33931SGrant Likely } 354e6a6928cSRob Herring 355dfbd4c6eSGavin Shan *pnp = np; 356dfbd4c6eSGavin Shan return fpsize; 357dfbd4c6eSGavin Shan } 358dfbd4c6eSGavin Shan 35950800082SGavin Shan static void reverse_nodes(struct device_node *parent) 36050800082SGavin Shan { 36150800082SGavin Shan struct device_node *child, *next; 36250800082SGavin Shan 36350800082SGavin Shan /* In-depth first */ 36450800082SGavin Shan child = parent->child; 36550800082SGavin Shan while (child) { 36650800082SGavin Shan reverse_nodes(child); 36750800082SGavin Shan 36850800082SGavin Shan child = child->sibling; 36950800082SGavin Shan } 37050800082SGavin Shan 37150800082SGavin Shan /* Reverse the nodes in the child list */ 37250800082SGavin Shan child = parent->child; 37350800082SGavin Shan parent->child = NULL; 37450800082SGavin Shan while (child) { 37550800082SGavin Shan next = child->sibling; 37650800082SGavin Shan 37750800082SGavin Shan child->sibling = parent->child; 37850800082SGavin Shan parent->child = child; 37950800082SGavin Shan child = next; 38050800082SGavin Shan } 38150800082SGavin Shan } 38250800082SGavin Shan 383dfbd4c6eSGavin Shan /** 384947c82cbSGavin Shan * unflatten_dt_nodes - Alloc and populate a device_node from the flat tree 385dfbd4c6eSGavin Shan * @blob: The parent device tree blob 386dfbd4c6eSGavin Shan * @mem: Memory chunk to use for allocating device nodes and properties 387dfbd4c6eSGavin Shan * @dad: Parent struct device_node 388dfbd4c6eSGavin Shan * @nodepp: The device_node tree created by the call 38950800082SGavin Shan * 39050800082SGavin Shan * It returns the size of unflattened device tree or error code 391dfbd4c6eSGavin Shan */ 392947c82cbSGavin Shan static int unflatten_dt_nodes(const void *blob, 393dfbd4c6eSGavin Shan void *mem, 394dfbd4c6eSGavin Shan struct device_node *dad, 39550800082SGavin Shan struct device_node **nodepp) 396dfbd4c6eSGavin Shan { 39750800082SGavin Shan struct device_node *root; 3988c237cd0SGavin Shan int offset = 0, depth = 0, initial_depth = 0; 39950800082SGavin Shan #define FDT_MAX_DEPTH 64 400dddc33e5SGavin Shan unsigned int fpsizes[FDT_MAX_DEPTH]; 40150800082SGavin Shan struct device_node *nps[FDT_MAX_DEPTH]; 40250800082SGavin Shan void *base = mem; 40350800082SGavin Shan bool dryrun = !base; 404dfbd4c6eSGavin Shan 40550800082SGavin Shan if (nodepp) 40650800082SGavin Shan *nodepp = NULL; 407dfbd4c6eSGavin Shan 4088c237cd0SGavin Shan /* 4098c237cd0SGavin Shan * We're unflattening device sub-tree if @dad is valid. There are 4108c237cd0SGavin Shan * possibly multiple nodes in the first level of depth. We need 4118c237cd0SGavin Shan * set @depth to 1 to make fdt_next_node() happy as it bails 4128c237cd0SGavin Shan * immediately when negative @depth is found. Otherwise, the device 4138c237cd0SGavin Shan * nodes except the first one won't be unflattened successfully. 4148c237cd0SGavin Shan */ 4158c237cd0SGavin Shan if (dad) 4168c237cd0SGavin Shan depth = initial_depth = 1; 4178c237cd0SGavin Shan 41850800082SGavin Shan root = dad; 41950800082SGavin Shan fpsizes[depth] = dad ? strlen(of_node_full_name(dad)) : 0; 42078c44d91SRhyland Klein nps[depth] = dad; 4218c237cd0SGavin Shan 42250800082SGavin Shan for (offset = 0; 4238c237cd0SGavin Shan offset >= 0 && depth >= initial_depth; 42450800082SGavin Shan offset = fdt_next_node(blob, offset, &depth)) { 42550800082SGavin Shan if (WARN_ON_ONCE(depth >= FDT_MAX_DEPTH)) 42650800082SGavin Shan continue; 427e6a6928cSRob Herring 42878c44d91SRhyland Klein fpsizes[depth+1] = populate_node(blob, offset, &mem, 42978c44d91SRhyland Klein nps[depth], 43078c44d91SRhyland Klein fpsizes[depth], 43178c44d91SRhyland Klein &nps[depth+1], dryrun); 43278c44d91SRhyland Klein if (!fpsizes[depth+1]) 43350800082SGavin Shan return mem - base; 43450800082SGavin Shan 43550800082SGavin Shan if (!dryrun && nodepp && !*nodepp) 43678c44d91SRhyland Klein *nodepp = nps[depth+1]; 43750800082SGavin Shan if (!dryrun && !root) 43878c44d91SRhyland Klein root = nps[depth+1]; 43950800082SGavin Shan } 44050800082SGavin Shan 44150800082SGavin Shan if (offset < 0 && offset != -FDT_ERR_NOTFOUND) { 442606ad42aSRob Herring pr_err("Error %d processing FDT\n", offset); 44350800082SGavin Shan return -EINVAL; 44450800082SGavin Shan } 445e6a6928cSRob Herring 44670161ff3SGrant Likely /* 44770161ff3SGrant Likely * Reverse the child list. Some drivers assumes node order matches .dts 44870161ff3SGrant Likely * node order 44970161ff3SGrant Likely */ 45050800082SGavin Shan if (!dryrun) 45150800082SGavin Shan reverse_nodes(root); 45270161ff3SGrant Likely 45350800082SGavin Shan return mem - base; 454bbd33931SGrant Likely } 45541f88009SGrant Likely 456fe140423SStephen Neuendorffer /** 457fe140423SStephen Neuendorffer * __unflatten_device_tree - create tree of device_nodes from flat blob 458fe140423SStephen Neuendorffer * 459fe140423SStephen Neuendorffer * unflattens a device-tree, creating the 460fe140423SStephen Neuendorffer * tree of struct device_node. It also fills the "name" and "type" 461fe140423SStephen Neuendorffer * pointers of the nodes so the normal device-tree walking functions 462fe140423SStephen Neuendorffer * can be used. 463fe140423SStephen Neuendorffer * @blob: The blob to expand 464c4263233SGavin Shan * @dad: Parent device node 465fe140423SStephen Neuendorffer * @mynodes: The device_node tree created by the call 466fe140423SStephen Neuendorffer * @dt_alloc: An allocator that provides a virtual address to memory 467fe140423SStephen Neuendorffer * for the resulting tree 46883262418SGavin Shan * 46983262418SGavin Shan * Returns NULL on failure or the memory chunk containing the unflattened 47083262418SGavin Shan * device tree on success. 471fe140423SStephen Neuendorffer */ 47283262418SGavin Shan static void *__unflatten_device_tree(const void *blob, 473c4263233SGavin Shan struct device_node *dad, 474fe140423SStephen Neuendorffer struct device_node **mynodes, 475fe140423SStephen Neuendorffer void *(*dt_alloc)(u64 size, u64 align)) 476fe140423SStephen Neuendorffer { 47750800082SGavin Shan int size; 478e6a6928cSRob Herring void *mem; 479fe140423SStephen Neuendorffer 480fe140423SStephen Neuendorffer pr_debug(" -> unflatten_device_tree()\n"); 481fe140423SStephen Neuendorffer 482fe140423SStephen Neuendorffer if (!blob) { 483fe140423SStephen Neuendorffer pr_debug("No device tree pointer\n"); 48483262418SGavin Shan return NULL; 485fe140423SStephen Neuendorffer } 486fe140423SStephen Neuendorffer 487fe140423SStephen Neuendorffer pr_debug("Unflattening device tree:\n"); 488c972de14SRob Herring pr_debug("magic: %08x\n", fdt_magic(blob)); 489c972de14SRob Herring pr_debug("size: %08x\n", fdt_totalsize(blob)); 490c972de14SRob Herring pr_debug("version: %08x\n", fdt_version(blob)); 491fe140423SStephen Neuendorffer 492c972de14SRob Herring if (fdt_check_header(blob)) { 493fe140423SStephen Neuendorffer pr_err("Invalid device tree blob header\n"); 49483262418SGavin Shan return NULL; 495fe140423SStephen Neuendorffer } 496fe140423SStephen Neuendorffer 497fe140423SStephen Neuendorffer /* First pass, scan for size */ 498c4263233SGavin Shan size = unflatten_dt_nodes(blob, NULL, dad, NULL); 49950800082SGavin Shan if (size < 0) 50083262418SGavin Shan return NULL; 501fe140423SStephen Neuendorffer 50250800082SGavin Shan size = ALIGN(size, 4); 50350800082SGavin Shan pr_debug(" size is %d, allocating...\n", size); 504fe140423SStephen Neuendorffer 505fe140423SStephen Neuendorffer /* Allocate memory for the expanded device tree */ 50644856819SGrant Likely mem = dt_alloc(size + 4, __alignof__(struct device_node)); 50744856819SGrant Likely memset(mem, 0, size); 508fe140423SStephen Neuendorffer 50944856819SGrant Likely *(__be32 *)(mem + size) = cpu_to_be32(0xdeadbeef); 5109e401275SWladislav Wiebe 51144856819SGrant Likely pr_debug(" unflattening %p...\n", mem); 512fe140423SStephen Neuendorffer 513fe140423SStephen Neuendorffer /* Second pass, do actual unflattening */ 514c4263233SGavin Shan unflatten_dt_nodes(blob, mem, dad, mynodes); 51544856819SGrant Likely if (be32_to_cpup(mem + size) != 0xdeadbeef) 516fe140423SStephen Neuendorffer pr_warning("End of tree marker overwritten: %08x\n", 51744856819SGrant Likely be32_to_cpup(mem + size)); 518fe140423SStephen Neuendorffer 519fe140423SStephen Neuendorffer pr_debug(" <- unflatten_device_tree()\n"); 52083262418SGavin Shan return mem; 521fe140423SStephen Neuendorffer } 522fe140423SStephen Neuendorffer 523fe140423SStephen Neuendorffer static void *kernel_tree_alloc(u64 size, u64 align) 524fe140423SStephen Neuendorffer { 525fe140423SStephen Neuendorffer return kzalloc(size, GFP_KERNEL); 526fe140423SStephen Neuendorffer } 527fe140423SStephen Neuendorffer 528f8062386SGuenter Roeck static DEFINE_MUTEX(of_fdt_unflatten_mutex); 529f8062386SGuenter Roeck 530fe140423SStephen Neuendorffer /** 531fe140423SStephen Neuendorffer * of_fdt_unflatten_tree - create tree of device_nodes from flat blob 532c4263233SGavin Shan * @blob: Flat device tree blob 533c4263233SGavin Shan * @dad: Parent device node 534c4263233SGavin Shan * @mynodes: The device tree created by the call 535fe140423SStephen Neuendorffer * 536fe140423SStephen Neuendorffer * unflattens the device-tree passed by the firmware, creating the 537fe140423SStephen Neuendorffer * tree of struct device_node. It also fills the "name" and "type" 538fe140423SStephen Neuendorffer * pointers of the nodes so the normal device-tree walking functions 539fe140423SStephen Neuendorffer * can be used. 54083262418SGavin Shan * 54183262418SGavin Shan * Returns NULL on failure or the memory chunk containing the unflattened 54283262418SGavin Shan * device tree on success. 543fe140423SStephen Neuendorffer */ 54483262418SGavin Shan void *of_fdt_unflatten_tree(const unsigned long *blob, 545c4263233SGavin Shan struct device_node *dad, 546fe140423SStephen Neuendorffer struct device_node **mynodes) 547fe140423SStephen Neuendorffer { 54883262418SGavin Shan void *mem; 54983262418SGavin Shan 550f8062386SGuenter Roeck mutex_lock(&of_fdt_unflatten_mutex); 55183262418SGavin Shan mem = __unflatten_device_tree(blob, dad, mynodes, &kernel_tree_alloc); 552f8062386SGuenter Roeck mutex_unlock(&of_fdt_unflatten_mutex); 55383262418SGavin Shan 55483262418SGavin Shan return mem; 555fe140423SStephen Neuendorffer } 556fe140423SStephen Neuendorffer EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree); 557fe140423SStephen Neuendorffer 55857d00ecfSStephen Neuendorffer /* Everything below here references initial_boot_params directly. */ 55957d00ecfSStephen Neuendorffer int __initdata dt_root_addr_cells; 56057d00ecfSStephen Neuendorffer int __initdata dt_root_size_cells; 56157d00ecfSStephen Neuendorffer 5621daa0c4cSRob Herring void *initial_boot_params; 56357d00ecfSStephen Neuendorffer 56457d00ecfSStephen Neuendorffer #ifdef CONFIG_OF_EARLY_FLATTREE 56557d00ecfSStephen Neuendorffer 56608d53aa5SArd Biesheuvel static u32 of_fdt_crc32; 56708d53aa5SArd Biesheuvel 56857d00ecfSStephen Neuendorffer /** 569e8d9d1f5SMarek Szyprowski * res_mem_reserve_reg() - reserve all memory described in 'reg' property 570e8d9d1f5SMarek Szyprowski */ 571e8d9d1f5SMarek Szyprowski static int __init __reserved_mem_reserve_reg(unsigned long node, 572e8d9d1f5SMarek Szyprowski const char *uname) 573e8d9d1f5SMarek Szyprowski { 574e8d9d1f5SMarek Szyprowski int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32); 575e8d9d1f5SMarek Szyprowski phys_addr_t base, size; 5769d0c4dfeSRob Herring int len; 5779d0c4dfeSRob Herring const __be32 *prop; 5783f0c8206SMarek Szyprowski int nomap, first = 1; 579e8d9d1f5SMarek Szyprowski 580e8d9d1f5SMarek Szyprowski prop = of_get_flat_dt_prop(node, "reg", &len); 581e8d9d1f5SMarek Szyprowski if (!prop) 582e8d9d1f5SMarek Szyprowski return -ENOENT; 583e8d9d1f5SMarek Szyprowski 584e8d9d1f5SMarek Szyprowski if (len && len % t_len != 0) { 585e8d9d1f5SMarek Szyprowski pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n", 586e8d9d1f5SMarek Szyprowski uname); 587e8d9d1f5SMarek Szyprowski return -EINVAL; 588e8d9d1f5SMarek Szyprowski } 589e8d9d1f5SMarek Szyprowski 590e8d9d1f5SMarek Szyprowski nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL; 591e8d9d1f5SMarek Szyprowski 592e8d9d1f5SMarek Szyprowski while (len >= t_len) { 593e8d9d1f5SMarek Szyprowski base = dt_mem_next_cell(dt_root_addr_cells, &prop); 594e8d9d1f5SMarek Szyprowski size = dt_mem_next_cell(dt_root_size_cells, &prop); 595e8d9d1f5SMarek Szyprowski 596b5f2a8c0SAl Cooper if (size && 597e8d9d1f5SMarek Szyprowski early_init_dt_reserve_memory_arch(base, size, nomap) == 0) 598e8d9d1f5SMarek Szyprowski pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %ld MiB\n", 599e8d9d1f5SMarek Szyprowski uname, &base, (unsigned long)size / SZ_1M); 600e8d9d1f5SMarek Szyprowski else 601e8d9d1f5SMarek Szyprowski pr_info("Reserved memory: failed to reserve memory for node '%s': base %pa, size %ld MiB\n", 602e8d9d1f5SMarek Szyprowski uname, &base, (unsigned long)size / SZ_1M); 603e8d9d1f5SMarek Szyprowski 604e8d9d1f5SMarek Szyprowski len -= t_len; 6053f0c8206SMarek Szyprowski if (first) { 6063f0c8206SMarek Szyprowski fdt_reserved_mem_save_node(node, uname, base, size); 6073f0c8206SMarek Szyprowski first = 0; 6083f0c8206SMarek Szyprowski } 609e8d9d1f5SMarek Szyprowski } 610e8d9d1f5SMarek Szyprowski return 0; 611e8d9d1f5SMarek Szyprowski } 612e8d9d1f5SMarek Szyprowski 613e8d9d1f5SMarek Szyprowski /** 614e8d9d1f5SMarek Szyprowski * __reserved_mem_check_root() - check if #size-cells, #address-cells provided 615e8d9d1f5SMarek Szyprowski * in /reserved-memory matches the values supported by the current implementation, 616e8d9d1f5SMarek Szyprowski * also check if ranges property has been provided 617e8d9d1f5SMarek Szyprowski */ 6185b624118SXiubo Li static int __init __reserved_mem_check_root(unsigned long node) 619e8d9d1f5SMarek Szyprowski { 6209d0c4dfeSRob Herring const __be32 *prop; 621e8d9d1f5SMarek Szyprowski 622e8d9d1f5SMarek Szyprowski prop = of_get_flat_dt_prop(node, "#size-cells", NULL); 623e8d9d1f5SMarek Szyprowski if (!prop || be32_to_cpup(prop) != dt_root_size_cells) 624e8d9d1f5SMarek Szyprowski return -EINVAL; 625e8d9d1f5SMarek Szyprowski 626e8d9d1f5SMarek Szyprowski prop = of_get_flat_dt_prop(node, "#address-cells", NULL); 627e8d9d1f5SMarek Szyprowski if (!prop || be32_to_cpup(prop) != dt_root_addr_cells) 628e8d9d1f5SMarek Szyprowski return -EINVAL; 629e8d9d1f5SMarek Szyprowski 630e8d9d1f5SMarek Szyprowski prop = of_get_flat_dt_prop(node, "ranges", NULL); 631e8d9d1f5SMarek Szyprowski if (!prop) 632e8d9d1f5SMarek Szyprowski return -EINVAL; 633e8d9d1f5SMarek Szyprowski return 0; 634e8d9d1f5SMarek Szyprowski } 635e8d9d1f5SMarek Szyprowski 636e8d9d1f5SMarek Szyprowski /** 637e8d9d1f5SMarek Szyprowski * fdt_scan_reserved_mem() - scan a single FDT node for reserved memory 638e8d9d1f5SMarek Szyprowski */ 639e8d9d1f5SMarek Szyprowski static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname, 640e8d9d1f5SMarek Szyprowski int depth, void *data) 641e8d9d1f5SMarek Szyprowski { 642e8d9d1f5SMarek Szyprowski static int found; 643e8d9d1f5SMarek Szyprowski const char *status; 6443f0c8206SMarek Szyprowski int err; 645e8d9d1f5SMarek Szyprowski 646e8d9d1f5SMarek Szyprowski if (!found && depth == 1 && strcmp(uname, "reserved-memory") == 0) { 647e8d9d1f5SMarek Szyprowski if (__reserved_mem_check_root(node) != 0) { 648e8d9d1f5SMarek Szyprowski pr_err("Reserved memory: unsupported node format, ignoring\n"); 649e8d9d1f5SMarek Szyprowski /* break scan */ 650e8d9d1f5SMarek Szyprowski return 1; 651e8d9d1f5SMarek Szyprowski } 652e8d9d1f5SMarek Szyprowski found = 1; 653e8d9d1f5SMarek Szyprowski /* scan next node */ 654e8d9d1f5SMarek Szyprowski return 0; 655e8d9d1f5SMarek Szyprowski } else if (!found) { 656e8d9d1f5SMarek Szyprowski /* scan next node */ 657e8d9d1f5SMarek Szyprowski return 0; 658e8d9d1f5SMarek Szyprowski } else if (found && depth < 2) { 659e8d9d1f5SMarek Szyprowski /* scanning of /reserved-memory has been finished */ 660e8d9d1f5SMarek Szyprowski return 1; 661e8d9d1f5SMarek Szyprowski } 662e8d9d1f5SMarek Szyprowski 663e8d9d1f5SMarek Szyprowski status = of_get_flat_dt_prop(node, "status", NULL); 664e8d9d1f5SMarek Szyprowski if (status && strcmp(status, "okay") != 0 && strcmp(status, "ok") != 0) 665e8d9d1f5SMarek Szyprowski return 0; 666e8d9d1f5SMarek Szyprowski 6673f0c8206SMarek Szyprowski err = __reserved_mem_reserve_reg(node, uname); 6683f0c8206SMarek Szyprowski if (err == -ENOENT && of_get_flat_dt_prop(node, "size", NULL)) 6693f0c8206SMarek Szyprowski fdt_reserved_mem_save_node(node, uname, 0, 0); 670e8d9d1f5SMarek Szyprowski 671e8d9d1f5SMarek Szyprowski /* scan next node */ 672e8d9d1f5SMarek Szyprowski return 0; 673e8d9d1f5SMarek Szyprowski } 674e8d9d1f5SMarek Szyprowski 675e8d9d1f5SMarek Szyprowski /** 676e8d9d1f5SMarek Szyprowski * early_init_fdt_scan_reserved_mem() - create reserved memory regions 677e8d9d1f5SMarek Szyprowski * 678e8d9d1f5SMarek Szyprowski * This function grabs memory from early allocator for device exclusive use 679e8d9d1f5SMarek Szyprowski * defined in device tree structures. It should be called by arch specific code 680e8d9d1f5SMarek Szyprowski * once the early allocator (i.e. memblock) has been fully activated. 681e8d9d1f5SMarek Szyprowski */ 682e8d9d1f5SMarek Szyprowski void __init early_init_fdt_scan_reserved_mem(void) 683e8d9d1f5SMarek Szyprowski { 684d1552ce4SRob Herring int n; 685d1552ce4SRob Herring u64 base, size; 686d1552ce4SRob Herring 6872040b527SJosh Cartwright if (!initial_boot_params) 6882040b527SJosh Cartwright return; 6892040b527SJosh Cartwright 690d1552ce4SRob Herring /* Process header /memreserve/ fields */ 691d1552ce4SRob Herring for (n = 0; ; n++) { 692d1552ce4SRob Herring fdt_get_mem_rsv(initial_boot_params, n, &base, &size); 693d1552ce4SRob Herring if (!size) 694d1552ce4SRob Herring break; 695d1552ce4SRob Herring early_init_dt_reserve_memory_arch(base, size, 0); 696d1552ce4SRob Herring } 697d1552ce4SRob Herring 698e8d9d1f5SMarek Szyprowski of_scan_flat_dt(__fdt_scan_reserved_mem, NULL); 6993f0c8206SMarek Szyprowski fdt_init_reserved_mem(); 700e8d9d1f5SMarek Szyprowski } 701e8d9d1f5SMarek Szyprowski 702e8d9d1f5SMarek Szyprowski /** 70324bbd929SArd Biesheuvel * early_init_fdt_reserve_self() - reserve the memory used by the FDT blob 70424bbd929SArd Biesheuvel */ 70524bbd929SArd Biesheuvel void __init early_init_fdt_reserve_self(void) 70624bbd929SArd Biesheuvel { 70724bbd929SArd Biesheuvel if (!initial_boot_params) 70824bbd929SArd Biesheuvel return; 70924bbd929SArd Biesheuvel 71024bbd929SArd Biesheuvel /* Reserve the dtb region */ 71124bbd929SArd Biesheuvel early_init_dt_reserve_memory_arch(__pa(initial_boot_params), 71224bbd929SArd Biesheuvel fdt_totalsize(initial_boot_params), 71324bbd929SArd Biesheuvel 0); 71424bbd929SArd Biesheuvel } 71524bbd929SArd Biesheuvel 71624bbd929SArd Biesheuvel /** 71757d00ecfSStephen Neuendorffer * of_scan_flat_dt - scan flattened tree blob and call callback on each. 71857d00ecfSStephen Neuendorffer * @it: callback function 71957d00ecfSStephen Neuendorffer * @data: context data pointer 72057d00ecfSStephen Neuendorffer * 72157d00ecfSStephen Neuendorffer * This function is used to scan the flattened device-tree, it is 72257d00ecfSStephen Neuendorffer * used to extract the memory information at boot before we can 72357d00ecfSStephen Neuendorffer * unflatten the tree 72457d00ecfSStephen Neuendorffer */ 72557d00ecfSStephen Neuendorffer int __init of_scan_flat_dt(int (*it)(unsigned long node, 72657d00ecfSStephen Neuendorffer const char *uname, int depth, 72757d00ecfSStephen Neuendorffer void *data), 72857d00ecfSStephen Neuendorffer void *data) 72957d00ecfSStephen Neuendorffer { 730e6a6928cSRob Herring const void *blob = initial_boot_params; 731e55b0829SFabio Estevam const char *pathp; 732e6a6928cSRob Herring int offset, rc = 0, depth = -1; 73357d00ecfSStephen Neuendorffer 734e6a6928cSRob Herring for (offset = fdt_next_node(blob, -1, &depth); 735e6a6928cSRob Herring offset >= 0 && depth >= 0 && !rc; 736e6a6928cSRob Herring offset = fdt_next_node(blob, offset, &depth)) { 737e6a6928cSRob Herring 738e6a6928cSRob Herring pathp = fdt_get_name(blob, offset, NULL); 739375da3a7SAndy Shevchenko if (*pathp == '/') 740375da3a7SAndy Shevchenko pathp = kbasename(pathp); 741e6a6928cSRob Herring rc = it(offset, pathp, depth, data); 742e6a6928cSRob Herring } 74357d00ecfSStephen Neuendorffer return rc; 74457d00ecfSStephen Neuendorffer } 74557d00ecfSStephen Neuendorffer 74657d00ecfSStephen Neuendorffer /** 74757d00ecfSStephen Neuendorffer * of_get_flat_dt_root - find the root node in the flat blob 74857d00ecfSStephen Neuendorffer */ 74957d00ecfSStephen Neuendorffer unsigned long __init of_get_flat_dt_root(void) 75057d00ecfSStephen Neuendorffer { 751e6a6928cSRob Herring return 0; 75257d00ecfSStephen Neuendorffer } 75357d00ecfSStephen Neuendorffer 75457d00ecfSStephen Neuendorffer /** 755c0556d3fSRob Herring * of_get_flat_dt_size - Return the total size of the FDT 756c0556d3fSRob Herring */ 757c0556d3fSRob Herring int __init of_get_flat_dt_size(void) 758c0556d3fSRob Herring { 759c0556d3fSRob Herring return fdt_totalsize(initial_boot_params); 760c0556d3fSRob Herring } 761c0556d3fSRob Herring 762c0556d3fSRob Herring /** 76357d00ecfSStephen Neuendorffer * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr 76457d00ecfSStephen Neuendorffer * 76557d00ecfSStephen Neuendorffer * This function can be used within scan_flattened_dt callback to get 76657d00ecfSStephen Neuendorffer * access to properties 76757d00ecfSStephen Neuendorffer */ 7689d0c4dfeSRob Herring const void *__init of_get_flat_dt_prop(unsigned long node, const char *name, 7699d0c4dfeSRob Herring int *size) 77057d00ecfSStephen Neuendorffer { 771e6a6928cSRob Herring return fdt_getprop(initial_boot_params, node, name, size); 77257d00ecfSStephen Neuendorffer } 77357d00ecfSStephen Neuendorffer 77457d00ecfSStephen Neuendorffer /** 77557d00ecfSStephen Neuendorffer * of_flat_dt_is_compatible - Return true if given node has compat in compatible list 77657d00ecfSStephen Neuendorffer * @node: node to test 77757d00ecfSStephen Neuendorffer * @compat: compatible string to compare with compatible list. 77857d00ecfSStephen Neuendorffer */ 77957d00ecfSStephen Neuendorffer int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) 78057d00ecfSStephen Neuendorffer { 78157d00ecfSStephen Neuendorffer return of_fdt_is_compatible(initial_boot_params, node, compat); 78257d00ecfSStephen Neuendorffer } 78357d00ecfSStephen Neuendorffer 784a4f740cfSGrant Likely /** 785a4f740cfSGrant Likely * of_flat_dt_match - Return true if node matches a list of compatible values 786a4f740cfSGrant Likely */ 7877b482c83SUwe Kleine-König int __init of_flat_dt_match(unsigned long node, const char *const *compat) 788a4f740cfSGrant Likely { 789a4f740cfSGrant Likely return of_fdt_match(initial_boot_params, node, compat); 790a4f740cfSGrant Likely } 791a4f740cfSGrant Likely 79257d74bcfSMarek Szyprowski struct fdt_scan_status { 79357d74bcfSMarek Szyprowski const char *name; 79457d74bcfSMarek Szyprowski int namelen; 79557d74bcfSMarek Szyprowski int depth; 79657d74bcfSMarek Szyprowski int found; 79757d74bcfSMarek Szyprowski int (*iterator)(unsigned long node, const char *uname, int depth, void *data); 79857d74bcfSMarek Szyprowski void *data; 79957d74bcfSMarek Szyprowski }; 80057d74bcfSMarek Szyprowski 8016a903a25SRob Herring const char * __init of_flat_dt_get_machine_name(void) 8026a903a25SRob Herring { 8036a903a25SRob Herring const char *name; 8046a903a25SRob Herring unsigned long dt_root = of_get_flat_dt_root(); 8056a903a25SRob Herring 8066a903a25SRob Herring name = of_get_flat_dt_prop(dt_root, "model", NULL); 8076a903a25SRob Herring if (!name) 8086a903a25SRob Herring name = of_get_flat_dt_prop(dt_root, "compatible", NULL); 8096a903a25SRob Herring return name; 8106a903a25SRob Herring } 8116a903a25SRob Herring 8126a903a25SRob Herring /** 8136a903a25SRob Herring * of_flat_dt_match_machine - Iterate match tables to find matching machine. 8146a903a25SRob Herring * 8156a903a25SRob Herring * @default_match: A machine specific ptr to return in case of no match. 8166a903a25SRob Herring * @get_next_compat: callback function to return next compatible match table. 8176a903a25SRob Herring * 8186a903a25SRob Herring * Iterate through machine match tables to find the best match for the machine 8196a903a25SRob Herring * compatible string in the FDT. 8206a903a25SRob Herring */ 8216a903a25SRob Herring const void * __init of_flat_dt_match_machine(const void *default_match, 8226a903a25SRob Herring const void * (*get_next_compat)(const char * const**)) 8236a903a25SRob Herring { 8246a903a25SRob Herring const void *data = NULL; 8256a903a25SRob Herring const void *best_data = default_match; 8266a903a25SRob Herring const char *const *compat; 8276a903a25SRob Herring unsigned long dt_root; 8286a903a25SRob Herring unsigned int best_score = ~1, score = 0; 8296a903a25SRob Herring 8306a903a25SRob Herring dt_root = of_get_flat_dt_root(); 8316a903a25SRob Herring while ((data = get_next_compat(&compat))) { 8326a903a25SRob Herring score = of_flat_dt_match(dt_root, compat); 8336a903a25SRob Herring if (score > 0 && score < best_score) { 8346a903a25SRob Herring best_data = data; 8356a903a25SRob Herring best_score = score; 8366a903a25SRob Herring } 8376a903a25SRob Herring } 8386a903a25SRob Herring if (!best_data) { 8396a903a25SRob Herring const char *prop; 8409d0c4dfeSRob Herring int size; 8416a903a25SRob Herring 8426a903a25SRob Herring pr_err("\n unrecognized device tree list:\n[ "); 8436a903a25SRob Herring 8446a903a25SRob Herring prop = of_get_flat_dt_prop(dt_root, "compatible", &size); 8456a903a25SRob Herring if (prop) { 8466a903a25SRob Herring while (size > 0) { 8476a903a25SRob Herring printk("'%s' ", prop); 8486a903a25SRob Herring size -= strlen(prop) + 1; 8496a903a25SRob Herring prop += strlen(prop) + 1; 8506a903a25SRob Herring } 8516a903a25SRob Herring } 8526a903a25SRob Herring printk("]\n\n"); 8536a903a25SRob Herring return NULL; 8546a903a25SRob Herring } 8556a903a25SRob Herring 8566a903a25SRob Herring pr_info("Machine model: %s\n", of_flat_dt_get_machine_name()); 8576a903a25SRob Herring 8586a903a25SRob Herring return best_data; 8596a903a25SRob Herring } 8606a903a25SRob Herring 861f7b3a835SGrant Likely #ifdef CONFIG_BLK_DEV_INITRD 862369bc9abSArd Biesheuvel #ifndef __early_init_dt_declare_initrd 863369bc9abSArd Biesheuvel static void __early_init_dt_declare_initrd(unsigned long start, 864369bc9abSArd Biesheuvel unsigned long end) 865369bc9abSArd Biesheuvel { 866369bc9abSArd Biesheuvel initrd_start = (unsigned long)__va(start); 867369bc9abSArd Biesheuvel initrd_end = (unsigned long)__va(end); 868369bc9abSArd Biesheuvel initrd_below_start_ok = 1; 869369bc9abSArd Biesheuvel } 870369bc9abSArd Biesheuvel #endif 871369bc9abSArd Biesheuvel 872f7b3a835SGrant Likely /** 873f7b3a835SGrant Likely * early_init_dt_check_for_initrd - Decode initrd location from flat tree 874f7b3a835SGrant Likely * @node: reference to node containing initrd location ('chosen') 875f7b3a835SGrant Likely */ 87629eb45a9SRob Herring static void __init early_init_dt_check_for_initrd(unsigned long node) 877f7b3a835SGrant Likely { 878374d5c99SSantosh Shilimkar u64 start, end; 8799d0c4dfeSRob Herring int len; 8809d0c4dfeSRob Herring const __be32 *prop; 881f7b3a835SGrant Likely 882f7b3a835SGrant Likely pr_debug("Looking for initrd properties... "); 883f7b3a835SGrant Likely 884f7b3a835SGrant Likely prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len); 8851406bc2fSJeremy Kerr if (!prop) 8861406bc2fSJeremy Kerr return; 887374d5c99SSantosh Shilimkar start = of_read_number(prop, len/4); 888f7b3a835SGrant Likely 889f7b3a835SGrant Likely prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len); 8901406bc2fSJeremy Kerr if (!prop) 8911406bc2fSJeremy Kerr return; 892374d5c99SSantosh Shilimkar end = of_read_number(prop, len/4); 893f7b3a835SGrant Likely 894369bc9abSArd Biesheuvel __early_init_dt_declare_initrd(start, end); 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 907523bf17fSLad, Prabhakar static int __init early_init_dt_scan_chosen_serial(void) 908fb11ffe7SRob Herring { 909fb11ffe7SRob Herring int offset; 9104d118c9aSPeter Hurley const char *p, *q, *options = NULL; 911fb11ffe7SRob Herring int l; 9122eaa7909SPeter Hurley const struct earlycon_id *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 9392eaa7909SPeter Hurley for (match = __earlycon_table; match < __earlycon_table_end; match++) { 9402eaa7909SPeter Hurley if (!match->compatible[0]) 941fb11ffe7SRob Herring continue; 9422eaa7909SPeter Hurley 9432eaa7909SPeter Hurley if (fdt_node_check_compatible(fdt, offset, match->compatible)) 9442eaa7909SPeter Hurley continue; 945fb11ffe7SRob Herring 946c90fe9c0SPeter Hurley of_setup_earlycon(match, offset, options); 947fb11ffe7SRob Herring return 0; 948fb11ffe7SRob Herring } 949fb11ffe7SRob Herring return -ENODEV; 950fb11ffe7SRob Herring } 951fb11ffe7SRob Herring 952fb11ffe7SRob Herring static int __init setup_of_earlycon(char *buf) 953fb11ffe7SRob Herring { 954fb11ffe7SRob Herring if (buf) 955fb11ffe7SRob Herring return 0; 956fb11ffe7SRob Herring 957fb11ffe7SRob Herring return early_init_dt_scan_chosen_serial(); 958fb11ffe7SRob Herring } 959fb11ffe7SRob Herring early_param("earlycon", setup_of_earlycon); 960fb11ffe7SRob Herring #endif 961fb11ffe7SRob Herring 96241f88009SGrant Likely /** 963f00abd94SGrant Likely * early_init_dt_scan_root - fetch the top level address and size cells 964f00abd94SGrant Likely */ 965f00abd94SGrant Likely int __init early_init_dt_scan_root(unsigned long node, const char *uname, 966f00abd94SGrant Likely int depth, void *data) 967f00abd94SGrant Likely { 9689d0c4dfeSRob Herring const __be32 *prop; 969f00abd94SGrant Likely 970f00abd94SGrant Likely if (depth != 0) 971f00abd94SGrant Likely return 0; 972f00abd94SGrant Likely 97333714881SJeremy Kerr dt_root_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT; 97433714881SJeremy Kerr dt_root_addr_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT; 97533714881SJeremy Kerr 976f00abd94SGrant Likely prop = of_get_flat_dt_prop(node, "#size-cells", NULL); 97733714881SJeremy Kerr if (prop) 97833714881SJeremy Kerr dt_root_size_cells = be32_to_cpup(prop); 979f00abd94SGrant Likely pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells); 980f00abd94SGrant Likely 981f00abd94SGrant Likely prop = of_get_flat_dt_prop(node, "#address-cells", NULL); 98233714881SJeremy Kerr if (prop) 98333714881SJeremy Kerr dt_root_addr_cells = be32_to_cpup(prop); 984f00abd94SGrant Likely pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells); 985f00abd94SGrant Likely 986f00abd94SGrant Likely /* break now */ 987f00abd94SGrant Likely return 1; 988f00abd94SGrant Likely } 989f00abd94SGrant Likely 9909d0c4dfeSRob Herring u64 __init dt_mem_next_cell(int s, const __be32 **cellp) 99183f7a06eSGrant Likely { 9929d0c4dfeSRob Herring const __be32 *p = *cellp; 99383f7a06eSGrant Likely 99483f7a06eSGrant Likely *cellp = p + s; 99583f7a06eSGrant Likely return of_read_number(p, s); 99683f7a06eSGrant Likely } 99783f7a06eSGrant Likely 99851975db0SGrant Likely /** 99951975db0SGrant Likely * early_init_dt_scan_memory - Look for an parse memory nodes 100051975db0SGrant Likely */ 100151975db0SGrant Likely int __init early_init_dt_scan_memory(unsigned long node, const char *uname, 100251975db0SGrant Likely int depth, void *data) 100351975db0SGrant Likely { 10049d0c4dfeSRob Herring const char *type = of_get_flat_dt_prop(node, "device_type", NULL); 10059d0c4dfeSRob Herring const __be32 *reg, *endp; 10069d0c4dfeSRob Herring int l; 100751975db0SGrant Likely 100851975db0SGrant Likely /* We are scanning "memory" nodes only */ 100951975db0SGrant Likely if (type == NULL) { 101051975db0SGrant Likely /* 101151975db0SGrant Likely * The longtrail doesn't have a device_type on the 101251975db0SGrant Likely * /memory node, so look for the node called /memory@0. 101351975db0SGrant Likely */ 1014b44aa25dSLeif Lindholm if (!IS_ENABLED(CONFIG_PPC32) || depth != 1 || strcmp(uname, "memory@0") != 0) 101551975db0SGrant Likely return 0; 101651975db0SGrant Likely } else if (strcmp(type, "memory") != 0) 101751975db0SGrant Likely return 0; 101851975db0SGrant Likely 101951975db0SGrant Likely reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l); 102051975db0SGrant Likely if (reg == NULL) 102151975db0SGrant Likely reg = of_get_flat_dt_prop(node, "reg", &l); 102251975db0SGrant Likely if (reg == NULL) 102351975db0SGrant Likely return 0; 102451975db0SGrant Likely 102551975db0SGrant Likely endp = reg + (l / sizeof(__be32)); 102651975db0SGrant Likely 1027c954b36eSFlorian Fainelli pr_debug("memory scan node %s, reg size %d,\n", uname, l); 102851975db0SGrant Likely 102951975db0SGrant Likely while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { 103051975db0SGrant Likely u64 base, size; 103151975db0SGrant Likely 103251975db0SGrant Likely base = dt_mem_next_cell(dt_root_addr_cells, ®); 103351975db0SGrant Likely size = dt_mem_next_cell(dt_root_size_cells, ®); 103451975db0SGrant Likely 103551975db0SGrant Likely if (size == 0) 103651975db0SGrant Likely continue; 103751975db0SGrant Likely pr_debug(" - %llx , %llx\n", (unsigned long long)base, 103851975db0SGrant Likely (unsigned long long)size); 103951975db0SGrant Likely 104051975db0SGrant Likely early_init_dt_add_memory_arch(base, size); 104151975db0SGrant Likely } 104251975db0SGrant Likely 104351975db0SGrant Likely return 0; 104451975db0SGrant Likely } 104551975db0SGrant Likely 104686e03221SGrant Likely int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, 104786e03221SGrant Likely int depth, void *data) 104886e03221SGrant Likely { 10499d0c4dfeSRob Herring int l; 10509d0c4dfeSRob Herring const char *p; 105186e03221SGrant Likely 105286e03221SGrant Likely pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname); 105386e03221SGrant Likely 105485f60ae4SGrant Likely if (depth != 1 || !data || 105586e03221SGrant Likely (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0)) 105686e03221SGrant Likely return 0; 105786e03221SGrant Likely 105886e03221SGrant Likely early_init_dt_check_for_initrd(node); 105986e03221SGrant Likely 106025985edcSLucas De Marchi /* Retrieve command line */ 106186e03221SGrant Likely p = of_get_flat_dt_prop(node, "bootargs", &l); 106286e03221SGrant Likely if (p != NULL && l > 0) 106385f60ae4SGrant Likely strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE)); 106486e03221SGrant Likely 106578b782cbSBenjamin Herrenschmidt /* 106678b782cbSBenjamin Herrenschmidt * CONFIG_CMDLINE is meant to be a default in case nothing else 106778b782cbSBenjamin Herrenschmidt * managed to set the command line, unless CONFIG_CMDLINE_FORCE 106878b782cbSBenjamin Herrenschmidt * is set in which case we override whatever was found earlier. 106978b782cbSBenjamin Herrenschmidt */ 107086e03221SGrant Likely #ifdef CONFIG_CMDLINE 107134b82026SMax Uvarov #if defined(CONFIG_CMDLINE_EXTEND) 107234b82026SMax Uvarov strlcat(data, " ", COMMAND_LINE_SIZE); 107334b82026SMax Uvarov strlcat(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE); 107434b82026SMax Uvarov #elif defined(CONFIG_CMDLINE_FORCE) 107585f60ae4SGrant Likely strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE); 107634b82026SMax Uvarov #else 107734b82026SMax Uvarov /* No arguments from boot loader, use kernel's cmdl*/ 107834b82026SMax Uvarov if (!((char *)data)[0]) 107934b82026SMax Uvarov strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE); 108034b82026SMax Uvarov #endif 108186e03221SGrant Likely #endif /* CONFIG_CMDLINE */ 108286e03221SGrant Likely 108385f60ae4SGrant Likely pr_debug("Command line is: %s\n", (char*)data); 108486e03221SGrant Likely 108586e03221SGrant Likely /* break now */ 108686e03221SGrant Likely return 1; 108786e03221SGrant Likely } 108886e03221SGrant Likely 1089a1727da5SGrant Likely #ifdef CONFIG_HAVE_MEMBLOCK 1090270522a0SArd Biesheuvel #ifndef MIN_MEMBLOCK_ADDR 1091270522a0SArd Biesheuvel #define MIN_MEMBLOCK_ADDR __pa(PAGE_OFFSET) 1092270522a0SArd Biesheuvel #endif 10938eafeb48SArd Biesheuvel #ifndef MAX_MEMBLOCK_ADDR 10948eafeb48SArd Biesheuvel #define MAX_MEMBLOCK_ADDR ((phys_addr_t)~0) 10958eafeb48SArd Biesheuvel #endif 10963069f0c0SLaura Abbott 1097068f6310SRob Herring void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size) 1098068f6310SRob Herring { 1099270522a0SArd Biesheuvel const u64 phys_offset = MIN_MEMBLOCK_ADDR; 11008f73d4b7SGeert Uytterhoeven 11018f73d4b7SGeert Uytterhoeven if (!PAGE_ALIGNED(base)) { 11028cccffc5SArd Biesheuvel if (size < PAGE_SIZE - (base & ~PAGE_MASK)) { 11038cccffc5SArd Biesheuvel pr_warn("Ignoring memory block 0x%llx - 0x%llx\n", 11048cccffc5SArd Biesheuvel base, base + size); 11058cccffc5SArd Biesheuvel return; 11068cccffc5SArd Biesheuvel } 11078f73d4b7SGeert Uytterhoeven size -= PAGE_SIZE - (base & ~PAGE_MASK); 11088f73d4b7SGeert Uytterhoeven base = PAGE_ALIGN(base); 11098f73d4b7SGeert Uytterhoeven } 1110068f6310SRob Herring size &= PAGE_MASK; 1111a67a6ed1SLaura Abbott 11128eafeb48SArd Biesheuvel if (base > MAX_MEMBLOCK_ADDR) { 1113a67a6ed1SLaura Abbott pr_warning("Ignoring memory block 0x%llx - 0x%llx\n", 1114a67a6ed1SLaura Abbott base, base + size); 1115a67a6ed1SLaura Abbott return; 1116a67a6ed1SLaura Abbott } 1117a67a6ed1SLaura Abbott 11188eafeb48SArd Biesheuvel if (base + size - 1 > MAX_MEMBLOCK_ADDR) { 11199aacd602SSrinivas Kandagatla pr_warning("Ignoring memory range 0x%llx - 0x%llx\n", 11208eafeb48SArd Biesheuvel ((u64)MAX_MEMBLOCK_ADDR) + 1, base + size); 11218eafeb48SArd Biesheuvel size = MAX_MEMBLOCK_ADDR - base + 1; 1122a67a6ed1SLaura Abbott } 1123a67a6ed1SLaura Abbott 1124068f6310SRob Herring if (base + size < phys_offset) { 1125068f6310SRob Herring pr_warning("Ignoring memory block 0x%llx - 0x%llx\n", 1126068f6310SRob Herring base, base + size); 1127068f6310SRob Herring return; 1128068f6310SRob Herring } 1129068f6310SRob Herring if (base < phys_offset) { 1130068f6310SRob Herring pr_warning("Ignoring memory range 0x%llx - 0x%llx\n", 1131068f6310SRob Herring base, phys_offset); 1132068f6310SRob Herring size -= phys_offset - base; 1133068f6310SRob Herring base = phys_offset; 1134068f6310SRob Herring } 1135068f6310SRob Herring memblock_add(base, size); 1136068f6310SRob Herring } 1137068f6310SRob Herring 1138e8d9d1f5SMarek Szyprowski int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base, 1139e8d9d1f5SMarek Szyprowski phys_addr_t size, bool nomap) 1140e8d9d1f5SMarek Szyprowski { 1141e8d9d1f5SMarek Szyprowski if (nomap) 1142e8d9d1f5SMarek Szyprowski return memblock_remove(base, size); 1143e8d9d1f5SMarek Szyprowski return memblock_reserve(base, size); 1144e8d9d1f5SMarek Szyprowski } 1145e8d9d1f5SMarek Szyprowski 1146a1727da5SGrant Likely /* 1147a1727da5SGrant Likely * called from unflatten_device_tree() to bootstrap devicetree itself 1148a1727da5SGrant Likely * Architectures can override this definition if memblock isn't used 1149a1727da5SGrant Likely */ 1150a1727da5SGrant Likely void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align) 1151a1727da5SGrant Likely { 1152a1727da5SGrant Likely return __va(memblock_alloc(size, align)); 1153a1727da5SGrant Likely } 1154e8d9d1f5SMarek Szyprowski #else 1155aefc7ec2SRob Herring void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size) 1156aefc7ec2SRob Herring { 1157aefc7ec2SRob Herring WARN_ON(1); 1158aefc7ec2SRob Herring } 1159aefc7ec2SRob Herring 1160e8d9d1f5SMarek Szyprowski int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base, 1161e8d9d1f5SMarek Szyprowski phys_addr_t size, bool nomap) 1162e8d9d1f5SMarek Szyprowski { 116378bb2abeSDmitry V. Krivenok pr_err("Reserved memory not supported, ignoring range %pa - %pa%s\n", 11641d1a661dSRob Herring &base, &size, nomap ? " (nomap)" : ""); 1165e8d9d1f5SMarek Szyprowski return -ENOSYS; 1166e8d9d1f5SMarek Szyprowski } 1167aefc7ec2SRob Herring 1168aefc7ec2SRob Herring void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align) 1169aefc7ec2SRob Herring { 1170aefc7ec2SRob Herring WARN_ON(1); 1171aefc7ec2SRob Herring return NULL; 1172aefc7ec2SRob Herring } 1173a1727da5SGrant Likely #endif 1174a1727da5SGrant Likely 11754972a74bSLaura Abbott bool __init early_init_dt_verify(void *params) 11760288ffcbSRob Herring { 11770288ffcbSRob Herring if (!params) 11780288ffcbSRob Herring return false; 11790288ffcbSRob Herring 118050ba08f3SBjorn Helgaas /* check device tree validity */ 118150ba08f3SBjorn Helgaas if (fdt_check_header(params)) 118250ba08f3SBjorn Helgaas return false; 118350ba08f3SBjorn Helgaas 11840288ffcbSRob Herring /* Setup flat device-tree pointer */ 11850288ffcbSRob Herring initial_boot_params = params; 118608d53aa5SArd Biesheuvel of_fdt_crc32 = crc32_be(~0, initial_boot_params, 118708d53aa5SArd Biesheuvel fdt_totalsize(initial_boot_params)); 11884972a74bSLaura Abbott return true; 11894972a74bSLaura Abbott } 11904972a74bSLaura Abbott 11914972a74bSLaura Abbott 11924972a74bSLaura Abbott void __init early_init_dt_scan_nodes(void) 11934972a74bSLaura Abbott { 11940288ffcbSRob Herring /* Retrieve various information from the /chosen node */ 11950288ffcbSRob Herring of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); 11960288ffcbSRob Herring 11970288ffcbSRob Herring /* Initialize {size,address}-cells info */ 11980288ffcbSRob Herring of_scan_flat_dt(early_init_dt_scan_root, NULL); 11990288ffcbSRob Herring 12000288ffcbSRob Herring /* Setup memory, calling early_init_dt_add_memory_arch */ 12010288ffcbSRob Herring of_scan_flat_dt(early_init_dt_scan_memory, NULL); 12024972a74bSLaura Abbott } 12030288ffcbSRob Herring 12044972a74bSLaura Abbott bool __init early_init_dt_scan(void *params) 12054972a74bSLaura Abbott { 12064972a74bSLaura Abbott bool status; 12074972a74bSLaura Abbott 12084972a74bSLaura Abbott status = early_init_dt_verify(params); 12094972a74bSLaura Abbott if (!status) 12104972a74bSLaura Abbott return false; 12114972a74bSLaura Abbott 12124972a74bSLaura Abbott early_init_dt_scan_nodes(); 12130288ffcbSRob Herring return true; 12140288ffcbSRob Herring } 12150288ffcbSRob Herring 1216f00abd94SGrant Likely /** 121741f88009SGrant Likely * unflatten_device_tree - create tree of device_nodes from flat blob 121841f88009SGrant Likely * 121941f88009SGrant Likely * unflattens the device-tree passed by the firmware, creating the 122041f88009SGrant Likely * tree of struct device_node. It also fills the "name" and "type" 122141f88009SGrant Likely * pointers of the nodes so the normal device-tree walking functions 122241f88009SGrant Likely * can be used. 122341f88009SGrant Likely */ 122441f88009SGrant Likely void __init unflatten_device_tree(void) 122541f88009SGrant Likely { 1226c4263233SGavin Shan __unflatten_device_tree(initial_boot_params, NULL, &of_root, 1227672c5446SGrant Likely early_init_dt_alloc_memory_arch); 122841f88009SGrant Likely 12294c7d6361SRobert P. J. Day /* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */ 1230611cad72SShawn Guo of_alias_scan(early_init_dt_alloc_memory_arch); 123141f88009SGrant Likely } 1232e6ce1324SStephen Neuendorffer 1233a8bf7527SRob Herring /** 1234a8bf7527SRob Herring * unflatten_and_copy_device_tree - copy and create tree of device_nodes from flat blob 1235a8bf7527SRob Herring * 1236a8bf7527SRob Herring * Copies and unflattens the device-tree passed by the firmware, creating the 1237a8bf7527SRob Herring * tree of struct device_node. It also fills the "name" and "type" 1238a8bf7527SRob Herring * pointers of the nodes so the normal device-tree walking functions 1239a8bf7527SRob Herring * can be used. This should only be used when the FDT memory has not been 1240a8bf7527SRob Herring * reserved such is the case when the FDT is built-in to the kernel init 1241a8bf7527SRob Herring * section. If the FDT memory is reserved already then unflatten_device_tree 1242a8bf7527SRob Herring * should be used instead. 1243a8bf7527SRob Herring */ 1244a8bf7527SRob Herring void __init unflatten_and_copy_device_tree(void) 1245a8bf7527SRob Herring { 12466f041e99SJames Hogan int size; 12476f041e99SJames Hogan void *dt; 12486f041e99SJames Hogan 12496f041e99SJames Hogan if (!initial_boot_params) { 12506f041e99SJames Hogan pr_warn("No valid device tree found, continuing without\n"); 12516f041e99SJames Hogan return; 12526f041e99SJames Hogan } 12536f041e99SJames Hogan 1254c972de14SRob Herring size = fdt_totalsize(initial_boot_params); 12556f041e99SJames Hogan dt = early_init_dt_alloc_memory_arch(size, 1256c972de14SRob Herring roundup_pow_of_two(FDT_V17_SIZE)); 1257a8bf7527SRob Herring 1258a8bf7527SRob Herring if (dt) { 1259a8bf7527SRob Herring memcpy(dt, initial_boot_params, size); 1260a8bf7527SRob Herring initial_boot_params = dt; 1261a8bf7527SRob Herring } 1262a8bf7527SRob Herring unflatten_device_tree(); 1263a8bf7527SRob Herring } 1264a8bf7527SRob Herring 126508d53aa5SArd Biesheuvel #ifdef CONFIG_SYSFS 126608d53aa5SArd Biesheuvel static ssize_t of_fdt_raw_read(struct file *filp, struct kobject *kobj, 126708d53aa5SArd Biesheuvel struct bin_attribute *bin_attr, 126808d53aa5SArd Biesheuvel char *buf, loff_t off, size_t count) 1269b0a6fb36SRob Herring { 127008d53aa5SArd Biesheuvel memcpy(buf, initial_boot_params + off, count); 127108d53aa5SArd Biesheuvel return count; 127208d53aa5SArd Biesheuvel } 1273b0a6fb36SRob Herring 127408d53aa5SArd Biesheuvel static int __init of_fdt_raw_init(void) 127508d53aa5SArd Biesheuvel { 127608d53aa5SArd Biesheuvel static struct bin_attribute of_fdt_raw_attr = 127708d53aa5SArd Biesheuvel __BIN_ATTR(fdt, S_IRUSR, of_fdt_raw_read, NULL, 0); 1278b0a6fb36SRob Herring 127908d53aa5SArd Biesheuvel if (!initial_boot_params) 128008d53aa5SArd Biesheuvel return 0; 1281b0a6fb36SRob Herring 128208d53aa5SArd Biesheuvel if (of_fdt_crc32 != crc32_be(~0, initial_boot_params, 128308d53aa5SArd Biesheuvel fdt_totalsize(initial_boot_params))) { 1284606ad42aSRob Herring pr_warn("not creating '/sys/firmware/fdt': CRC check failed\n"); 1285b0a6fb36SRob Herring return 0; 1286b0a6fb36SRob Herring } 128708d53aa5SArd Biesheuvel of_fdt_raw_attr.size = fdt_totalsize(initial_boot_params); 128808d53aa5SArd Biesheuvel return sysfs_create_bin_file(firmware_kobj, &of_fdt_raw_attr); 128908d53aa5SArd Biesheuvel } 129008d53aa5SArd Biesheuvel late_initcall(of_fdt_raw_init); 1291b0a6fb36SRob Herring #endif 1292b0a6fb36SRob Herring 1293e6ce1324SStephen Neuendorffer #endif /* CONFIG_OF_EARLY_FLATTREE */ 1294