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> 15e169cfbeSGrant Likely #include <linux/of.h> 16e169cfbeSGrant Likely #include <linux/of_fdt.h> 173f0c8206SMarek Szyprowski #include <linux/of_reserved_mem.h> 18e8d9d1f5SMarek Szyprowski #include <linux/sizes.h> 194ef7b373SJeremy Kerr #include <linux/string.h> 204ef7b373SJeremy Kerr #include <linux/errno.h> 21fe140423SStephen Neuendorffer #include <linux/slab.h> 22e6a6928cSRob Herring #include <linux/libfdt.h> 2351975db0SGrant Likely 24c89810acSFabio Estevam #include <asm/setup.h> /* for COMMAND_LINE_SIZE */ 254ef7b373SJeremy Kerr #include <asm/page.h> 264ef7b373SJeremy Kerr 279706a36eSStephen Neuendorffer /** 289706a36eSStephen Neuendorffer * of_fdt_is_compatible - Return true if given node from the given blob has 299706a36eSStephen Neuendorffer * compat in its compatible list 309706a36eSStephen Neuendorffer * @blob: A device tree blob 319706a36eSStephen Neuendorffer * @node: node to test 329706a36eSStephen Neuendorffer * @compat: compatible string to compare with compatible list. 33a4f740cfSGrant Likely * 34a4f740cfSGrant Likely * On match, returns a non-zero value with smaller values returned for more 35a4f740cfSGrant Likely * specific compatible values. 369706a36eSStephen Neuendorffer */ 379706a36eSStephen Neuendorffer int of_fdt_is_compatible(struct boot_param_header *blob, 389706a36eSStephen Neuendorffer unsigned long node, const char *compat) 399706a36eSStephen Neuendorffer { 409706a36eSStephen Neuendorffer const char *cp; 419d0c4dfeSRob Herring int cplen; 429d0c4dfeSRob Herring unsigned long l, score = 0; 439706a36eSStephen Neuendorffer 44e6a6928cSRob Herring cp = fdt_getprop(blob, node, "compatible", &cplen); 459706a36eSStephen Neuendorffer if (cp == NULL) 469706a36eSStephen Neuendorffer return 0; 479706a36eSStephen Neuendorffer while (cplen > 0) { 48a4f740cfSGrant Likely score++; 499706a36eSStephen Neuendorffer if (of_compat_cmp(cp, compat, strlen(compat)) == 0) 50a4f740cfSGrant Likely return score; 519706a36eSStephen Neuendorffer l = strlen(cp) + 1; 529706a36eSStephen Neuendorffer cp += l; 539706a36eSStephen Neuendorffer cplen -= l; 549706a36eSStephen Neuendorffer } 559706a36eSStephen Neuendorffer 569706a36eSStephen Neuendorffer return 0; 579706a36eSStephen Neuendorffer } 589706a36eSStephen Neuendorffer 59a4f740cfSGrant Likely /** 60a4f740cfSGrant Likely * of_fdt_match - Return true if node matches a list of compatible values 61a4f740cfSGrant Likely */ 62a4f740cfSGrant Likely int of_fdt_match(struct boot_param_header *blob, unsigned long node, 637b482c83SUwe Kleine-König const char *const *compat) 64a4f740cfSGrant Likely { 65a4f740cfSGrant Likely unsigned int tmp, score = 0; 66a4f740cfSGrant Likely 67a4f740cfSGrant Likely if (!compat) 68a4f740cfSGrant Likely return 0; 69a4f740cfSGrant Likely 70a4f740cfSGrant Likely while (*compat) { 71a4f740cfSGrant Likely tmp = of_fdt_is_compatible(blob, node, *compat); 72a4f740cfSGrant Likely if (tmp && (score == 0 || (tmp < score))) 73a4f740cfSGrant Likely score = tmp; 74a4f740cfSGrant Likely compat++; 75a4f740cfSGrant Likely } 76a4f740cfSGrant Likely 77a4f740cfSGrant Likely return score; 78a4f740cfSGrant Likely } 79a4f740cfSGrant Likely 8044856819SGrant Likely static void *unflatten_dt_alloc(void **mem, unsigned long size, 81bbd33931SGrant Likely unsigned long align) 82bbd33931SGrant Likely { 83bbd33931SGrant Likely void *res; 84bbd33931SGrant Likely 8544856819SGrant Likely *mem = PTR_ALIGN(*mem, align); 8644856819SGrant Likely res = *mem; 87bbd33931SGrant Likely *mem += size; 88bbd33931SGrant Likely 89bbd33931SGrant Likely return res; 90bbd33931SGrant Likely } 91bbd33931SGrant Likely 92bbd33931SGrant Likely /** 93bbd33931SGrant Likely * unflatten_dt_node - Alloc and populate a device_node from the flat tree 94a40d6c4cSStephen Neuendorffer * @blob: The parent device tree blob 95a7006c97SAndres Salomon * @mem: Memory chunk to use for allocating device nodes and properties 96bbd33931SGrant Likely * @p: pointer to node in flat tree 97bbd33931SGrant Likely * @dad: Parent struct device_node 98bbd33931SGrant Likely * @allnextpp: pointer to ->allnext from last allocated device_node 99bbd33931SGrant Likely * @fpsize: Size of the node path up at the current depth. 100bbd33931SGrant Likely */ 10144856819SGrant Likely static void * unflatten_dt_node(struct boot_param_header *blob, 10244856819SGrant Likely void *mem, 103e6a6928cSRob Herring int *poffset, 104bbd33931SGrant Likely struct device_node *dad, 105bbd33931SGrant Likely struct device_node ***allnextpp, 106bbd33931SGrant Likely unsigned long fpsize) 107bbd33931SGrant Likely { 108e6a6928cSRob Herring const __be32 *p; 109bbd33931SGrant Likely struct device_node *np; 110bbd33931SGrant Likely struct property *pp, **prev_pp = NULL; 111e6a6928cSRob Herring const char *pathp; 112bbd33931SGrant Likely unsigned int l, allocl; 113e6a6928cSRob Herring static int depth = 0; 114e6a6928cSRob Herring int old_depth; 115e6a6928cSRob Herring int offset; 116bbd33931SGrant Likely int has_name = 0; 117bbd33931SGrant Likely int new_format = 0; 118bbd33931SGrant Likely 119e6a6928cSRob Herring pathp = fdt_get_name(blob, *poffset, &l); 120e6a6928cSRob Herring if (!pathp) 121bbd33931SGrant Likely return mem; 122e6a6928cSRob Herring 123e6a6928cSRob Herring allocl = l++; 124bbd33931SGrant Likely 125bbd33931SGrant Likely /* version 0x10 has a more compact unit name here instead of the full 126bbd33931SGrant Likely * path. we accumulate the full path size using "fpsize", we'll rebuild 127bbd33931SGrant Likely * it later. We detect this because the first character of the name is 128bbd33931SGrant Likely * not '/'. 129bbd33931SGrant Likely */ 130bbd33931SGrant Likely if ((*pathp) != '/') { 131bbd33931SGrant Likely new_format = 1; 132bbd33931SGrant Likely if (fpsize == 0) { 133bbd33931SGrant Likely /* root node: special case. fpsize accounts for path 134bbd33931SGrant Likely * plus terminating zero. root node only has '/', so 135bbd33931SGrant Likely * fpsize should be 2, but we want to avoid the first 136bbd33931SGrant Likely * level nodes to have two '/' so we use fpsize 1 here 137bbd33931SGrant Likely */ 138bbd33931SGrant Likely fpsize = 1; 139bbd33931SGrant Likely allocl = 2; 1400fca5deaSCatalin Marinas l = 1; 141e6a6928cSRob Herring pathp = ""; 142bbd33931SGrant Likely } else { 143bbd33931SGrant Likely /* account for '/' and path size minus terminal 0 144bbd33931SGrant Likely * already in 'l' 145bbd33931SGrant Likely */ 146bbd33931SGrant Likely fpsize += l; 147bbd33931SGrant Likely allocl = fpsize; 148bbd33931SGrant Likely } 149bbd33931SGrant Likely } 150bbd33931SGrant Likely 151bbd33931SGrant Likely np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, 152bbd33931SGrant Likely __alignof__(struct device_node)); 153bbd33931SGrant Likely if (allnextpp) { 154c22618a1SGrant Likely char *fn; 1550829f6d1SPantelis Antoniou of_node_init(np); 156c22618a1SGrant Likely np->full_name = fn = ((char *)np) + sizeof(*np); 157bbd33931SGrant Likely if (new_format) { 158bbd33931SGrant Likely /* rebuild full path for new format */ 159bbd33931SGrant Likely if (dad && dad->parent) { 160bbd33931SGrant Likely strcpy(fn, dad->full_name); 161bbd33931SGrant Likely #ifdef DEBUG 162bbd33931SGrant Likely if ((strlen(fn) + l + 1) != allocl) { 163bbd33931SGrant Likely pr_debug("%s: p: %d, l: %d, a: %d\n", 164bbd33931SGrant Likely pathp, (int)strlen(fn), 165bbd33931SGrant Likely l, allocl); 166bbd33931SGrant Likely } 167bbd33931SGrant Likely #endif 168bbd33931SGrant Likely fn += strlen(fn); 169bbd33931SGrant Likely } 170bbd33931SGrant Likely *(fn++) = '/'; 171c22618a1SGrant Likely } 172bbd33931SGrant Likely memcpy(fn, pathp, l); 173c22618a1SGrant Likely 174bbd33931SGrant Likely prev_pp = &np->properties; 175bbd33931SGrant Likely **allnextpp = np; 176bbd33931SGrant Likely *allnextpp = &np->allnext; 177bbd33931SGrant Likely if (dad != NULL) { 178bbd33931SGrant Likely np->parent = dad; 179bbd33931SGrant Likely /* we temporarily use the next field as `last_child'*/ 180bbd33931SGrant Likely if (dad->next == NULL) 181bbd33931SGrant Likely dad->child = np; 182bbd33931SGrant Likely else 183bbd33931SGrant Likely dad->next->sibling = np; 184bbd33931SGrant Likely dad->next = np; 185bbd33931SGrant Likely } 186bbd33931SGrant Likely } 187a7006c97SAndres Salomon /* process properties */ 188e6a6928cSRob Herring for (offset = fdt_first_property_offset(blob, *poffset); 189e6a6928cSRob Herring (offset >= 0); 190e6a6928cSRob Herring (offset = fdt_next_property_offset(blob, offset))) { 191e6a6928cSRob Herring const char *pname; 192e6a6928cSRob Herring u32 sz; 193bbd33931SGrant Likely 194e6a6928cSRob Herring if (!(p = fdt_getprop_by_offset(blob, offset, &pname, &sz))) { 195e6a6928cSRob Herring offset = -FDT_ERR_INTERNAL; 196bbd33931SGrant Likely break; 197e6a6928cSRob Herring } 198bbd33931SGrant Likely 199bbd33931SGrant Likely if (pname == NULL) { 200bbd33931SGrant Likely pr_info("Can't find property name in list !\n"); 201bbd33931SGrant Likely break; 202bbd33931SGrant Likely } 203bbd33931SGrant Likely if (strcmp(pname, "name") == 0) 204bbd33931SGrant Likely has_name = 1; 205bbd33931SGrant Likely pp = unflatten_dt_alloc(&mem, sizeof(struct property), 206bbd33931SGrant Likely __alignof__(struct property)); 207bbd33931SGrant Likely if (allnextpp) { 20804b954a6SDavid Gibson /* We accept flattened tree phandles either in 20904b954a6SDavid Gibson * ePAPR-style "phandle" properties, or the 21004b954a6SDavid Gibson * legacy "linux,phandle" properties. If both 21104b954a6SDavid Gibson * appear and have different values, things 21204b954a6SDavid Gibson * will get weird. Don't do that. */ 21304b954a6SDavid Gibson if ((strcmp(pname, "phandle") == 0) || 21404b954a6SDavid Gibson (strcmp(pname, "linux,phandle") == 0)) { 2156016a363SGrant Likely if (np->phandle == 0) 216e6a6928cSRob Herring np->phandle = be32_to_cpup(p); 217bbd33931SGrant Likely } 21804b954a6SDavid Gibson /* And we process the "ibm,phandle" property 21904b954a6SDavid Gibson * used in pSeries dynamic device tree 22004b954a6SDavid Gibson * stuff */ 221bbd33931SGrant Likely if (strcmp(pname, "ibm,phandle") == 0) 222e6a6928cSRob Herring np->phandle = be32_to_cpup(p); 223e6a6928cSRob Herring pp->name = (char *)pname; 224bbd33931SGrant Likely pp->length = sz; 225e6a6928cSRob Herring pp->value = (__be32 *)p; 226bbd33931SGrant Likely *prev_pp = pp; 227bbd33931SGrant Likely prev_pp = &pp->next; 228bbd33931SGrant Likely } 229bbd33931SGrant Likely } 230bbd33931SGrant Likely /* with version 0x10 we may not have the name property, recreate 231bbd33931SGrant Likely * it here from the unit name if absent 232bbd33931SGrant Likely */ 233bbd33931SGrant Likely if (!has_name) { 234e6a6928cSRob Herring const char *p1 = pathp, *ps = pathp, *pa = NULL; 235bbd33931SGrant Likely int sz; 236bbd33931SGrant Likely 237bbd33931SGrant Likely while (*p1) { 238bbd33931SGrant Likely if ((*p1) == '@') 239bbd33931SGrant Likely pa = p1; 240bbd33931SGrant Likely if ((*p1) == '/') 241bbd33931SGrant Likely ps = p1 + 1; 242bbd33931SGrant Likely p1++; 243bbd33931SGrant Likely } 244bbd33931SGrant Likely if (pa < ps) 245bbd33931SGrant Likely pa = p1; 246bbd33931SGrant Likely sz = (pa - ps) + 1; 247bbd33931SGrant Likely pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, 248bbd33931SGrant Likely __alignof__(struct property)); 249bbd33931SGrant Likely if (allnextpp) { 250bbd33931SGrant Likely pp->name = "name"; 251bbd33931SGrant Likely pp->length = sz; 252bbd33931SGrant Likely pp->value = pp + 1; 253bbd33931SGrant Likely *prev_pp = pp; 254bbd33931SGrant Likely prev_pp = &pp->next; 255bbd33931SGrant Likely memcpy(pp->value, ps, sz - 1); 256bbd33931SGrant Likely ((char *)pp->value)[sz - 1] = 0; 257bbd33931SGrant Likely pr_debug("fixed up name for %s -> %s\n", pathp, 258bbd33931SGrant Likely (char *)pp->value); 259bbd33931SGrant Likely } 260bbd33931SGrant Likely } 261bbd33931SGrant Likely if (allnextpp) { 262bbd33931SGrant Likely *prev_pp = NULL; 263bbd33931SGrant Likely np->name = of_get_property(np, "name", NULL); 264bbd33931SGrant Likely np->type = of_get_property(np, "device_type", NULL); 265bbd33931SGrant Likely 266bbd33931SGrant Likely if (!np->name) 267bbd33931SGrant Likely np->name = "<NULL>"; 268bbd33931SGrant Likely if (!np->type) 269bbd33931SGrant Likely np->type = "<NULL>"; 270bbd33931SGrant Likely } 271e6a6928cSRob Herring 272e6a6928cSRob Herring old_depth = depth; 273e6a6928cSRob Herring *poffset = fdt_next_node(blob, *poffset, &depth); 274e6a6928cSRob Herring if (depth < 0) 275e6a6928cSRob Herring depth = 0; 276e6a6928cSRob Herring while (*poffset > 0 && depth > old_depth) 277e6a6928cSRob Herring mem = unflatten_dt_node(blob, mem, poffset, np, allnextpp, 278a40d6c4cSStephen Neuendorffer fpsize); 279e6a6928cSRob Herring 280e6a6928cSRob Herring if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND) 281e6a6928cSRob Herring pr_err("unflatten: error %d processing FDT\n", *poffset); 282e6a6928cSRob Herring 283bbd33931SGrant Likely return mem; 284bbd33931SGrant Likely } 28541f88009SGrant Likely 286fe140423SStephen Neuendorffer /** 287fe140423SStephen Neuendorffer * __unflatten_device_tree - create tree of device_nodes from flat blob 288fe140423SStephen Neuendorffer * 289fe140423SStephen Neuendorffer * unflattens a device-tree, creating the 290fe140423SStephen Neuendorffer * tree of struct device_node. It also fills the "name" and "type" 291fe140423SStephen Neuendorffer * pointers of the nodes so the normal device-tree walking functions 292fe140423SStephen Neuendorffer * can be used. 293fe140423SStephen Neuendorffer * @blob: The blob to expand 294fe140423SStephen Neuendorffer * @mynodes: The device_node tree created by the call 295fe140423SStephen Neuendorffer * @dt_alloc: An allocator that provides a virtual address to memory 296fe140423SStephen Neuendorffer * for the resulting tree 297fe140423SStephen Neuendorffer */ 298a7006c97SAndres Salomon static void __unflatten_device_tree(struct boot_param_header *blob, 299fe140423SStephen Neuendorffer struct device_node **mynodes, 300fe140423SStephen Neuendorffer void * (*dt_alloc)(u64 size, u64 align)) 301fe140423SStephen Neuendorffer { 30244856819SGrant Likely unsigned long size; 303e6a6928cSRob Herring int start; 304e6a6928cSRob Herring void *mem; 305fe140423SStephen Neuendorffer struct device_node **allnextp = mynodes; 306fe140423SStephen Neuendorffer 307fe140423SStephen Neuendorffer pr_debug(" -> unflatten_device_tree()\n"); 308fe140423SStephen Neuendorffer 309fe140423SStephen Neuendorffer if (!blob) { 310fe140423SStephen Neuendorffer pr_debug("No device tree pointer\n"); 311fe140423SStephen Neuendorffer return; 312fe140423SStephen Neuendorffer } 313fe140423SStephen Neuendorffer 314fe140423SStephen Neuendorffer pr_debug("Unflattening device tree:\n"); 315fe140423SStephen Neuendorffer pr_debug("magic: %08x\n", be32_to_cpu(blob->magic)); 316fe140423SStephen Neuendorffer pr_debug("size: %08x\n", be32_to_cpu(blob->totalsize)); 317fe140423SStephen Neuendorffer pr_debug("version: %08x\n", be32_to_cpu(blob->version)); 318fe140423SStephen Neuendorffer 319fe140423SStephen Neuendorffer if (be32_to_cpu(blob->magic) != OF_DT_HEADER) { 320fe140423SStephen Neuendorffer pr_err("Invalid device tree blob header\n"); 321fe140423SStephen Neuendorffer return; 322fe140423SStephen Neuendorffer } 323fe140423SStephen Neuendorffer 324fe140423SStephen Neuendorffer /* First pass, scan for size */ 325e6a6928cSRob Herring start = 0; 32644856819SGrant Likely size = (unsigned long)unflatten_dt_node(blob, 0, &start, NULL, NULL, 0); 32744856819SGrant Likely size = ALIGN(size, 4); 328fe140423SStephen Neuendorffer 329fe140423SStephen Neuendorffer pr_debug(" size is %lx, allocating...\n", size); 330fe140423SStephen Neuendorffer 331fe140423SStephen Neuendorffer /* Allocate memory for the expanded device tree */ 33244856819SGrant Likely mem = dt_alloc(size + 4, __alignof__(struct device_node)); 33344856819SGrant Likely memset(mem, 0, size); 334fe140423SStephen Neuendorffer 33544856819SGrant Likely *(__be32 *)(mem + size) = cpu_to_be32(0xdeadbeef); 3369e401275SWladislav Wiebe 33744856819SGrant Likely pr_debug(" unflattening %p...\n", mem); 338fe140423SStephen Neuendorffer 339fe140423SStephen Neuendorffer /* Second pass, do actual unflattening */ 340e6a6928cSRob Herring start = 0; 341fe140423SStephen Neuendorffer unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0); 34244856819SGrant Likely if (be32_to_cpup(mem + size) != 0xdeadbeef) 343fe140423SStephen Neuendorffer pr_warning("End of tree marker overwritten: %08x\n", 34444856819SGrant Likely be32_to_cpup(mem + size)); 345fe140423SStephen Neuendorffer *allnextp = NULL; 346fe140423SStephen Neuendorffer 347fe140423SStephen Neuendorffer pr_debug(" <- unflatten_device_tree()\n"); 348fe140423SStephen Neuendorffer } 349fe140423SStephen Neuendorffer 350fe140423SStephen Neuendorffer static void *kernel_tree_alloc(u64 size, u64 align) 351fe140423SStephen Neuendorffer { 352fe140423SStephen Neuendorffer return kzalloc(size, GFP_KERNEL); 353fe140423SStephen Neuendorffer } 354fe140423SStephen Neuendorffer 355fe140423SStephen Neuendorffer /** 356fe140423SStephen Neuendorffer * of_fdt_unflatten_tree - create tree of device_nodes from flat blob 357fe140423SStephen Neuendorffer * 358fe140423SStephen Neuendorffer * unflattens the device-tree passed by the firmware, creating the 359fe140423SStephen Neuendorffer * tree of struct device_node. It also fills the "name" and "type" 360fe140423SStephen Neuendorffer * pointers of the nodes so the normal device-tree walking functions 361fe140423SStephen Neuendorffer * can be used. 362fe140423SStephen Neuendorffer */ 363fe140423SStephen Neuendorffer void of_fdt_unflatten_tree(unsigned long *blob, 364fe140423SStephen Neuendorffer struct device_node **mynodes) 365fe140423SStephen Neuendorffer { 366fe140423SStephen Neuendorffer struct boot_param_header *device_tree = 367fe140423SStephen Neuendorffer (struct boot_param_header *)blob; 368fe140423SStephen Neuendorffer __unflatten_device_tree(device_tree, mynodes, &kernel_tree_alloc); 369fe140423SStephen Neuendorffer } 370fe140423SStephen Neuendorffer EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree); 371fe140423SStephen Neuendorffer 37257d00ecfSStephen Neuendorffer /* Everything below here references initial_boot_params directly. */ 37357d00ecfSStephen Neuendorffer int __initdata dt_root_addr_cells; 37457d00ecfSStephen Neuendorffer int __initdata dt_root_size_cells; 37557d00ecfSStephen Neuendorffer 37657d00ecfSStephen Neuendorffer struct boot_param_header *initial_boot_params; 37757d00ecfSStephen Neuendorffer 37857d00ecfSStephen Neuendorffer #ifdef CONFIG_OF_EARLY_FLATTREE 37957d00ecfSStephen Neuendorffer 38057d00ecfSStephen Neuendorffer /** 381e8d9d1f5SMarek Szyprowski * res_mem_reserve_reg() - reserve all memory described in 'reg' property 382e8d9d1f5SMarek Szyprowski */ 383e8d9d1f5SMarek Szyprowski static int __init __reserved_mem_reserve_reg(unsigned long node, 384e8d9d1f5SMarek Szyprowski const char *uname) 385e8d9d1f5SMarek Szyprowski { 386e8d9d1f5SMarek Szyprowski int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32); 387e8d9d1f5SMarek Szyprowski phys_addr_t base, size; 3889d0c4dfeSRob Herring int len; 3899d0c4dfeSRob Herring const __be32 *prop; 3903f0c8206SMarek Szyprowski int nomap, first = 1; 391e8d9d1f5SMarek Szyprowski 392e8d9d1f5SMarek Szyprowski prop = of_get_flat_dt_prop(node, "reg", &len); 393e8d9d1f5SMarek Szyprowski if (!prop) 394e8d9d1f5SMarek Szyprowski return -ENOENT; 395e8d9d1f5SMarek Szyprowski 396e8d9d1f5SMarek Szyprowski if (len && len % t_len != 0) { 397e8d9d1f5SMarek Szyprowski pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n", 398e8d9d1f5SMarek Szyprowski uname); 399e8d9d1f5SMarek Szyprowski return -EINVAL; 400e8d9d1f5SMarek Szyprowski } 401e8d9d1f5SMarek Szyprowski 402e8d9d1f5SMarek Szyprowski nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL; 403e8d9d1f5SMarek Szyprowski 404e8d9d1f5SMarek Szyprowski while (len >= t_len) { 405e8d9d1f5SMarek Szyprowski base = dt_mem_next_cell(dt_root_addr_cells, &prop); 406e8d9d1f5SMarek Szyprowski size = dt_mem_next_cell(dt_root_size_cells, &prop); 407e8d9d1f5SMarek Szyprowski 408e8d9d1f5SMarek Szyprowski if (base && size && 409e8d9d1f5SMarek Szyprowski early_init_dt_reserve_memory_arch(base, size, nomap) == 0) 410e8d9d1f5SMarek Szyprowski pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %ld MiB\n", 411e8d9d1f5SMarek Szyprowski uname, &base, (unsigned long)size / SZ_1M); 412e8d9d1f5SMarek Szyprowski else 413e8d9d1f5SMarek Szyprowski pr_info("Reserved memory: failed to reserve memory for node '%s': base %pa, size %ld MiB\n", 414e8d9d1f5SMarek Szyprowski uname, &base, (unsigned long)size / SZ_1M); 415e8d9d1f5SMarek Szyprowski 416e8d9d1f5SMarek Szyprowski len -= t_len; 4173f0c8206SMarek Szyprowski if (first) { 4183f0c8206SMarek Szyprowski fdt_reserved_mem_save_node(node, uname, base, size); 4193f0c8206SMarek Szyprowski first = 0; 4203f0c8206SMarek Szyprowski } 421e8d9d1f5SMarek Szyprowski } 422e8d9d1f5SMarek Szyprowski return 0; 423e8d9d1f5SMarek Szyprowski } 424e8d9d1f5SMarek Szyprowski 425e8d9d1f5SMarek Szyprowski /** 426e8d9d1f5SMarek Szyprowski * __reserved_mem_check_root() - check if #size-cells, #address-cells provided 427e8d9d1f5SMarek Szyprowski * in /reserved-memory matches the values supported by the current implementation, 428e8d9d1f5SMarek Szyprowski * also check if ranges property has been provided 429e8d9d1f5SMarek Szyprowski */ 4305b624118SXiubo Li static int __init __reserved_mem_check_root(unsigned long node) 431e8d9d1f5SMarek Szyprowski { 4329d0c4dfeSRob Herring const __be32 *prop; 433e8d9d1f5SMarek Szyprowski 434e8d9d1f5SMarek Szyprowski prop = of_get_flat_dt_prop(node, "#size-cells", NULL); 435e8d9d1f5SMarek Szyprowski if (!prop || be32_to_cpup(prop) != dt_root_size_cells) 436e8d9d1f5SMarek Szyprowski return -EINVAL; 437e8d9d1f5SMarek Szyprowski 438e8d9d1f5SMarek Szyprowski prop = of_get_flat_dt_prop(node, "#address-cells", NULL); 439e8d9d1f5SMarek Szyprowski if (!prop || be32_to_cpup(prop) != dt_root_addr_cells) 440e8d9d1f5SMarek Szyprowski return -EINVAL; 441e8d9d1f5SMarek Szyprowski 442e8d9d1f5SMarek Szyprowski prop = of_get_flat_dt_prop(node, "ranges", NULL); 443e8d9d1f5SMarek Szyprowski if (!prop) 444e8d9d1f5SMarek Szyprowski return -EINVAL; 445e8d9d1f5SMarek Szyprowski return 0; 446e8d9d1f5SMarek Szyprowski } 447e8d9d1f5SMarek Szyprowski 448e8d9d1f5SMarek Szyprowski /** 449e8d9d1f5SMarek Szyprowski * fdt_scan_reserved_mem() - scan a single FDT node for reserved memory 450e8d9d1f5SMarek Szyprowski */ 451e8d9d1f5SMarek Szyprowski static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname, 452e8d9d1f5SMarek Szyprowski int depth, void *data) 453e8d9d1f5SMarek Szyprowski { 454e8d9d1f5SMarek Szyprowski static int found; 455e8d9d1f5SMarek Szyprowski const char *status; 4563f0c8206SMarek Szyprowski int err; 457e8d9d1f5SMarek Szyprowski 458e8d9d1f5SMarek Szyprowski if (!found && depth == 1 && strcmp(uname, "reserved-memory") == 0) { 459e8d9d1f5SMarek Szyprowski if (__reserved_mem_check_root(node) != 0) { 460e8d9d1f5SMarek Szyprowski pr_err("Reserved memory: unsupported node format, ignoring\n"); 461e8d9d1f5SMarek Szyprowski /* break scan */ 462e8d9d1f5SMarek Szyprowski return 1; 463e8d9d1f5SMarek Szyprowski } 464e8d9d1f5SMarek Szyprowski found = 1; 465e8d9d1f5SMarek Szyprowski /* scan next node */ 466e8d9d1f5SMarek Szyprowski return 0; 467e8d9d1f5SMarek Szyprowski } else if (!found) { 468e8d9d1f5SMarek Szyprowski /* scan next node */ 469e8d9d1f5SMarek Szyprowski return 0; 470e8d9d1f5SMarek Szyprowski } else if (found && depth < 2) { 471e8d9d1f5SMarek Szyprowski /* scanning of /reserved-memory has been finished */ 472e8d9d1f5SMarek Szyprowski return 1; 473e8d9d1f5SMarek Szyprowski } 474e8d9d1f5SMarek Szyprowski 475e8d9d1f5SMarek Szyprowski status = of_get_flat_dt_prop(node, "status", NULL); 476e8d9d1f5SMarek Szyprowski if (status && strcmp(status, "okay") != 0 && strcmp(status, "ok") != 0) 477e8d9d1f5SMarek Szyprowski return 0; 478e8d9d1f5SMarek Szyprowski 4793f0c8206SMarek Szyprowski err = __reserved_mem_reserve_reg(node, uname); 4803f0c8206SMarek Szyprowski if (err == -ENOENT && of_get_flat_dt_prop(node, "size", NULL)) 4813f0c8206SMarek Szyprowski fdt_reserved_mem_save_node(node, uname, 0, 0); 482e8d9d1f5SMarek Szyprowski 483e8d9d1f5SMarek Szyprowski /* scan next node */ 484e8d9d1f5SMarek Szyprowski return 0; 485e8d9d1f5SMarek Szyprowski } 486e8d9d1f5SMarek Szyprowski 487e8d9d1f5SMarek Szyprowski /** 488e8d9d1f5SMarek Szyprowski * early_init_fdt_scan_reserved_mem() - create reserved memory regions 489e8d9d1f5SMarek Szyprowski * 490e8d9d1f5SMarek Szyprowski * This function grabs memory from early allocator for device exclusive use 491e8d9d1f5SMarek Szyprowski * defined in device tree structures. It should be called by arch specific code 492e8d9d1f5SMarek Szyprowski * once the early allocator (i.e. memblock) has been fully activated. 493e8d9d1f5SMarek Szyprowski */ 494e8d9d1f5SMarek Szyprowski void __init early_init_fdt_scan_reserved_mem(void) 495e8d9d1f5SMarek Szyprowski { 4962040b527SJosh Cartwright if (!initial_boot_params) 4972040b527SJosh Cartwright return; 4982040b527SJosh Cartwright 499e8d9d1f5SMarek Szyprowski of_scan_flat_dt(__fdt_scan_reserved_mem, NULL); 5003f0c8206SMarek Szyprowski fdt_init_reserved_mem(); 501e8d9d1f5SMarek Szyprowski } 502e8d9d1f5SMarek Szyprowski 503e8d9d1f5SMarek Szyprowski /** 50457d00ecfSStephen Neuendorffer * of_scan_flat_dt - scan flattened tree blob and call callback on each. 50557d00ecfSStephen Neuendorffer * @it: callback function 50657d00ecfSStephen Neuendorffer * @data: context data pointer 50757d00ecfSStephen Neuendorffer * 50857d00ecfSStephen Neuendorffer * This function is used to scan the flattened device-tree, it is 50957d00ecfSStephen Neuendorffer * used to extract the memory information at boot before we can 51057d00ecfSStephen Neuendorffer * unflatten the tree 51157d00ecfSStephen Neuendorffer */ 51257d00ecfSStephen Neuendorffer int __init of_scan_flat_dt(int (*it)(unsigned long node, 51357d00ecfSStephen Neuendorffer const char *uname, int depth, 51457d00ecfSStephen Neuendorffer void *data), 51557d00ecfSStephen Neuendorffer void *data) 51657d00ecfSStephen Neuendorffer { 517e6a6928cSRob Herring const void *blob = initial_boot_params; 518e55b0829SFabio Estevam const char *pathp; 519e6a6928cSRob Herring int offset, rc = 0, depth = -1; 52057d00ecfSStephen Neuendorffer 521e6a6928cSRob Herring for (offset = fdt_next_node(blob, -1, &depth); 522e6a6928cSRob Herring offset >= 0 && depth >= 0 && !rc; 523e6a6928cSRob Herring offset = fdt_next_node(blob, offset, &depth)) { 524e6a6928cSRob Herring 525e6a6928cSRob Herring pathp = fdt_get_name(blob, offset, NULL); 526375da3a7SAndy Shevchenko if (*pathp == '/') 527375da3a7SAndy Shevchenko pathp = kbasename(pathp); 528e6a6928cSRob Herring rc = it(offset, pathp, depth, data); 529e6a6928cSRob Herring } 53057d00ecfSStephen Neuendorffer return rc; 53157d00ecfSStephen Neuendorffer } 53257d00ecfSStephen Neuendorffer 53357d00ecfSStephen Neuendorffer /** 53457d00ecfSStephen Neuendorffer * of_get_flat_dt_root - find the root node in the flat blob 53557d00ecfSStephen Neuendorffer */ 53657d00ecfSStephen Neuendorffer unsigned long __init of_get_flat_dt_root(void) 53757d00ecfSStephen Neuendorffer { 538e6a6928cSRob Herring return 0; 53957d00ecfSStephen Neuendorffer } 54057d00ecfSStephen Neuendorffer 54157d00ecfSStephen Neuendorffer /** 54257d00ecfSStephen Neuendorffer * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr 54357d00ecfSStephen Neuendorffer * 54457d00ecfSStephen Neuendorffer * This function can be used within scan_flattened_dt callback to get 54557d00ecfSStephen Neuendorffer * access to properties 54657d00ecfSStephen Neuendorffer */ 5479d0c4dfeSRob Herring const void *__init of_get_flat_dt_prop(unsigned long node, const char *name, 5489d0c4dfeSRob Herring int *size) 54957d00ecfSStephen Neuendorffer { 550e6a6928cSRob Herring return fdt_getprop(initial_boot_params, node, name, size); 55157d00ecfSStephen Neuendorffer } 55257d00ecfSStephen Neuendorffer 55357d00ecfSStephen Neuendorffer /** 55457d00ecfSStephen Neuendorffer * of_flat_dt_is_compatible - Return true if given node has compat in compatible list 55557d00ecfSStephen Neuendorffer * @node: node to test 55657d00ecfSStephen Neuendorffer * @compat: compatible string to compare with compatible list. 55757d00ecfSStephen Neuendorffer */ 55857d00ecfSStephen Neuendorffer int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) 55957d00ecfSStephen Neuendorffer { 56057d00ecfSStephen Neuendorffer return of_fdt_is_compatible(initial_boot_params, node, compat); 56157d00ecfSStephen Neuendorffer } 56257d00ecfSStephen Neuendorffer 563a4f740cfSGrant Likely /** 564a4f740cfSGrant Likely * of_flat_dt_match - Return true if node matches a list of compatible values 565a4f740cfSGrant Likely */ 5667b482c83SUwe Kleine-König int __init of_flat_dt_match(unsigned long node, const char *const *compat) 567a4f740cfSGrant Likely { 568a4f740cfSGrant Likely return of_fdt_match(initial_boot_params, node, compat); 569a4f740cfSGrant Likely } 570a4f740cfSGrant Likely 57157d74bcfSMarek Szyprowski struct fdt_scan_status { 57257d74bcfSMarek Szyprowski const char *name; 57357d74bcfSMarek Szyprowski int namelen; 57457d74bcfSMarek Szyprowski int depth; 57557d74bcfSMarek Szyprowski int found; 57657d74bcfSMarek Szyprowski int (*iterator)(unsigned long node, const char *uname, int depth, void *data); 57757d74bcfSMarek Szyprowski void *data; 57857d74bcfSMarek Szyprowski }; 57957d74bcfSMarek Szyprowski 5806a903a25SRob Herring const char * __init of_flat_dt_get_machine_name(void) 5816a903a25SRob Herring { 5826a903a25SRob Herring const char *name; 5836a903a25SRob Herring unsigned long dt_root = of_get_flat_dt_root(); 5846a903a25SRob Herring 5856a903a25SRob Herring name = of_get_flat_dt_prop(dt_root, "model", NULL); 5866a903a25SRob Herring if (!name) 5876a903a25SRob Herring name = of_get_flat_dt_prop(dt_root, "compatible", NULL); 5886a903a25SRob Herring return name; 5896a903a25SRob Herring } 5906a903a25SRob Herring 5916a903a25SRob Herring /** 5926a903a25SRob Herring * of_flat_dt_match_machine - Iterate match tables to find matching machine. 5936a903a25SRob Herring * 5946a903a25SRob Herring * @default_match: A machine specific ptr to return in case of no match. 5956a903a25SRob Herring * @get_next_compat: callback function to return next compatible match table. 5966a903a25SRob Herring * 5976a903a25SRob Herring * Iterate through machine match tables to find the best match for the machine 5986a903a25SRob Herring * compatible string in the FDT. 5996a903a25SRob Herring */ 6006a903a25SRob Herring const void * __init of_flat_dt_match_machine(const void *default_match, 6016a903a25SRob Herring const void * (*get_next_compat)(const char * const**)) 6026a903a25SRob Herring { 6036a903a25SRob Herring const void *data = NULL; 6046a903a25SRob Herring const void *best_data = default_match; 6056a903a25SRob Herring const char *const *compat; 6066a903a25SRob Herring unsigned long dt_root; 6076a903a25SRob Herring unsigned int best_score = ~1, score = 0; 6086a903a25SRob Herring 6096a903a25SRob Herring dt_root = of_get_flat_dt_root(); 6106a903a25SRob Herring while ((data = get_next_compat(&compat))) { 6116a903a25SRob Herring score = of_flat_dt_match(dt_root, compat); 6126a903a25SRob Herring if (score > 0 && score < best_score) { 6136a903a25SRob Herring best_data = data; 6146a903a25SRob Herring best_score = score; 6156a903a25SRob Herring } 6166a903a25SRob Herring } 6176a903a25SRob Herring if (!best_data) { 6186a903a25SRob Herring const char *prop; 6199d0c4dfeSRob Herring int size; 6206a903a25SRob Herring 6216a903a25SRob Herring pr_err("\n unrecognized device tree list:\n[ "); 6226a903a25SRob Herring 6236a903a25SRob Herring prop = of_get_flat_dt_prop(dt_root, "compatible", &size); 6246a903a25SRob Herring if (prop) { 6256a903a25SRob Herring while (size > 0) { 6266a903a25SRob Herring printk("'%s' ", prop); 6276a903a25SRob Herring size -= strlen(prop) + 1; 6286a903a25SRob Herring prop += strlen(prop) + 1; 6296a903a25SRob Herring } 6306a903a25SRob Herring } 6316a903a25SRob Herring printk("]\n\n"); 6326a903a25SRob Herring return NULL; 6336a903a25SRob Herring } 6346a903a25SRob Herring 6356a903a25SRob Herring pr_info("Machine model: %s\n", of_flat_dt_get_machine_name()); 6366a903a25SRob Herring 6376a903a25SRob Herring return best_data; 6386a903a25SRob Herring } 6396a903a25SRob Herring 640f7b3a835SGrant Likely #ifdef CONFIG_BLK_DEV_INITRD 641f7b3a835SGrant Likely /** 642f7b3a835SGrant Likely * early_init_dt_check_for_initrd - Decode initrd location from flat tree 643f7b3a835SGrant Likely * @node: reference to node containing initrd location ('chosen') 644f7b3a835SGrant Likely */ 64529eb45a9SRob Herring static void __init early_init_dt_check_for_initrd(unsigned long node) 646f7b3a835SGrant Likely { 647374d5c99SSantosh Shilimkar u64 start, end; 6489d0c4dfeSRob Herring int len; 6499d0c4dfeSRob Herring const __be32 *prop; 650f7b3a835SGrant Likely 651f7b3a835SGrant Likely pr_debug("Looking for initrd properties... "); 652f7b3a835SGrant Likely 653f7b3a835SGrant Likely prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len); 6541406bc2fSJeremy Kerr if (!prop) 6551406bc2fSJeremy Kerr return; 656374d5c99SSantosh Shilimkar start = of_read_number(prop, len/4); 657f7b3a835SGrant Likely 658f7b3a835SGrant Likely prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len); 6591406bc2fSJeremy Kerr if (!prop) 6601406bc2fSJeremy Kerr return; 661374d5c99SSantosh Shilimkar end = of_read_number(prop, len/4); 662f7b3a835SGrant Likely 66329eb45a9SRob Herring initrd_start = (unsigned long)__va(start); 66429eb45a9SRob Herring initrd_end = (unsigned long)__va(end); 66529eb45a9SRob Herring initrd_below_start_ok = 1; 66629eb45a9SRob Herring 667374d5c99SSantosh Shilimkar pr_debug("initrd_start=0x%llx initrd_end=0x%llx\n", 668374d5c99SSantosh Shilimkar (unsigned long long)start, (unsigned long long)end); 669f7b3a835SGrant Likely } 670f7b3a835SGrant Likely #else 67129eb45a9SRob Herring static inline void early_init_dt_check_for_initrd(unsigned long node) 672f7b3a835SGrant Likely { 673f7b3a835SGrant Likely } 674f7b3a835SGrant Likely #endif /* CONFIG_BLK_DEV_INITRD */ 675f7b3a835SGrant Likely 67641f88009SGrant Likely /** 677f00abd94SGrant Likely * early_init_dt_scan_root - fetch the top level address and size cells 678f00abd94SGrant Likely */ 679f00abd94SGrant Likely int __init early_init_dt_scan_root(unsigned long node, const char *uname, 680f00abd94SGrant Likely int depth, void *data) 681f00abd94SGrant Likely { 6829d0c4dfeSRob Herring const __be32 *prop; 683f00abd94SGrant Likely 684f00abd94SGrant Likely if (depth != 0) 685f00abd94SGrant Likely return 0; 686f00abd94SGrant Likely 68733714881SJeremy Kerr dt_root_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT; 68833714881SJeremy Kerr dt_root_addr_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT; 68933714881SJeremy Kerr 690f00abd94SGrant Likely prop = of_get_flat_dt_prop(node, "#size-cells", NULL); 69133714881SJeremy Kerr if (prop) 69233714881SJeremy Kerr dt_root_size_cells = be32_to_cpup(prop); 693f00abd94SGrant Likely pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells); 694f00abd94SGrant Likely 695f00abd94SGrant Likely prop = of_get_flat_dt_prop(node, "#address-cells", NULL); 69633714881SJeremy Kerr if (prop) 69733714881SJeremy Kerr dt_root_addr_cells = be32_to_cpup(prop); 698f00abd94SGrant Likely pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells); 699f00abd94SGrant Likely 700f00abd94SGrant Likely /* break now */ 701f00abd94SGrant Likely return 1; 702f00abd94SGrant Likely } 703f00abd94SGrant Likely 7049d0c4dfeSRob Herring u64 __init dt_mem_next_cell(int s, const __be32 **cellp) 70583f7a06eSGrant Likely { 7069d0c4dfeSRob Herring const __be32 *p = *cellp; 70783f7a06eSGrant Likely 70883f7a06eSGrant Likely *cellp = p + s; 70983f7a06eSGrant Likely return of_read_number(p, s); 71083f7a06eSGrant Likely } 71183f7a06eSGrant Likely 71251975db0SGrant Likely /** 71351975db0SGrant Likely * early_init_dt_scan_memory - Look for an parse memory nodes 71451975db0SGrant Likely */ 71551975db0SGrant Likely int __init early_init_dt_scan_memory(unsigned long node, const char *uname, 71651975db0SGrant Likely int depth, void *data) 71751975db0SGrant Likely { 7189d0c4dfeSRob Herring const char *type = of_get_flat_dt_prop(node, "device_type", NULL); 7199d0c4dfeSRob Herring const __be32 *reg, *endp; 7209d0c4dfeSRob Herring int l; 72151975db0SGrant Likely 72251975db0SGrant Likely /* We are scanning "memory" nodes only */ 72351975db0SGrant Likely if (type == NULL) { 72451975db0SGrant Likely /* 72551975db0SGrant Likely * The longtrail doesn't have a device_type on the 72651975db0SGrant Likely * /memory node, so look for the node called /memory@0. 72751975db0SGrant Likely */ 72851975db0SGrant Likely if (depth != 1 || strcmp(uname, "memory@0") != 0) 72951975db0SGrant Likely return 0; 73051975db0SGrant Likely } else if (strcmp(type, "memory") != 0) 73151975db0SGrant Likely return 0; 73251975db0SGrant Likely 73351975db0SGrant Likely reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l); 73451975db0SGrant Likely if (reg == NULL) 73551975db0SGrant Likely reg = of_get_flat_dt_prop(node, "reg", &l); 73651975db0SGrant Likely if (reg == NULL) 73751975db0SGrant Likely return 0; 73851975db0SGrant Likely 73951975db0SGrant Likely endp = reg + (l / sizeof(__be32)); 74051975db0SGrant Likely 7419d0c4dfeSRob Herring pr_debug("memory scan node %s, reg size %d, data: %x %x %x %x,\n", 74251975db0SGrant Likely uname, l, reg[0], reg[1], reg[2], reg[3]); 74351975db0SGrant Likely 74451975db0SGrant Likely while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { 74551975db0SGrant Likely u64 base, size; 74651975db0SGrant Likely 74751975db0SGrant Likely base = dt_mem_next_cell(dt_root_addr_cells, ®); 74851975db0SGrant Likely size = dt_mem_next_cell(dt_root_size_cells, ®); 74951975db0SGrant Likely 75051975db0SGrant Likely if (size == 0) 75151975db0SGrant Likely continue; 75251975db0SGrant Likely pr_debug(" - %llx , %llx\n", (unsigned long long)base, 75351975db0SGrant Likely (unsigned long long)size); 75451975db0SGrant Likely 75551975db0SGrant Likely early_init_dt_add_memory_arch(base, size); 75651975db0SGrant Likely } 75751975db0SGrant Likely 75851975db0SGrant Likely return 0; 75951975db0SGrant Likely } 76051975db0SGrant Likely 76186e03221SGrant Likely int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, 76286e03221SGrant Likely int depth, void *data) 76386e03221SGrant Likely { 7649d0c4dfeSRob Herring int l; 7659d0c4dfeSRob Herring const char *p; 76686e03221SGrant Likely 76786e03221SGrant Likely pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname); 76886e03221SGrant Likely 76985f60ae4SGrant Likely if (depth != 1 || !data || 77086e03221SGrant Likely (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0)) 77186e03221SGrant Likely return 0; 77286e03221SGrant Likely 77386e03221SGrant Likely early_init_dt_check_for_initrd(node); 77486e03221SGrant Likely 77525985edcSLucas De Marchi /* Retrieve command line */ 77686e03221SGrant Likely p = of_get_flat_dt_prop(node, "bootargs", &l); 77786e03221SGrant Likely if (p != NULL && l > 0) 77885f60ae4SGrant Likely strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE)); 77986e03221SGrant Likely 78078b782cbSBenjamin Herrenschmidt /* 78178b782cbSBenjamin Herrenschmidt * CONFIG_CMDLINE is meant to be a default in case nothing else 78278b782cbSBenjamin Herrenschmidt * managed to set the command line, unless CONFIG_CMDLINE_FORCE 78378b782cbSBenjamin Herrenschmidt * is set in which case we override whatever was found earlier. 78478b782cbSBenjamin Herrenschmidt */ 78586e03221SGrant Likely #ifdef CONFIG_CMDLINE 78686e03221SGrant Likely #ifndef CONFIG_CMDLINE_FORCE 78778b782cbSBenjamin Herrenschmidt if (!((char *)data)[0]) 78886e03221SGrant Likely #endif 78985f60ae4SGrant Likely strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE); 79086e03221SGrant Likely #endif /* CONFIG_CMDLINE */ 79186e03221SGrant Likely 79285f60ae4SGrant Likely pr_debug("Command line is: %s\n", (char*)data); 79386e03221SGrant Likely 79486e03221SGrant Likely /* break now */ 79586e03221SGrant Likely return 1; 79686e03221SGrant Likely } 79786e03221SGrant Likely 798a1727da5SGrant Likely #ifdef CONFIG_HAVE_MEMBLOCK 799068f6310SRob Herring void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size) 800068f6310SRob Herring { 801068f6310SRob Herring const u64 phys_offset = __pa(PAGE_OFFSET); 802068f6310SRob Herring base &= PAGE_MASK; 803068f6310SRob Herring size &= PAGE_MASK; 804068f6310SRob Herring if (base + size < phys_offset) { 805068f6310SRob Herring pr_warning("Ignoring memory block 0x%llx - 0x%llx\n", 806068f6310SRob Herring base, base + size); 807068f6310SRob Herring return; 808068f6310SRob Herring } 809068f6310SRob Herring if (base < phys_offset) { 810068f6310SRob Herring pr_warning("Ignoring memory range 0x%llx - 0x%llx\n", 811068f6310SRob Herring base, phys_offset); 812068f6310SRob Herring size -= phys_offset - base; 813068f6310SRob Herring base = phys_offset; 814068f6310SRob Herring } 815068f6310SRob Herring memblock_add(base, size); 816068f6310SRob Herring } 817068f6310SRob Herring 818e8d9d1f5SMarek Szyprowski int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base, 819e8d9d1f5SMarek Szyprowski phys_addr_t size, bool nomap) 820e8d9d1f5SMarek Szyprowski { 821e8d9d1f5SMarek Szyprowski if (memblock_is_region_reserved(base, size)) 822e8d9d1f5SMarek Szyprowski return -EBUSY; 823e8d9d1f5SMarek Szyprowski if (nomap) 824e8d9d1f5SMarek Szyprowski return memblock_remove(base, size); 825e8d9d1f5SMarek Szyprowski return memblock_reserve(base, size); 826e8d9d1f5SMarek Szyprowski } 827e8d9d1f5SMarek Szyprowski 828a1727da5SGrant Likely /* 829a1727da5SGrant Likely * called from unflatten_device_tree() to bootstrap devicetree itself 830a1727da5SGrant Likely * Architectures can override this definition if memblock isn't used 831a1727da5SGrant Likely */ 832a1727da5SGrant Likely void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align) 833a1727da5SGrant Likely { 834a1727da5SGrant Likely return __va(memblock_alloc(size, align)); 835a1727da5SGrant Likely } 836e8d9d1f5SMarek Szyprowski #else 837e8d9d1f5SMarek Szyprowski int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base, 838e8d9d1f5SMarek Szyprowski phys_addr_t size, bool nomap) 839e8d9d1f5SMarek Szyprowski { 840e8d9d1f5SMarek Szyprowski pr_err("Reserved memory not supported, ignoring range 0x%llx - 0x%llx%s\n", 841e8d9d1f5SMarek Szyprowski base, size, nomap ? " (nomap)" : ""); 842e8d9d1f5SMarek Szyprowski return -ENOSYS; 843e8d9d1f5SMarek Szyprowski } 844a1727da5SGrant Likely #endif 845a1727da5SGrant Likely 8460288ffcbSRob Herring bool __init early_init_dt_scan(void *params) 8470288ffcbSRob Herring { 8480288ffcbSRob Herring if (!params) 8490288ffcbSRob Herring return false; 8500288ffcbSRob Herring 8510288ffcbSRob Herring /* Setup flat device-tree pointer */ 8520288ffcbSRob Herring initial_boot_params = params; 8530288ffcbSRob Herring 8540288ffcbSRob Herring /* check device tree validity */ 8550288ffcbSRob Herring if (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) { 8560288ffcbSRob Herring initial_boot_params = NULL; 8570288ffcbSRob Herring return false; 8580288ffcbSRob Herring } 8590288ffcbSRob Herring 8600288ffcbSRob Herring /* Retrieve various information from the /chosen node */ 8610288ffcbSRob Herring of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); 8620288ffcbSRob Herring 8630288ffcbSRob Herring /* Initialize {size,address}-cells info */ 8640288ffcbSRob Herring of_scan_flat_dt(early_init_dt_scan_root, NULL); 8650288ffcbSRob Herring 8660288ffcbSRob Herring /* Setup memory, calling early_init_dt_add_memory_arch */ 8670288ffcbSRob Herring of_scan_flat_dt(early_init_dt_scan_memory, NULL); 8680288ffcbSRob Herring 8690288ffcbSRob Herring return true; 8700288ffcbSRob Herring } 8710288ffcbSRob Herring 872f00abd94SGrant Likely /** 87341f88009SGrant Likely * unflatten_device_tree - create tree of device_nodes from flat blob 87441f88009SGrant Likely * 87541f88009SGrant Likely * unflattens the device-tree passed by the firmware, creating the 87641f88009SGrant Likely * tree of struct device_node. It also fills the "name" and "type" 87741f88009SGrant Likely * pointers of the nodes so the normal device-tree walking functions 87841f88009SGrant Likely * can be used. 87941f88009SGrant Likely */ 88041f88009SGrant Likely void __init unflatten_device_tree(void) 88141f88009SGrant Likely { 882465aac6dSRandy Dunlap __unflatten_device_tree(initial_boot_params, &of_allnodes, 883672c5446SGrant Likely early_init_dt_alloc_memory_arch); 88441f88009SGrant Likely 8854c7d6361SRobert P. J. Day /* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */ 886611cad72SShawn Guo of_alias_scan(early_init_dt_alloc_memory_arch); 88741f88009SGrant Likely } 888e6ce1324SStephen Neuendorffer 889a8bf7527SRob Herring /** 890a8bf7527SRob Herring * unflatten_and_copy_device_tree - copy and create tree of device_nodes from flat blob 891a8bf7527SRob Herring * 892a8bf7527SRob Herring * Copies and unflattens the device-tree passed by the firmware, creating the 893a8bf7527SRob Herring * tree of struct device_node. It also fills the "name" and "type" 894a8bf7527SRob Herring * pointers of the nodes so the normal device-tree walking functions 895a8bf7527SRob Herring * can be used. This should only be used when the FDT memory has not been 896a8bf7527SRob Herring * reserved such is the case when the FDT is built-in to the kernel init 897a8bf7527SRob Herring * section. If the FDT memory is reserved already then unflatten_device_tree 898a8bf7527SRob Herring * should be used instead. 899a8bf7527SRob Herring */ 900a8bf7527SRob Herring void __init unflatten_and_copy_device_tree(void) 901a8bf7527SRob Herring { 9026f041e99SJames Hogan int size; 9036f041e99SJames Hogan void *dt; 9046f041e99SJames Hogan 9056f041e99SJames Hogan if (!initial_boot_params) { 9066f041e99SJames Hogan pr_warn("No valid device tree found, continuing without\n"); 9076f041e99SJames Hogan return; 9086f041e99SJames Hogan } 9096f041e99SJames Hogan 9106f041e99SJames Hogan size = __be32_to_cpu(initial_boot_params->totalsize); 9116f041e99SJames Hogan dt = early_init_dt_alloc_memory_arch(size, 912a8bf7527SRob Herring __alignof__(struct boot_param_header)); 913a8bf7527SRob Herring 914a8bf7527SRob Herring if (dt) { 915a8bf7527SRob Herring memcpy(dt, initial_boot_params, size); 916a8bf7527SRob Herring initial_boot_params = dt; 917a8bf7527SRob Herring } 918a8bf7527SRob Herring unflatten_device_tree(); 919a8bf7527SRob Herring } 920a8bf7527SRob Herring 921e6ce1324SStephen Neuendorffer #endif /* CONFIG_OF_EARLY_FLATTREE */ 922