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 1241f88009SGrant Likely #include <linux/kernel.h> 13f7b3a835SGrant Likely #include <linux/initrd.h> 14a1727da5SGrant Likely #include <linux/memblock.h> 15fe140423SStephen Neuendorffer #include <linux/module.h> 16e169cfbeSGrant Likely #include <linux/of.h> 17e169cfbeSGrant Likely #include <linux/of_fdt.h> 184ef7b373SJeremy Kerr #include <linux/string.h> 194ef7b373SJeremy Kerr #include <linux/errno.h> 20fe140423SStephen Neuendorffer #include <linux/slab.h> 21109b6236SAnton Blanchard #include <linux/random.h> 2251975db0SGrant Likely 23c89810acSFabio Estevam #include <asm/setup.h> /* for COMMAND_LINE_SIZE */ 2486e03221SGrant Likely #ifdef CONFIG_PPC 2586e03221SGrant Likely #include <asm/machdep.h> 2686e03221SGrant Likely #endif /* CONFIG_PPC */ 2786e03221SGrant Likely 284ef7b373SJeremy Kerr #include <asm/page.h> 294ef7b373SJeremy Kerr 309706a36eSStephen Neuendorffer char *of_fdt_get_string(struct boot_param_header *blob, u32 offset) 319706a36eSStephen Neuendorffer { 329706a36eSStephen Neuendorffer return ((char *)blob) + 339706a36eSStephen Neuendorffer be32_to_cpu(blob->off_dt_strings) + offset; 349706a36eSStephen Neuendorffer } 359706a36eSStephen Neuendorffer 369706a36eSStephen Neuendorffer /** 379706a36eSStephen Neuendorffer * of_fdt_get_property - Given a node in the given flat blob, return 389706a36eSStephen Neuendorffer * the property ptr 399706a36eSStephen Neuendorffer */ 409706a36eSStephen Neuendorffer void *of_fdt_get_property(struct boot_param_header *blob, 419706a36eSStephen Neuendorffer unsigned long node, const char *name, 429706a36eSStephen Neuendorffer unsigned long *size) 439706a36eSStephen Neuendorffer { 449706a36eSStephen Neuendorffer unsigned long p = node; 459706a36eSStephen Neuendorffer 469706a36eSStephen Neuendorffer do { 479706a36eSStephen Neuendorffer u32 tag = be32_to_cpup((__be32 *)p); 489706a36eSStephen Neuendorffer u32 sz, noff; 499706a36eSStephen Neuendorffer const char *nstr; 509706a36eSStephen Neuendorffer 519706a36eSStephen Neuendorffer p += 4; 529706a36eSStephen Neuendorffer if (tag == OF_DT_NOP) 539706a36eSStephen Neuendorffer continue; 549706a36eSStephen Neuendorffer if (tag != OF_DT_PROP) 559706a36eSStephen Neuendorffer return NULL; 569706a36eSStephen Neuendorffer 579706a36eSStephen Neuendorffer sz = be32_to_cpup((__be32 *)p); 589706a36eSStephen Neuendorffer noff = be32_to_cpup((__be32 *)(p + 4)); 599706a36eSStephen Neuendorffer p += 8; 609706a36eSStephen Neuendorffer if (be32_to_cpu(blob->version) < 0x10) 619706a36eSStephen Neuendorffer p = ALIGN(p, sz >= 8 ? 8 : 4); 629706a36eSStephen Neuendorffer 639706a36eSStephen Neuendorffer nstr = of_fdt_get_string(blob, noff); 649706a36eSStephen Neuendorffer if (nstr == NULL) { 659706a36eSStephen Neuendorffer pr_warning("Can't find property index name !\n"); 669706a36eSStephen Neuendorffer return NULL; 679706a36eSStephen Neuendorffer } 689706a36eSStephen Neuendorffer if (strcmp(name, nstr) == 0) { 699706a36eSStephen Neuendorffer if (size) 709706a36eSStephen Neuendorffer *size = sz; 719706a36eSStephen Neuendorffer return (void *)p; 729706a36eSStephen Neuendorffer } 739706a36eSStephen Neuendorffer p += sz; 749706a36eSStephen Neuendorffer p = ALIGN(p, 4); 759706a36eSStephen Neuendorffer } while (1); 769706a36eSStephen Neuendorffer } 779706a36eSStephen Neuendorffer 789706a36eSStephen Neuendorffer /** 799706a36eSStephen Neuendorffer * of_fdt_is_compatible - Return true if given node from the given blob has 809706a36eSStephen Neuendorffer * compat in its compatible list 819706a36eSStephen Neuendorffer * @blob: A device tree blob 829706a36eSStephen Neuendorffer * @node: node to test 839706a36eSStephen Neuendorffer * @compat: compatible string to compare with compatible list. 84a4f740cfSGrant Likely * 85a4f740cfSGrant Likely * On match, returns a non-zero value with smaller values returned for more 86a4f740cfSGrant Likely * specific compatible values. 879706a36eSStephen Neuendorffer */ 889706a36eSStephen Neuendorffer int of_fdt_is_compatible(struct boot_param_header *blob, 899706a36eSStephen Neuendorffer unsigned long node, const char *compat) 909706a36eSStephen Neuendorffer { 919706a36eSStephen Neuendorffer const char *cp; 92a4f740cfSGrant Likely unsigned long cplen, l, score = 0; 939706a36eSStephen Neuendorffer 949706a36eSStephen Neuendorffer cp = of_fdt_get_property(blob, node, "compatible", &cplen); 959706a36eSStephen Neuendorffer if (cp == NULL) 969706a36eSStephen Neuendorffer return 0; 979706a36eSStephen Neuendorffer while (cplen > 0) { 98a4f740cfSGrant Likely score++; 999706a36eSStephen Neuendorffer if (of_compat_cmp(cp, compat, strlen(compat)) == 0) 100a4f740cfSGrant Likely return score; 1019706a36eSStephen Neuendorffer l = strlen(cp) + 1; 1029706a36eSStephen Neuendorffer cp += l; 1039706a36eSStephen Neuendorffer cplen -= l; 1049706a36eSStephen Neuendorffer } 1059706a36eSStephen Neuendorffer 1069706a36eSStephen Neuendorffer return 0; 1079706a36eSStephen Neuendorffer } 1089706a36eSStephen Neuendorffer 109a4f740cfSGrant Likely /** 110a4f740cfSGrant Likely * of_fdt_match - Return true if node matches a list of compatible values 111a4f740cfSGrant Likely */ 112a4f740cfSGrant Likely int of_fdt_match(struct boot_param_header *blob, unsigned long node, 1137b482c83SUwe Kleine-König const char *const *compat) 114a4f740cfSGrant Likely { 115a4f740cfSGrant Likely unsigned int tmp, score = 0; 116a4f740cfSGrant Likely 117a4f740cfSGrant Likely if (!compat) 118a4f740cfSGrant Likely return 0; 119a4f740cfSGrant Likely 120a4f740cfSGrant Likely while (*compat) { 121a4f740cfSGrant Likely tmp = of_fdt_is_compatible(blob, node, *compat); 122a4f740cfSGrant Likely if (tmp && (score == 0 || (tmp < score))) 123a4f740cfSGrant Likely score = tmp; 124a4f740cfSGrant Likely compat++; 125a4f740cfSGrant Likely } 126a4f740cfSGrant Likely 127a4f740cfSGrant Likely return score; 128a4f740cfSGrant Likely } 129a4f740cfSGrant Likely 13044856819SGrant Likely static void *unflatten_dt_alloc(void **mem, unsigned long size, 131bbd33931SGrant Likely unsigned long align) 132bbd33931SGrant Likely { 133bbd33931SGrant Likely void *res; 134bbd33931SGrant Likely 13544856819SGrant Likely *mem = PTR_ALIGN(*mem, align); 13644856819SGrant Likely res = *mem; 137bbd33931SGrant Likely *mem += size; 138bbd33931SGrant Likely 139bbd33931SGrant Likely return res; 140bbd33931SGrant Likely } 141bbd33931SGrant Likely 142bbd33931SGrant Likely /** 143bbd33931SGrant Likely * unflatten_dt_node - Alloc and populate a device_node from the flat tree 144a40d6c4cSStephen Neuendorffer * @blob: The parent device tree blob 145a7006c97SAndres Salomon * @mem: Memory chunk to use for allocating device nodes and properties 146bbd33931SGrant Likely * @p: pointer to node in flat tree 147bbd33931SGrant Likely * @dad: Parent struct device_node 148bbd33931SGrant Likely * @allnextpp: pointer to ->allnext from last allocated device_node 149bbd33931SGrant Likely * @fpsize: Size of the node path up at the current depth. 150bbd33931SGrant Likely */ 15144856819SGrant Likely static void * unflatten_dt_node(struct boot_param_header *blob, 15244856819SGrant Likely void *mem, 15344856819SGrant Likely void **p, 154bbd33931SGrant Likely struct device_node *dad, 155bbd33931SGrant Likely struct device_node ***allnextpp, 156bbd33931SGrant Likely unsigned long fpsize) 157bbd33931SGrant Likely { 158bbd33931SGrant Likely struct device_node *np; 159bbd33931SGrant Likely struct property *pp, **prev_pp = NULL; 160bbd33931SGrant Likely char *pathp; 161bbd33931SGrant Likely u32 tag; 162bbd33931SGrant Likely unsigned int l, allocl; 163bbd33931SGrant Likely int has_name = 0; 164bbd33931SGrant Likely int new_format = 0; 165bbd33931SGrant Likely 16644856819SGrant Likely tag = be32_to_cpup(*p); 167bbd33931SGrant Likely if (tag != OF_DT_BEGIN_NODE) { 168bbd33931SGrant Likely pr_err("Weird tag at start of node: %x\n", tag); 169bbd33931SGrant Likely return mem; 170bbd33931SGrant Likely } 171bbd33931SGrant Likely *p += 4; 17244856819SGrant Likely pathp = *p; 173bbd33931SGrant Likely l = allocl = strlen(pathp) + 1; 17444856819SGrant Likely *p = PTR_ALIGN(*p + l, 4); 175bbd33931SGrant Likely 176bbd33931SGrant Likely /* version 0x10 has a more compact unit name here instead of the full 177bbd33931SGrant Likely * path. we accumulate the full path size using "fpsize", we'll rebuild 178bbd33931SGrant Likely * it later. We detect this because the first character of the name is 179bbd33931SGrant Likely * not '/'. 180bbd33931SGrant Likely */ 181bbd33931SGrant Likely if ((*pathp) != '/') { 182bbd33931SGrant Likely new_format = 1; 183bbd33931SGrant Likely if (fpsize == 0) { 184bbd33931SGrant Likely /* root node: special case. fpsize accounts for path 185bbd33931SGrant Likely * plus terminating zero. root node only has '/', so 186bbd33931SGrant Likely * fpsize should be 2, but we want to avoid the first 187bbd33931SGrant Likely * level nodes to have two '/' so we use fpsize 1 here 188bbd33931SGrant Likely */ 189bbd33931SGrant Likely fpsize = 1; 190bbd33931SGrant Likely allocl = 2; 1910fca5deaSCatalin Marinas l = 1; 1920fca5deaSCatalin Marinas *pathp = '\0'; 193bbd33931SGrant Likely } else { 194bbd33931SGrant Likely /* account for '/' and path size minus terminal 0 195bbd33931SGrant Likely * already in 'l' 196bbd33931SGrant Likely */ 197bbd33931SGrant Likely fpsize += l; 198bbd33931SGrant Likely allocl = fpsize; 199bbd33931SGrant Likely } 200bbd33931SGrant Likely } 201bbd33931SGrant Likely 202bbd33931SGrant Likely np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, 203bbd33931SGrant Likely __alignof__(struct device_node)); 204bbd33931SGrant Likely if (allnextpp) { 205c22618a1SGrant Likely char *fn; 206c22618a1SGrant Likely np->full_name = fn = ((char *)np) + sizeof(*np); 207bbd33931SGrant Likely if (new_format) { 208bbd33931SGrant Likely /* rebuild full path for new format */ 209bbd33931SGrant Likely if (dad && dad->parent) { 210bbd33931SGrant Likely strcpy(fn, dad->full_name); 211bbd33931SGrant Likely #ifdef DEBUG 212bbd33931SGrant Likely if ((strlen(fn) + l + 1) != allocl) { 213bbd33931SGrant Likely pr_debug("%s: p: %d, l: %d, a: %d\n", 214bbd33931SGrant Likely pathp, (int)strlen(fn), 215bbd33931SGrant Likely l, allocl); 216bbd33931SGrant Likely } 217bbd33931SGrant Likely #endif 218bbd33931SGrant Likely fn += strlen(fn); 219bbd33931SGrant Likely } 220bbd33931SGrant Likely *(fn++) = '/'; 221c22618a1SGrant Likely } 222bbd33931SGrant Likely memcpy(fn, pathp, l); 223c22618a1SGrant Likely 224bbd33931SGrant Likely prev_pp = &np->properties; 225bbd33931SGrant Likely **allnextpp = np; 226bbd33931SGrant Likely *allnextpp = &np->allnext; 227bbd33931SGrant Likely if (dad != NULL) { 228bbd33931SGrant Likely np->parent = dad; 229bbd33931SGrant Likely /* we temporarily use the next field as `last_child'*/ 230bbd33931SGrant Likely if (dad->next == NULL) 231bbd33931SGrant Likely dad->child = np; 232bbd33931SGrant Likely else 233bbd33931SGrant Likely dad->next->sibling = np; 234bbd33931SGrant Likely dad->next = np; 235bbd33931SGrant Likely } 236bbd33931SGrant Likely kref_init(&np->kref); 237bbd33931SGrant Likely } 238a7006c97SAndres Salomon /* process properties */ 239bbd33931SGrant Likely while (1) { 240bbd33931SGrant Likely u32 sz, noff; 241bbd33931SGrant Likely char *pname; 242bbd33931SGrant Likely 24344856819SGrant Likely tag = be32_to_cpup(*p); 244bbd33931SGrant Likely if (tag == OF_DT_NOP) { 245bbd33931SGrant Likely *p += 4; 246bbd33931SGrant Likely continue; 247bbd33931SGrant Likely } 248bbd33931SGrant Likely if (tag != OF_DT_PROP) 249bbd33931SGrant Likely break; 250bbd33931SGrant Likely *p += 4; 25144856819SGrant Likely sz = be32_to_cpup(*p); 25244856819SGrant Likely noff = be32_to_cpup(*p + 4); 253bbd33931SGrant Likely *p += 8; 254a40d6c4cSStephen Neuendorffer if (be32_to_cpu(blob->version) < 0x10) 25544856819SGrant Likely *p = PTR_ALIGN(*p, sz >= 8 ? 8 : 4); 256bbd33931SGrant Likely 257a40d6c4cSStephen Neuendorffer pname = of_fdt_get_string(blob, noff); 258bbd33931SGrant Likely if (pname == NULL) { 259bbd33931SGrant Likely pr_info("Can't find property name in list !\n"); 260bbd33931SGrant Likely break; 261bbd33931SGrant Likely } 262bbd33931SGrant Likely if (strcmp(pname, "name") == 0) 263bbd33931SGrant Likely has_name = 1; 264bbd33931SGrant Likely l = strlen(pname) + 1; 265bbd33931SGrant Likely pp = unflatten_dt_alloc(&mem, sizeof(struct property), 266bbd33931SGrant Likely __alignof__(struct property)); 267bbd33931SGrant Likely if (allnextpp) { 26804b954a6SDavid Gibson /* We accept flattened tree phandles either in 26904b954a6SDavid Gibson * ePAPR-style "phandle" properties, or the 27004b954a6SDavid Gibson * legacy "linux,phandle" properties. If both 27104b954a6SDavid Gibson * appear and have different values, things 27204b954a6SDavid Gibson * will get weird. Don't do that. */ 27304b954a6SDavid Gibson if ((strcmp(pname, "phandle") == 0) || 27404b954a6SDavid Gibson (strcmp(pname, "linux,phandle") == 0)) { 2756016a363SGrant Likely if (np->phandle == 0) 2769a6b2e58SGrant Likely np->phandle = be32_to_cpup((__be32*)*p); 277bbd33931SGrant Likely } 27804b954a6SDavid Gibson /* And we process the "ibm,phandle" property 27904b954a6SDavid Gibson * used in pSeries dynamic device tree 28004b954a6SDavid Gibson * stuff */ 281bbd33931SGrant Likely if (strcmp(pname, "ibm,phandle") == 0) 2829a6b2e58SGrant Likely np->phandle = be32_to_cpup((__be32 *)*p); 283bbd33931SGrant Likely pp->name = pname; 284bbd33931SGrant Likely pp->length = sz; 28544856819SGrant Likely pp->value = *p; 286bbd33931SGrant Likely *prev_pp = pp; 287bbd33931SGrant Likely prev_pp = &pp->next; 288bbd33931SGrant Likely } 28944856819SGrant Likely *p = PTR_ALIGN((*p) + sz, 4); 290bbd33931SGrant Likely } 291bbd33931SGrant Likely /* with version 0x10 we may not have the name property, recreate 292bbd33931SGrant Likely * it here from the unit name if absent 293bbd33931SGrant Likely */ 294bbd33931SGrant Likely if (!has_name) { 295bbd33931SGrant Likely char *p1 = pathp, *ps = pathp, *pa = NULL; 296bbd33931SGrant Likely int sz; 297bbd33931SGrant Likely 298bbd33931SGrant Likely while (*p1) { 299bbd33931SGrant Likely if ((*p1) == '@') 300bbd33931SGrant Likely pa = p1; 301bbd33931SGrant Likely if ((*p1) == '/') 302bbd33931SGrant Likely ps = p1 + 1; 303bbd33931SGrant Likely p1++; 304bbd33931SGrant Likely } 305bbd33931SGrant Likely if (pa < ps) 306bbd33931SGrant Likely pa = p1; 307bbd33931SGrant Likely sz = (pa - ps) + 1; 308bbd33931SGrant Likely pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, 309bbd33931SGrant Likely __alignof__(struct property)); 310bbd33931SGrant Likely if (allnextpp) { 311bbd33931SGrant Likely pp->name = "name"; 312bbd33931SGrant Likely pp->length = sz; 313bbd33931SGrant Likely pp->value = pp + 1; 314bbd33931SGrant Likely *prev_pp = pp; 315bbd33931SGrant Likely prev_pp = &pp->next; 316bbd33931SGrant Likely memcpy(pp->value, ps, sz - 1); 317bbd33931SGrant Likely ((char *)pp->value)[sz - 1] = 0; 318bbd33931SGrant Likely pr_debug("fixed up name for %s -> %s\n", pathp, 319bbd33931SGrant Likely (char *)pp->value); 320bbd33931SGrant Likely } 321bbd33931SGrant Likely } 322bbd33931SGrant Likely if (allnextpp) { 323bbd33931SGrant Likely *prev_pp = NULL; 324bbd33931SGrant Likely np->name = of_get_property(np, "name", NULL); 325bbd33931SGrant Likely np->type = of_get_property(np, "device_type", NULL); 326bbd33931SGrant Likely 327bbd33931SGrant Likely if (!np->name) 328bbd33931SGrant Likely np->name = "<NULL>"; 329bbd33931SGrant Likely if (!np->type) 330bbd33931SGrant Likely np->type = "<NULL>"; 331bbd33931SGrant Likely } 3327f809e1fSJason Gunthorpe while (tag == OF_DT_BEGIN_NODE || tag == OF_DT_NOP) { 3337f809e1fSJason Gunthorpe if (tag == OF_DT_NOP) 3347f809e1fSJason Gunthorpe *p += 4; 3357f809e1fSJason Gunthorpe else 336a40d6c4cSStephen Neuendorffer mem = unflatten_dt_node(blob, mem, p, np, allnextpp, 337a40d6c4cSStephen Neuendorffer fpsize); 33844856819SGrant Likely tag = be32_to_cpup(*p); 339bbd33931SGrant Likely } 340bbd33931SGrant Likely if (tag != OF_DT_END_NODE) { 341bbd33931SGrant Likely pr_err("Weird tag at end of node: %x\n", tag); 342bbd33931SGrant Likely return mem; 343bbd33931SGrant Likely } 344bbd33931SGrant Likely *p += 4; 345bbd33931SGrant Likely return mem; 346bbd33931SGrant Likely } 34741f88009SGrant Likely 348fe140423SStephen Neuendorffer /** 349fe140423SStephen Neuendorffer * __unflatten_device_tree - create tree of device_nodes from flat blob 350fe140423SStephen Neuendorffer * 351fe140423SStephen Neuendorffer * unflattens a device-tree, creating the 352fe140423SStephen Neuendorffer * tree of struct device_node. It also fills the "name" and "type" 353fe140423SStephen Neuendorffer * pointers of the nodes so the normal device-tree walking functions 354fe140423SStephen Neuendorffer * can be used. 355fe140423SStephen Neuendorffer * @blob: The blob to expand 356fe140423SStephen Neuendorffer * @mynodes: The device_node tree created by the call 357fe140423SStephen Neuendorffer * @dt_alloc: An allocator that provides a virtual address to memory 358fe140423SStephen Neuendorffer * for the resulting tree 359fe140423SStephen Neuendorffer */ 360a7006c97SAndres Salomon static void __unflatten_device_tree(struct boot_param_header *blob, 361fe140423SStephen Neuendorffer struct device_node **mynodes, 362fe140423SStephen Neuendorffer void * (*dt_alloc)(u64 size, u64 align)) 363fe140423SStephen Neuendorffer { 36444856819SGrant Likely unsigned long size; 36544856819SGrant Likely void *start, *mem; 366fe140423SStephen Neuendorffer struct device_node **allnextp = mynodes; 367fe140423SStephen Neuendorffer 368fe140423SStephen Neuendorffer pr_debug(" -> unflatten_device_tree()\n"); 369fe140423SStephen Neuendorffer 370fe140423SStephen Neuendorffer if (!blob) { 371fe140423SStephen Neuendorffer pr_debug("No device tree pointer\n"); 372fe140423SStephen Neuendorffer return; 373fe140423SStephen Neuendorffer } 374fe140423SStephen Neuendorffer 375fe140423SStephen Neuendorffer pr_debug("Unflattening device tree:\n"); 376fe140423SStephen Neuendorffer pr_debug("magic: %08x\n", be32_to_cpu(blob->magic)); 377fe140423SStephen Neuendorffer pr_debug("size: %08x\n", be32_to_cpu(blob->totalsize)); 378fe140423SStephen Neuendorffer pr_debug("version: %08x\n", be32_to_cpu(blob->version)); 379fe140423SStephen Neuendorffer 380fe140423SStephen Neuendorffer if (be32_to_cpu(blob->magic) != OF_DT_HEADER) { 381fe140423SStephen Neuendorffer pr_err("Invalid device tree blob header\n"); 382fe140423SStephen Neuendorffer return; 383fe140423SStephen Neuendorffer } 384fe140423SStephen Neuendorffer 385fe140423SStephen Neuendorffer /* First pass, scan for size */ 38644856819SGrant Likely start = ((void *)blob) + be32_to_cpu(blob->off_dt_struct); 38744856819SGrant Likely size = (unsigned long)unflatten_dt_node(blob, 0, &start, NULL, NULL, 0); 38844856819SGrant Likely size = ALIGN(size, 4); 389fe140423SStephen Neuendorffer 390fe140423SStephen Neuendorffer pr_debug(" size is %lx, allocating...\n", size); 391fe140423SStephen Neuendorffer 392fe140423SStephen Neuendorffer /* Allocate memory for the expanded device tree */ 39344856819SGrant Likely mem = dt_alloc(size + 4, __alignof__(struct device_node)); 39444856819SGrant Likely memset(mem, 0, size); 395fe140423SStephen Neuendorffer 39644856819SGrant Likely *(__be32 *)(mem + size) = cpu_to_be32(0xdeadbeef); 3979e401275SWladislav Wiebe 39844856819SGrant Likely pr_debug(" unflattening %p...\n", mem); 399fe140423SStephen Neuendorffer 400fe140423SStephen Neuendorffer /* Second pass, do actual unflattening */ 40144856819SGrant Likely start = ((void *)blob) + be32_to_cpu(blob->off_dt_struct); 402fe140423SStephen Neuendorffer unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0); 40344856819SGrant Likely if (be32_to_cpup(start) != OF_DT_END) 40444856819SGrant Likely pr_warning("Weird tag at end of tree: %08x\n", be32_to_cpup(start)); 40544856819SGrant Likely if (be32_to_cpup(mem + size) != 0xdeadbeef) 406fe140423SStephen Neuendorffer pr_warning("End of tree marker overwritten: %08x\n", 40744856819SGrant Likely be32_to_cpup(mem + size)); 408fe140423SStephen Neuendorffer *allnextp = NULL; 409fe140423SStephen Neuendorffer 410fe140423SStephen Neuendorffer pr_debug(" <- unflatten_device_tree()\n"); 411fe140423SStephen Neuendorffer } 412fe140423SStephen Neuendorffer 413fe140423SStephen Neuendorffer static void *kernel_tree_alloc(u64 size, u64 align) 414fe140423SStephen Neuendorffer { 415fe140423SStephen Neuendorffer return kzalloc(size, GFP_KERNEL); 416fe140423SStephen Neuendorffer } 417fe140423SStephen Neuendorffer 418fe140423SStephen Neuendorffer /** 419fe140423SStephen Neuendorffer * of_fdt_unflatten_tree - create tree of device_nodes from flat blob 420fe140423SStephen Neuendorffer * 421fe140423SStephen Neuendorffer * unflattens the device-tree passed by the firmware, creating the 422fe140423SStephen Neuendorffer * tree of struct device_node. It also fills the "name" and "type" 423fe140423SStephen Neuendorffer * pointers of the nodes so the normal device-tree walking functions 424fe140423SStephen Neuendorffer * can be used. 425fe140423SStephen Neuendorffer */ 426fe140423SStephen Neuendorffer void of_fdt_unflatten_tree(unsigned long *blob, 427fe140423SStephen Neuendorffer struct device_node **mynodes) 428fe140423SStephen Neuendorffer { 429fe140423SStephen Neuendorffer struct boot_param_header *device_tree = 430fe140423SStephen Neuendorffer (struct boot_param_header *)blob; 431fe140423SStephen Neuendorffer __unflatten_device_tree(device_tree, mynodes, &kernel_tree_alloc); 432fe140423SStephen Neuendorffer } 433fe140423SStephen Neuendorffer EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree); 434fe140423SStephen Neuendorffer 43557d00ecfSStephen Neuendorffer /* Everything below here references initial_boot_params directly. */ 43657d00ecfSStephen Neuendorffer int __initdata dt_root_addr_cells; 43757d00ecfSStephen Neuendorffer int __initdata dt_root_size_cells; 43857d00ecfSStephen Neuendorffer 43957d00ecfSStephen Neuendorffer struct boot_param_header *initial_boot_params; 44057d00ecfSStephen Neuendorffer 44157d00ecfSStephen Neuendorffer #ifdef CONFIG_OF_EARLY_FLATTREE 44257d00ecfSStephen Neuendorffer 44357d00ecfSStephen Neuendorffer /** 44457d00ecfSStephen Neuendorffer * of_scan_flat_dt - scan flattened tree blob and call callback on each. 44557d00ecfSStephen Neuendorffer * @it: callback function 44657d00ecfSStephen Neuendorffer * @data: context data pointer 44757d00ecfSStephen Neuendorffer * 44857d00ecfSStephen Neuendorffer * This function is used to scan the flattened device-tree, it is 44957d00ecfSStephen Neuendorffer * used to extract the memory information at boot before we can 45057d00ecfSStephen Neuendorffer * unflatten the tree 45157d00ecfSStephen Neuendorffer */ 45257d00ecfSStephen Neuendorffer int __init of_scan_flat_dt(int (*it)(unsigned long node, 45357d00ecfSStephen Neuendorffer const char *uname, int depth, 45457d00ecfSStephen Neuendorffer void *data), 45557d00ecfSStephen Neuendorffer void *data) 45657d00ecfSStephen Neuendorffer { 45757d00ecfSStephen Neuendorffer unsigned long p = ((unsigned long)initial_boot_params) + 45857d00ecfSStephen Neuendorffer be32_to_cpu(initial_boot_params->off_dt_struct); 45957d00ecfSStephen Neuendorffer int rc = 0; 46057d00ecfSStephen Neuendorffer int depth = -1; 46157d00ecfSStephen Neuendorffer 46257d00ecfSStephen Neuendorffer do { 46357d00ecfSStephen Neuendorffer u32 tag = be32_to_cpup((__be32 *)p); 464e55b0829SFabio Estevam const char *pathp; 46557d00ecfSStephen Neuendorffer 46657d00ecfSStephen Neuendorffer p += 4; 46757d00ecfSStephen Neuendorffer if (tag == OF_DT_END_NODE) { 46857d00ecfSStephen Neuendorffer depth--; 46957d00ecfSStephen Neuendorffer continue; 47057d00ecfSStephen Neuendorffer } 47157d00ecfSStephen Neuendorffer if (tag == OF_DT_NOP) 47257d00ecfSStephen Neuendorffer continue; 47357d00ecfSStephen Neuendorffer if (tag == OF_DT_END) 47457d00ecfSStephen Neuendorffer break; 47557d00ecfSStephen Neuendorffer if (tag == OF_DT_PROP) { 47657d00ecfSStephen Neuendorffer u32 sz = be32_to_cpup((__be32 *)p); 47757d00ecfSStephen Neuendorffer p += 8; 47857d00ecfSStephen Neuendorffer if (be32_to_cpu(initial_boot_params->version) < 0x10) 47957d00ecfSStephen Neuendorffer p = ALIGN(p, sz >= 8 ? 8 : 4); 48057d00ecfSStephen Neuendorffer p += sz; 48157d00ecfSStephen Neuendorffer p = ALIGN(p, 4); 48257d00ecfSStephen Neuendorffer continue; 48357d00ecfSStephen Neuendorffer } 48457d00ecfSStephen Neuendorffer if (tag != OF_DT_BEGIN_NODE) { 48557d00ecfSStephen Neuendorffer pr_err("Invalid tag %x in flat device tree!\n", tag); 48657d00ecfSStephen Neuendorffer return -EINVAL; 48757d00ecfSStephen Neuendorffer } 48857d00ecfSStephen Neuendorffer depth++; 48957d00ecfSStephen Neuendorffer pathp = (char *)p; 49057d00ecfSStephen Neuendorffer p = ALIGN(p + strlen(pathp) + 1, 4); 491375da3a7SAndy Shevchenko if (*pathp == '/') 492375da3a7SAndy Shevchenko pathp = kbasename(pathp); 49357d00ecfSStephen Neuendorffer rc = it(p, pathp, depth, data); 49457d00ecfSStephen Neuendorffer if (rc != 0) 49557d00ecfSStephen Neuendorffer break; 49657d00ecfSStephen Neuendorffer } while (1); 49757d00ecfSStephen Neuendorffer 49857d00ecfSStephen Neuendorffer return rc; 49957d00ecfSStephen Neuendorffer } 50057d00ecfSStephen Neuendorffer 50157d00ecfSStephen Neuendorffer /** 50257d00ecfSStephen Neuendorffer * of_get_flat_dt_root - find the root node in the flat blob 50357d00ecfSStephen Neuendorffer */ 50457d00ecfSStephen Neuendorffer unsigned long __init of_get_flat_dt_root(void) 50557d00ecfSStephen Neuendorffer { 50657d00ecfSStephen Neuendorffer unsigned long p = ((unsigned long)initial_boot_params) + 50757d00ecfSStephen Neuendorffer be32_to_cpu(initial_boot_params->off_dt_struct); 50857d00ecfSStephen Neuendorffer 50957d00ecfSStephen Neuendorffer while (be32_to_cpup((__be32 *)p) == OF_DT_NOP) 51057d00ecfSStephen Neuendorffer p += 4; 51157d00ecfSStephen Neuendorffer BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE); 51257d00ecfSStephen Neuendorffer p += 4; 51357d00ecfSStephen Neuendorffer return ALIGN(p + strlen((char *)p) + 1, 4); 51457d00ecfSStephen Neuendorffer } 51557d00ecfSStephen Neuendorffer 51657d00ecfSStephen Neuendorffer /** 51757d00ecfSStephen Neuendorffer * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr 51857d00ecfSStephen Neuendorffer * 51957d00ecfSStephen Neuendorffer * This function can be used within scan_flattened_dt callback to get 52057d00ecfSStephen Neuendorffer * access to properties 52157d00ecfSStephen Neuendorffer */ 52257d00ecfSStephen Neuendorffer void *__init of_get_flat_dt_prop(unsigned long node, const char *name, 52357d00ecfSStephen Neuendorffer unsigned long *size) 52457d00ecfSStephen Neuendorffer { 52557d00ecfSStephen Neuendorffer return of_fdt_get_property(initial_boot_params, node, name, size); 52657d00ecfSStephen Neuendorffer } 52757d00ecfSStephen Neuendorffer 52857d00ecfSStephen Neuendorffer /** 52957d00ecfSStephen Neuendorffer * of_flat_dt_is_compatible - Return true if given node has compat in compatible list 53057d00ecfSStephen Neuendorffer * @node: node to test 53157d00ecfSStephen Neuendorffer * @compat: compatible string to compare with compatible list. 53257d00ecfSStephen Neuendorffer */ 53357d00ecfSStephen Neuendorffer int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) 53457d00ecfSStephen Neuendorffer { 53557d00ecfSStephen Neuendorffer return of_fdt_is_compatible(initial_boot_params, node, compat); 53657d00ecfSStephen Neuendorffer } 53757d00ecfSStephen Neuendorffer 538a4f740cfSGrant Likely /** 539a4f740cfSGrant Likely * of_flat_dt_match - Return true if node matches a list of compatible values 540a4f740cfSGrant Likely */ 5417b482c83SUwe Kleine-König int __init of_flat_dt_match(unsigned long node, const char *const *compat) 542a4f740cfSGrant Likely { 543a4f740cfSGrant Likely return of_fdt_match(initial_boot_params, node, compat); 544a4f740cfSGrant Likely } 545a4f740cfSGrant Likely 54657d74bcfSMarek Szyprowski struct fdt_scan_status { 54757d74bcfSMarek Szyprowski const char *name; 54857d74bcfSMarek Szyprowski int namelen; 54957d74bcfSMarek Szyprowski int depth; 55057d74bcfSMarek Szyprowski int found; 55157d74bcfSMarek Szyprowski int (*iterator)(unsigned long node, const char *uname, int depth, void *data); 55257d74bcfSMarek Szyprowski void *data; 55357d74bcfSMarek Szyprowski }; 55457d74bcfSMarek Szyprowski 55557d74bcfSMarek Szyprowski /** 55657d74bcfSMarek Szyprowski * fdt_scan_node_by_path - iterator for of_scan_flat_dt_by_path function 55757d74bcfSMarek Szyprowski */ 55857d74bcfSMarek Szyprowski static int __init fdt_scan_node_by_path(unsigned long node, const char *uname, 55957d74bcfSMarek Szyprowski int depth, void *data) 56057d74bcfSMarek Szyprowski { 56157d74bcfSMarek Szyprowski struct fdt_scan_status *st = data; 56257d74bcfSMarek Szyprowski 56357d74bcfSMarek Szyprowski /* 56457d74bcfSMarek Szyprowski * if scan at the requested fdt node has been completed, 56557d74bcfSMarek Szyprowski * return -ENXIO to abort further scanning 56657d74bcfSMarek Szyprowski */ 56757d74bcfSMarek Szyprowski if (depth <= st->depth) 56857d74bcfSMarek Szyprowski return -ENXIO; 56957d74bcfSMarek Szyprowski 57057d74bcfSMarek Szyprowski /* requested fdt node has been found, so call iterator function */ 57157d74bcfSMarek Szyprowski if (st->found) 57257d74bcfSMarek Szyprowski return st->iterator(node, uname, depth, st->data); 57357d74bcfSMarek Szyprowski 57457d74bcfSMarek Szyprowski /* check if scanning automata is entering next level of fdt nodes */ 57557d74bcfSMarek Szyprowski if (depth == st->depth + 1 && 57657d74bcfSMarek Szyprowski strncmp(st->name, uname, st->namelen) == 0 && 57757d74bcfSMarek Szyprowski uname[st->namelen] == 0) { 57857d74bcfSMarek Szyprowski st->depth += 1; 57957d74bcfSMarek Szyprowski if (st->name[st->namelen] == 0) { 58057d74bcfSMarek Szyprowski st->found = 1; 58157d74bcfSMarek Szyprowski } else { 58257d74bcfSMarek Szyprowski const char *next = st->name + st->namelen + 1; 58357d74bcfSMarek Szyprowski st->name = next; 58457d74bcfSMarek Szyprowski st->namelen = strcspn(next, "/"); 58557d74bcfSMarek Szyprowski } 58657d74bcfSMarek Szyprowski return 0; 58757d74bcfSMarek Szyprowski } 58857d74bcfSMarek Szyprowski 58957d74bcfSMarek Szyprowski /* scan next fdt node */ 59057d74bcfSMarek Szyprowski return 0; 59157d74bcfSMarek Szyprowski } 59257d74bcfSMarek Szyprowski 59357d74bcfSMarek Szyprowski /** 59457d74bcfSMarek Szyprowski * of_scan_flat_dt_by_path - scan flattened tree blob and call callback on each 59557d74bcfSMarek Szyprowski * child of the given path. 59657d74bcfSMarek Szyprowski * @path: path to start searching for children 59757d74bcfSMarek Szyprowski * @it: callback function 59857d74bcfSMarek Szyprowski * @data: context data pointer 59957d74bcfSMarek Szyprowski * 60057d74bcfSMarek Szyprowski * This function is used to scan the flattened device-tree starting from the 60157d74bcfSMarek Szyprowski * node given by path. It is used to extract information (like reserved 60257d74bcfSMarek Szyprowski * memory), which is required on ealy boot before we can unflatten the tree. 60357d74bcfSMarek Szyprowski */ 60457d74bcfSMarek Szyprowski int __init of_scan_flat_dt_by_path(const char *path, 60557d74bcfSMarek Szyprowski int (*it)(unsigned long node, const char *name, int depth, void *data), 60657d74bcfSMarek Szyprowski void *data) 60757d74bcfSMarek Szyprowski { 60857d74bcfSMarek Szyprowski struct fdt_scan_status st = {path, 0, -1, 0, it, data}; 60957d74bcfSMarek Szyprowski int ret = 0; 61057d74bcfSMarek Szyprowski 61157d74bcfSMarek Szyprowski if (initial_boot_params) 61257d74bcfSMarek Szyprowski ret = of_scan_flat_dt(fdt_scan_node_by_path, &st); 61357d74bcfSMarek Szyprowski 61457d74bcfSMarek Szyprowski if (!st.found) 61557d74bcfSMarek Szyprowski return -ENOENT; 61657d74bcfSMarek Szyprowski else if (ret == -ENXIO) /* scan has been completed */ 61757d74bcfSMarek Szyprowski return 0; 61857d74bcfSMarek Szyprowski else 61957d74bcfSMarek Szyprowski return ret; 62057d74bcfSMarek Szyprowski } 62157d74bcfSMarek Szyprowski 622f7b3a835SGrant Likely #ifdef CONFIG_BLK_DEV_INITRD 623f7b3a835SGrant Likely /** 624f7b3a835SGrant Likely * early_init_dt_check_for_initrd - Decode initrd location from flat tree 625f7b3a835SGrant Likely * @node: reference to node containing initrd location ('chosen') 626f7b3a835SGrant Likely */ 62729eb45a9SRob Herring static void __init early_init_dt_check_for_initrd(unsigned long node) 628f7b3a835SGrant Likely { 629374d5c99SSantosh Shilimkar u64 start, end; 630374d5c99SSantosh Shilimkar unsigned long len; 63133714881SJeremy Kerr __be32 *prop; 632f7b3a835SGrant Likely 633f7b3a835SGrant Likely pr_debug("Looking for initrd properties... "); 634f7b3a835SGrant Likely 635f7b3a835SGrant Likely prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len); 6361406bc2fSJeremy Kerr if (!prop) 6371406bc2fSJeremy Kerr return; 638374d5c99SSantosh Shilimkar start = of_read_number(prop, len/4); 639f7b3a835SGrant Likely 640f7b3a835SGrant Likely prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len); 6411406bc2fSJeremy Kerr if (!prop) 6421406bc2fSJeremy Kerr return; 643374d5c99SSantosh Shilimkar end = of_read_number(prop, len/4); 644f7b3a835SGrant Likely 64529eb45a9SRob Herring initrd_start = (unsigned long)__va(start); 64629eb45a9SRob Herring initrd_end = (unsigned long)__va(end); 64729eb45a9SRob Herring initrd_below_start_ok = 1; 64829eb45a9SRob Herring 649374d5c99SSantosh Shilimkar pr_debug("initrd_start=0x%llx initrd_end=0x%llx\n", 650374d5c99SSantosh Shilimkar (unsigned long long)start, (unsigned long long)end); 651f7b3a835SGrant Likely } 652f7b3a835SGrant Likely #else 65329eb45a9SRob Herring static inline void early_init_dt_check_for_initrd(unsigned long node) 654f7b3a835SGrant Likely { 655f7b3a835SGrant Likely } 656f7b3a835SGrant Likely #endif /* CONFIG_BLK_DEV_INITRD */ 657f7b3a835SGrant Likely 65841f88009SGrant Likely /** 659f00abd94SGrant Likely * early_init_dt_scan_root - fetch the top level address and size cells 660f00abd94SGrant Likely */ 661f00abd94SGrant Likely int __init early_init_dt_scan_root(unsigned long node, const char *uname, 662f00abd94SGrant Likely int depth, void *data) 663f00abd94SGrant Likely { 66433714881SJeremy Kerr __be32 *prop; 665f00abd94SGrant Likely 666f00abd94SGrant Likely if (depth != 0) 667f00abd94SGrant Likely return 0; 668f00abd94SGrant Likely 66933714881SJeremy Kerr dt_root_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT; 67033714881SJeremy Kerr dt_root_addr_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT; 67133714881SJeremy Kerr 672f00abd94SGrant Likely prop = of_get_flat_dt_prop(node, "#size-cells", NULL); 67333714881SJeremy Kerr if (prop) 67433714881SJeremy Kerr dt_root_size_cells = be32_to_cpup(prop); 675f00abd94SGrant Likely pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells); 676f00abd94SGrant Likely 677f00abd94SGrant Likely prop = of_get_flat_dt_prop(node, "#address-cells", NULL); 67833714881SJeremy Kerr if (prop) 67933714881SJeremy Kerr dt_root_addr_cells = be32_to_cpup(prop); 680f00abd94SGrant Likely pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells); 681f00abd94SGrant Likely 682f00abd94SGrant Likely /* break now */ 683f00abd94SGrant Likely return 1; 684f00abd94SGrant Likely } 685f00abd94SGrant Likely 6862e89e685SJeremy Kerr u64 __init dt_mem_next_cell(int s, __be32 **cellp) 68783f7a06eSGrant Likely { 6882e89e685SJeremy Kerr __be32 *p = *cellp; 68983f7a06eSGrant Likely 69083f7a06eSGrant Likely *cellp = p + s; 69183f7a06eSGrant Likely return of_read_number(p, s); 69283f7a06eSGrant Likely } 69383f7a06eSGrant Likely 69451975db0SGrant Likely /** 69551975db0SGrant Likely * early_init_dt_scan_memory - Look for an parse memory nodes 69651975db0SGrant Likely */ 69751975db0SGrant Likely int __init early_init_dt_scan_memory(unsigned long node, const char *uname, 69851975db0SGrant Likely int depth, void *data) 69951975db0SGrant Likely { 70051975db0SGrant Likely char *type = of_get_flat_dt_prop(node, "device_type", NULL); 70151975db0SGrant Likely __be32 *reg, *endp; 70251975db0SGrant Likely unsigned long l; 70351975db0SGrant Likely 70451975db0SGrant Likely /* We are scanning "memory" nodes only */ 70551975db0SGrant Likely if (type == NULL) { 70651975db0SGrant Likely /* 70751975db0SGrant Likely * The longtrail doesn't have a device_type on the 70851975db0SGrant Likely * /memory node, so look for the node called /memory@0. 70951975db0SGrant Likely */ 71051975db0SGrant Likely if (depth != 1 || strcmp(uname, "memory@0") != 0) 71151975db0SGrant Likely return 0; 71251975db0SGrant Likely } else if (strcmp(type, "memory") != 0) 71351975db0SGrant Likely return 0; 71451975db0SGrant Likely 71551975db0SGrant Likely reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l); 71651975db0SGrant Likely if (reg == NULL) 71751975db0SGrant Likely reg = of_get_flat_dt_prop(node, "reg", &l); 71851975db0SGrant Likely if (reg == NULL) 71951975db0SGrant Likely return 0; 72051975db0SGrant Likely 72151975db0SGrant Likely endp = reg + (l / sizeof(__be32)); 72251975db0SGrant Likely 72351975db0SGrant Likely pr_debug("memory scan node %s, reg size %ld, data: %x %x %x %x,\n", 72451975db0SGrant Likely uname, l, reg[0], reg[1], reg[2], reg[3]); 72551975db0SGrant Likely 72651975db0SGrant Likely while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { 72751975db0SGrant Likely u64 base, size; 72851975db0SGrant Likely 72951975db0SGrant Likely base = dt_mem_next_cell(dt_root_addr_cells, ®); 73051975db0SGrant Likely size = dt_mem_next_cell(dt_root_size_cells, ®); 73151975db0SGrant Likely 73251975db0SGrant Likely if (size == 0) 73351975db0SGrant Likely continue; 73451975db0SGrant Likely pr_debug(" - %llx , %llx\n", (unsigned long long)base, 73551975db0SGrant Likely (unsigned long long)size); 73651975db0SGrant Likely 73751975db0SGrant Likely early_init_dt_add_memory_arch(base, size); 73851975db0SGrant Likely } 73951975db0SGrant Likely 74051975db0SGrant Likely return 0; 74151975db0SGrant Likely } 74251975db0SGrant Likely 74386e03221SGrant Likely int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, 74486e03221SGrant Likely int depth, void *data) 74586e03221SGrant Likely { 74686e03221SGrant Likely unsigned long l; 74786e03221SGrant Likely char *p; 74886e03221SGrant Likely 74986e03221SGrant Likely pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname); 75086e03221SGrant Likely 75185f60ae4SGrant Likely if (depth != 1 || !data || 75286e03221SGrant Likely (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0)) 75386e03221SGrant Likely return 0; 75486e03221SGrant Likely 75586e03221SGrant Likely early_init_dt_check_for_initrd(node); 75686e03221SGrant Likely 75725985edcSLucas De Marchi /* Retrieve command line */ 75886e03221SGrant Likely p = of_get_flat_dt_prop(node, "bootargs", &l); 75986e03221SGrant Likely if (p != NULL && l > 0) 76085f60ae4SGrant Likely strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE)); 76186e03221SGrant Likely 76278b782cbSBenjamin Herrenschmidt /* 76378b782cbSBenjamin Herrenschmidt * CONFIG_CMDLINE is meant to be a default in case nothing else 76478b782cbSBenjamin Herrenschmidt * managed to set the command line, unless CONFIG_CMDLINE_FORCE 76578b782cbSBenjamin Herrenschmidt * is set in which case we override whatever was found earlier. 76678b782cbSBenjamin Herrenschmidt */ 76786e03221SGrant Likely #ifdef CONFIG_CMDLINE 76886e03221SGrant Likely #ifndef CONFIG_CMDLINE_FORCE 76978b782cbSBenjamin Herrenschmidt if (!((char *)data)[0]) 77086e03221SGrant Likely #endif 77185f60ae4SGrant Likely strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE); 77286e03221SGrant Likely #endif /* CONFIG_CMDLINE */ 77386e03221SGrant Likely 77485f60ae4SGrant Likely pr_debug("Command line is: %s\n", (char*)data); 77586e03221SGrant Likely 77686e03221SGrant Likely /* break now */ 77786e03221SGrant Likely return 1; 77886e03221SGrant Likely } 77986e03221SGrant Likely 780a1727da5SGrant Likely #ifdef CONFIG_HAVE_MEMBLOCK 781068f6310SRob Herring void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size) 782068f6310SRob Herring { 783068f6310SRob Herring const u64 phys_offset = __pa(PAGE_OFFSET); 784068f6310SRob Herring base &= PAGE_MASK; 785068f6310SRob Herring size &= PAGE_MASK; 786068f6310SRob Herring if (base + size < phys_offset) { 787068f6310SRob Herring pr_warning("Ignoring memory block 0x%llx - 0x%llx\n", 788068f6310SRob Herring base, base + size); 789068f6310SRob Herring return; 790068f6310SRob Herring } 791068f6310SRob Herring if (base < phys_offset) { 792068f6310SRob Herring pr_warning("Ignoring memory range 0x%llx - 0x%llx\n", 793068f6310SRob Herring base, phys_offset); 794068f6310SRob Herring size -= phys_offset - base; 795068f6310SRob Herring base = phys_offset; 796068f6310SRob Herring } 797068f6310SRob Herring memblock_add(base, size); 798068f6310SRob Herring } 799068f6310SRob Herring 800a1727da5SGrant Likely /* 801a1727da5SGrant Likely * called from unflatten_device_tree() to bootstrap devicetree itself 802a1727da5SGrant Likely * Architectures can override this definition if memblock isn't used 803a1727da5SGrant Likely */ 804a1727da5SGrant Likely void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align) 805a1727da5SGrant Likely { 806a1727da5SGrant Likely return __va(memblock_alloc(size, align)); 807a1727da5SGrant Likely } 808a1727da5SGrant Likely #endif 809a1727da5SGrant Likely 8100288ffcbSRob Herring bool __init early_init_dt_scan(void *params) 8110288ffcbSRob Herring { 8120288ffcbSRob Herring if (!params) 8130288ffcbSRob Herring return false; 8140288ffcbSRob Herring 8150288ffcbSRob Herring /* Setup flat device-tree pointer */ 8160288ffcbSRob Herring initial_boot_params = params; 8170288ffcbSRob Herring 8180288ffcbSRob Herring /* check device tree validity */ 8190288ffcbSRob Herring if (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) { 8200288ffcbSRob Herring initial_boot_params = NULL; 8210288ffcbSRob Herring return false; 8220288ffcbSRob Herring } 8230288ffcbSRob Herring 8240288ffcbSRob Herring /* Retrieve various information from the /chosen node */ 8250288ffcbSRob Herring of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); 8260288ffcbSRob Herring 8270288ffcbSRob Herring /* Initialize {size,address}-cells info */ 8280288ffcbSRob Herring of_scan_flat_dt(early_init_dt_scan_root, NULL); 8290288ffcbSRob Herring 8300288ffcbSRob Herring /* Setup memory, calling early_init_dt_add_memory_arch */ 8310288ffcbSRob Herring of_scan_flat_dt(early_init_dt_scan_memory, NULL); 8320288ffcbSRob Herring 8330288ffcbSRob Herring return true; 8340288ffcbSRob Herring } 8350288ffcbSRob Herring 836f00abd94SGrant Likely /** 83741f88009SGrant Likely * unflatten_device_tree - create tree of device_nodes from flat blob 83841f88009SGrant Likely * 83941f88009SGrant Likely * unflattens the device-tree passed by the firmware, creating the 84041f88009SGrant Likely * tree of struct device_node. It also fills the "name" and "type" 84141f88009SGrant Likely * pointers of the nodes so the normal device-tree walking functions 84241f88009SGrant Likely * can be used. 84341f88009SGrant Likely */ 84441f88009SGrant Likely void __init unflatten_device_tree(void) 84541f88009SGrant Likely { 846465aac6dSRandy Dunlap __unflatten_device_tree(initial_boot_params, &of_allnodes, 847672c5446SGrant Likely early_init_dt_alloc_memory_arch); 84841f88009SGrant Likely 8494c7d6361SRobert P. J. Day /* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */ 850611cad72SShawn Guo of_alias_scan(early_init_dt_alloc_memory_arch); 85141f88009SGrant Likely } 852e6ce1324SStephen Neuendorffer 853a8bf7527SRob Herring /** 854a8bf7527SRob Herring * unflatten_and_copy_device_tree - copy and create tree of device_nodes from flat blob 855a8bf7527SRob Herring * 856a8bf7527SRob Herring * Copies and unflattens the device-tree passed by the firmware, creating the 857a8bf7527SRob Herring * tree of struct device_node. It also fills the "name" and "type" 858a8bf7527SRob Herring * pointers of the nodes so the normal device-tree walking functions 859a8bf7527SRob Herring * can be used. This should only be used when the FDT memory has not been 860a8bf7527SRob Herring * reserved such is the case when the FDT is built-in to the kernel init 861a8bf7527SRob Herring * section. If the FDT memory is reserved already then unflatten_device_tree 862a8bf7527SRob Herring * should be used instead. 863a8bf7527SRob Herring */ 864a8bf7527SRob Herring void __init unflatten_and_copy_device_tree(void) 865a8bf7527SRob Herring { 866a8bf7527SRob Herring int size = __be32_to_cpu(initial_boot_params->totalsize); 867a8bf7527SRob Herring void *dt = early_init_dt_alloc_memory_arch(size, 868a8bf7527SRob Herring __alignof__(struct boot_param_header)); 869a8bf7527SRob Herring 870a8bf7527SRob Herring if (dt) { 871a8bf7527SRob Herring memcpy(dt, initial_boot_params, size); 872a8bf7527SRob Herring initial_boot_params = dt; 873a8bf7527SRob Herring } 874a8bf7527SRob Herring unflatten_device_tree(); 875a8bf7527SRob Herring } 876a8bf7527SRob Herring 877e6ce1324SStephen Neuendorffer #endif /* CONFIG_OF_EARLY_FLATTREE */ 878109b6236SAnton Blanchard 879109b6236SAnton Blanchard /* Feed entire flattened device tree into the random pool */ 880109b6236SAnton Blanchard static int __init add_fdt_randomness(void) 881109b6236SAnton Blanchard { 882109b6236SAnton Blanchard if (initial_boot_params) 883109b6236SAnton Blanchard add_device_randomness(initial_boot_params, 884109b6236SAnton Blanchard be32_to_cpu(initial_boot_params->totalsize)); 885109b6236SAnton Blanchard 886109b6236SAnton Blanchard return 0; 887109b6236SAnton Blanchard } 888109b6236SAnton Blanchard core_initcall(add_fdt_randomness); 889