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> 14fe140423SStephen Neuendorffer #include <linux/module.h> 15e169cfbeSGrant Likely #include <linux/of.h> 16e169cfbeSGrant Likely #include <linux/of_fdt.h> 174ef7b373SJeremy Kerr #include <linux/string.h> 184ef7b373SJeremy Kerr #include <linux/errno.h> 19fe140423SStephen Neuendorffer #include <linux/slab.h> 2051975db0SGrant Likely 2186e03221SGrant Likely #ifdef CONFIG_PPC 2286e03221SGrant Likely #include <asm/machdep.h> 2386e03221SGrant Likely #endif /* CONFIG_PPC */ 2486e03221SGrant Likely 254ef7b373SJeremy Kerr #include <asm/page.h> 264ef7b373SJeremy Kerr 279706a36eSStephen Neuendorffer char *of_fdt_get_string(struct boot_param_header *blob, u32 offset) 289706a36eSStephen Neuendorffer { 299706a36eSStephen Neuendorffer return ((char *)blob) + 309706a36eSStephen Neuendorffer be32_to_cpu(blob->off_dt_strings) + offset; 319706a36eSStephen Neuendorffer } 329706a36eSStephen Neuendorffer 339706a36eSStephen Neuendorffer /** 349706a36eSStephen Neuendorffer * of_fdt_get_property - Given a node in the given flat blob, return 359706a36eSStephen Neuendorffer * the property ptr 369706a36eSStephen Neuendorffer */ 379706a36eSStephen Neuendorffer void *of_fdt_get_property(struct boot_param_header *blob, 389706a36eSStephen Neuendorffer unsigned long node, const char *name, 399706a36eSStephen Neuendorffer unsigned long *size) 409706a36eSStephen Neuendorffer { 419706a36eSStephen Neuendorffer unsigned long p = node; 429706a36eSStephen Neuendorffer 439706a36eSStephen Neuendorffer do { 449706a36eSStephen Neuendorffer u32 tag = be32_to_cpup((__be32 *)p); 459706a36eSStephen Neuendorffer u32 sz, noff; 469706a36eSStephen Neuendorffer const char *nstr; 479706a36eSStephen Neuendorffer 489706a36eSStephen Neuendorffer p += 4; 499706a36eSStephen Neuendorffer if (tag == OF_DT_NOP) 509706a36eSStephen Neuendorffer continue; 519706a36eSStephen Neuendorffer if (tag != OF_DT_PROP) 529706a36eSStephen Neuendorffer return NULL; 539706a36eSStephen Neuendorffer 549706a36eSStephen Neuendorffer sz = be32_to_cpup((__be32 *)p); 559706a36eSStephen Neuendorffer noff = be32_to_cpup((__be32 *)(p + 4)); 569706a36eSStephen Neuendorffer p += 8; 579706a36eSStephen Neuendorffer if (be32_to_cpu(blob->version) < 0x10) 589706a36eSStephen Neuendorffer p = ALIGN(p, sz >= 8 ? 8 : 4); 599706a36eSStephen Neuendorffer 609706a36eSStephen Neuendorffer nstr = of_fdt_get_string(blob, noff); 619706a36eSStephen Neuendorffer if (nstr == NULL) { 629706a36eSStephen Neuendorffer pr_warning("Can't find property index name !\n"); 639706a36eSStephen Neuendorffer return NULL; 649706a36eSStephen Neuendorffer } 659706a36eSStephen Neuendorffer if (strcmp(name, nstr) == 0) { 669706a36eSStephen Neuendorffer if (size) 679706a36eSStephen Neuendorffer *size = sz; 689706a36eSStephen Neuendorffer return (void *)p; 699706a36eSStephen Neuendorffer } 709706a36eSStephen Neuendorffer p += sz; 719706a36eSStephen Neuendorffer p = ALIGN(p, 4); 729706a36eSStephen Neuendorffer } while (1); 739706a36eSStephen Neuendorffer } 749706a36eSStephen Neuendorffer 759706a36eSStephen Neuendorffer /** 769706a36eSStephen Neuendorffer * of_fdt_is_compatible - Return true if given node from the given blob has 779706a36eSStephen Neuendorffer * compat in its compatible list 789706a36eSStephen Neuendorffer * @blob: A device tree blob 799706a36eSStephen Neuendorffer * @node: node to test 809706a36eSStephen Neuendorffer * @compat: compatible string to compare with compatible list. 81a4f740cfSGrant Likely * 82a4f740cfSGrant Likely * On match, returns a non-zero value with smaller values returned for more 83a4f740cfSGrant Likely * specific compatible values. 849706a36eSStephen Neuendorffer */ 859706a36eSStephen Neuendorffer int of_fdt_is_compatible(struct boot_param_header *blob, 869706a36eSStephen Neuendorffer unsigned long node, const char *compat) 879706a36eSStephen Neuendorffer { 889706a36eSStephen Neuendorffer const char *cp; 89a4f740cfSGrant Likely unsigned long cplen, l, score = 0; 909706a36eSStephen Neuendorffer 919706a36eSStephen Neuendorffer cp = of_fdt_get_property(blob, node, "compatible", &cplen); 929706a36eSStephen Neuendorffer if (cp == NULL) 939706a36eSStephen Neuendorffer return 0; 949706a36eSStephen Neuendorffer while (cplen > 0) { 95a4f740cfSGrant Likely score++; 969706a36eSStephen Neuendorffer if (of_compat_cmp(cp, compat, strlen(compat)) == 0) 97a4f740cfSGrant Likely return score; 989706a36eSStephen Neuendorffer l = strlen(cp) + 1; 999706a36eSStephen Neuendorffer cp += l; 1009706a36eSStephen Neuendorffer cplen -= l; 1019706a36eSStephen Neuendorffer } 1029706a36eSStephen Neuendorffer 1039706a36eSStephen Neuendorffer return 0; 1049706a36eSStephen Neuendorffer } 1059706a36eSStephen Neuendorffer 106a4f740cfSGrant Likely /** 107a4f740cfSGrant Likely * of_fdt_match - Return true if node matches a list of compatible values 108a4f740cfSGrant Likely */ 109a4f740cfSGrant Likely int of_fdt_match(struct boot_param_header *blob, unsigned long node, 110a4f740cfSGrant Likely const char **compat) 111a4f740cfSGrant Likely { 112a4f740cfSGrant Likely unsigned int tmp, score = 0; 113a4f740cfSGrant Likely 114a4f740cfSGrant Likely if (!compat) 115a4f740cfSGrant Likely return 0; 116a4f740cfSGrant Likely 117a4f740cfSGrant Likely while (*compat) { 118a4f740cfSGrant Likely tmp = of_fdt_is_compatible(blob, node, *compat); 119a4f740cfSGrant Likely if (tmp && (score == 0 || (tmp < score))) 120a4f740cfSGrant Likely score = tmp; 121a4f740cfSGrant Likely compat++; 122a4f740cfSGrant Likely } 123a4f740cfSGrant Likely 124a4f740cfSGrant Likely return score; 125a4f740cfSGrant Likely } 126a4f740cfSGrant Likely 127a40d6c4cSStephen Neuendorffer static void *unflatten_dt_alloc(unsigned long *mem, unsigned long size, 128bbd33931SGrant Likely unsigned long align) 129bbd33931SGrant Likely { 130bbd33931SGrant Likely void *res; 131bbd33931SGrant Likely 132f1d4c3a7SGrant Likely *mem = ALIGN(*mem, align); 133bbd33931SGrant Likely res = (void *)*mem; 134bbd33931SGrant Likely *mem += size; 135bbd33931SGrant Likely 136bbd33931SGrant Likely return res; 137bbd33931SGrant Likely } 138bbd33931SGrant Likely 139bbd33931SGrant Likely /** 140bbd33931SGrant Likely * unflatten_dt_node - Alloc and populate a device_node from the flat tree 141a40d6c4cSStephen Neuendorffer * @blob: The parent device tree blob 142a7006c97SAndres Salomon * @mem: Memory chunk to use for allocating device nodes and properties 143bbd33931SGrant Likely * @p: pointer to node in flat tree 144bbd33931SGrant Likely * @dad: Parent struct device_node 145bbd33931SGrant Likely * @allnextpp: pointer to ->allnext from last allocated device_node 146bbd33931SGrant Likely * @fpsize: Size of the node path up at the current depth. 147bbd33931SGrant Likely */ 148a7006c97SAndres Salomon static unsigned long unflatten_dt_node(struct boot_param_header *blob, 149a40d6c4cSStephen Neuendorffer unsigned long mem, 150bbd33931SGrant Likely unsigned long *p, 151bbd33931SGrant Likely struct device_node *dad, 152bbd33931SGrant Likely struct device_node ***allnextpp, 153bbd33931SGrant Likely unsigned long fpsize) 154bbd33931SGrant Likely { 155bbd33931SGrant Likely struct device_node *np; 156bbd33931SGrant Likely struct property *pp, **prev_pp = NULL; 157bbd33931SGrant Likely char *pathp; 158bbd33931SGrant Likely u32 tag; 159bbd33931SGrant Likely unsigned int l, allocl; 160bbd33931SGrant Likely int has_name = 0; 161bbd33931SGrant Likely int new_format = 0; 162bbd33931SGrant Likely 16333714881SJeremy Kerr tag = be32_to_cpup((__be32 *)(*p)); 164bbd33931SGrant Likely if (tag != OF_DT_BEGIN_NODE) { 165bbd33931SGrant Likely pr_err("Weird tag at start of node: %x\n", tag); 166bbd33931SGrant Likely return mem; 167bbd33931SGrant Likely } 168bbd33931SGrant Likely *p += 4; 169bbd33931SGrant Likely pathp = (char *)*p; 170bbd33931SGrant Likely l = allocl = strlen(pathp) + 1; 171f1d4c3a7SGrant Likely *p = ALIGN(*p + l, 4); 172bbd33931SGrant Likely 173bbd33931SGrant Likely /* version 0x10 has a more compact unit name here instead of the full 174bbd33931SGrant Likely * path. we accumulate the full path size using "fpsize", we'll rebuild 175bbd33931SGrant Likely * it later. We detect this because the first character of the name is 176bbd33931SGrant Likely * not '/'. 177bbd33931SGrant Likely */ 178bbd33931SGrant Likely if ((*pathp) != '/') { 179bbd33931SGrant Likely new_format = 1; 180bbd33931SGrant Likely if (fpsize == 0) { 181bbd33931SGrant Likely /* root node: special case. fpsize accounts for path 182bbd33931SGrant Likely * plus terminating zero. root node only has '/', so 183bbd33931SGrant Likely * fpsize should be 2, but we want to avoid the first 184bbd33931SGrant Likely * level nodes to have two '/' so we use fpsize 1 here 185bbd33931SGrant Likely */ 186bbd33931SGrant Likely fpsize = 1; 187bbd33931SGrant Likely allocl = 2; 188bbd33931SGrant Likely } else { 189bbd33931SGrant Likely /* account for '/' and path size minus terminal 0 190bbd33931SGrant Likely * already in 'l' 191bbd33931SGrant Likely */ 192bbd33931SGrant Likely fpsize += l; 193bbd33931SGrant Likely allocl = fpsize; 194bbd33931SGrant Likely } 195bbd33931SGrant Likely } 196bbd33931SGrant Likely 197bbd33931SGrant Likely np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, 198bbd33931SGrant Likely __alignof__(struct device_node)); 199bbd33931SGrant Likely if (allnextpp) { 200bbd33931SGrant Likely memset(np, 0, sizeof(*np)); 201bbd33931SGrant Likely np->full_name = ((char *)np) + sizeof(struct device_node); 202bbd33931SGrant Likely if (new_format) { 203bbd33931SGrant Likely char *fn = np->full_name; 204bbd33931SGrant Likely /* rebuild full path for new format */ 205bbd33931SGrant Likely if (dad && dad->parent) { 206bbd33931SGrant Likely strcpy(fn, dad->full_name); 207bbd33931SGrant Likely #ifdef DEBUG 208bbd33931SGrant Likely if ((strlen(fn) + l + 1) != allocl) { 209bbd33931SGrant Likely pr_debug("%s: p: %d, l: %d, a: %d\n", 210bbd33931SGrant Likely pathp, (int)strlen(fn), 211bbd33931SGrant Likely l, allocl); 212bbd33931SGrant Likely } 213bbd33931SGrant Likely #endif 214bbd33931SGrant Likely fn += strlen(fn); 215bbd33931SGrant Likely } 216bbd33931SGrant Likely *(fn++) = '/'; 217bbd33931SGrant Likely memcpy(fn, pathp, l); 218bbd33931SGrant Likely } else 219bbd33931SGrant Likely memcpy(np->full_name, pathp, l); 220bbd33931SGrant Likely prev_pp = &np->properties; 221bbd33931SGrant Likely **allnextpp = np; 222bbd33931SGrant Likely *allnextpp = &np->allnext; 223bbd33931SGrant Likely if (dad != NULL) { 224bbd33931SGrant Likely np->parent = dad; 225bbd33931SGrant Likely /* we temporarily use the next field as `last_child'*/ 226bbd33931SGrant Likely if (dad->next == NULL) 227bbd33931SGrant Likely dad->child = np; 228bbd33931SGrant Likely else 229bbd33931SGrant Likely dad->next->sibling = np; 230bbd33931SGrant Likely dad->next = np; 231bbd33931SGrant Likely } 232bbd33931SGrant Likely kref_init(&np->kref); 233bbd33931SGrant Likely } 234a7006c97SAndres Salomon /* process properties */ 235bbd33931SGrant Likely while (1) { 236bbd33931SGrant Likely u32 sz, noff; 237bbd33931SGrant Likely char *pname; 238bbd33931SGrant Likely 23933714881SJeremy Kerr tag = be32_to_cpup((__be32 *)(*p)); 240bbd33931SGrant Likely if (tag == OF_DT_NOP) { 241bbd33931SGrant Likely *p += 4; 242bbd33931SGrant Likely continue; 243bbd33931SGrant Likely } 244bbd33931SGrant Likely if (tag != OF_DT_PROP) 245bbd33931SGrant Likely break; 246bbd33931SGrant Likely *p += 4; 24733714881SJeremy Kerr sz = be32_to_cpup((__be32 *)(*p)); 24833714881SJeremy Kerr noff = be32_to_cpup((__be32 *)((*p) + 4)); 249bbd33931SGrant Likely *p += 8; 250a40d6c4cSStephen Neuendorffer if (be32_to_cpu(blob->version) < 0x10) 251f1d4c3a7SGrant Likely *p = ALIGN(*p, sz >= 8 ? 8 : 4); 252bbd33931SGrant Likely 253a40d6c4cSStephen Neuendorffer pname = of_fdt_get_string(blob, noff); 254bbd33931SGrant Likely if (pname == NULL) { 255bbd33931SGrant Likely pr_info("Can't find property name in list !\n"); 256bbd33931SGrant Likely break; 257bbd33931SGrant Likely } 258bbd33931SGrant Likely if (strcmp(pname, "name") == 0) 259bbd33931SGrant Likely has_name = 1; 260bbd33931SGrant Likely l = strlen(pname) + 1; 261bbd33931SGrant Likely pp = unflatten_dt_alloc(&mem, sizeof(struct property), 262bbd33931SGrant Likely __alignof__(struct property)); 263bbd33931SGrant Likely if (allnextpp) { 26404b954a6SDavid Gibson /* We accept flattened tree phandles either in 26504b954a6SDavid Gibson * ePAPR-style "phandle" properties, or the 26604b954a6SDavid Gibson * legacy "linux,phandle" properties. If both 26704b954a6SDavid Gibson * appear and have different values, things 26804b954a6SDavid Gibson * will get weird. Don't do that. */ 26904b954a6SDavid Gibson if ((strcmp(pname, "phandle") == 0) || 27004b954a6SDavid Gibson (strcmp(pname, "linux,phandle") == 0)) { 2716016a363SGrant Likely if (np->phandle == 0) 2729a6b2e58SGrant Likely np->phandle = be32_to_cpup((__be32*)*p); 273bbd33931SGrant Likely } 27404b954a6SDavid Gibson /* And we process the "ibm,phandle" property 27504b954a6SDavid Gibson * used in pSeries dynamic device tree 27604b954a6SDavid Gibson * stuff */ 277bbd33931SGrant Likely if (strcmp(pname, "ibm,phandle") == 0) 2789a6b2e58SGrant Likely np->phandle = be32_to_cpup((__be32 *)*p); 279bbd33931SGrant Likely pp->name = pname; 280bbd33931SGrant Likely pp->length = sz; 281bbd33931SGrant Likely pp->value = (void *)*p; 282bbd33931SGrant Likely *prev_pp = pp; 283bbd33931SGrant Likely prev_pp = &pp->next; 284bbd33931SGrant Likely } 285f1d4c3a7SGrant Likely *p = ALIGN((*p) + sz, 4); 286bbd33931SGrant Likely } 287bbd33931SGrant Likely /* with version 0x10 we may not have the name property, recreate 288bbd33931SGrant Likely * it here from the unit name if absent 289bbd33931SGrant Likely */ 290bbd33931SGrant Likely if (!has_name) { 291bbd33931SGrant Likely char *p1 = pathp, *ps = pathp, *pa = NULL; 292bbd33931SGrant Likely int sz; 293bbd33931SGrant Likely 294bbd33931SGrant Likely while (*p1) { 295bbd33931SGrant Likely if ((*p1) == '@') 296bbd33931SGrant Likely pa = p1; 297bbd33931SGrant Likely if ((*p1) == '/') 298bbd33931SGrant Likely ps = p1 + 1; 299bbd33931SGrant Likely p1++; 300bbd33931SGrant Likely } 301bbd33931SGrant Likely if (pa < ps) 302bbd33931SGrant Likely pa = p1; 303bbd33931SGrant Likely sz = (pa - ps) + 1; 304bbd33931SGrant Likely pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, 305bbd33931SGrant Likely __alignof__(struct property)); 306bbd33931SGrant Likely if (allnextpp) { 307bbd33931SGrant Likely pp->name = "name"; 308bbd33931SGrant Likely pp->length = sz; 309bbd33931SGrant Likely pp->value = pp + 1; 310bbd33931SGrant Likely *prev_pp = pp; 311bbd33931SGrant Likely prev_pp = &pp->next; 312bbd33931SGrant Likely memcpy(pp->value, ps, sz - 1); 313bbd33931SGrant Likely ((char *)pp->value)[sz - 1] = 0; 314bbd33931SGrant Likely pr_debug("fixed up name for %s -> %s\n", pathp, 315bbd33931SGrant Likely (char *)pp->value); 316bbd33931SGrant Likely } 317bbd33931SGrant Likely } 318bbd33931SGrant Likely if (allnextpp) { 319bbd33931SGrant Likely *prev_pp = NULL; 320bbd33931SGrant Likely np->name = of_get_property(np, "name", NULL); 321bbd33931SGrant Likely np->type = of_get_property(np, "device_type", NULL); 322bbd33931SGrant Likely 323bbd33931SGrant Likely if (!np->name) 324bbd33931SGrant Likely np->name = "<NULL>"; 325bbd33931SGrant Likely if (!np->type) 326bbd33931SGrant Likely np->type = "<NULL>"; 327bbd33931SGrant Likely } 3287f809e1fSJason Gunthorpe while (tag == OF_DT_BEGIN_NODE || tag == OF_DT_NOP) { 3297f809e1fSJason Gunthorpe if (tag == OF_DT_NOP) 3307f809e1fSJason Gunthorpe *p += 4; 3317f809e1fSJason Gunthorpe else 332a40d6c4cSStephen Neuendorffer mem = unflatten_dt_node(blob, mem, p, np, allnextpp, 333a40d6c4cSStephen Neuendorffer fpsize); 33433714881SJeremy Kerr tag = be32_to_cpup((__be32 *)(*p)); 335bbd33931SGrant Likely } 336bbd33931SGrant Likely if (tag != OF_DT_END_NODE) { 337bbd33931SGrant Likely pr_err("Weird tag at end of node: %x\n", tag); 338bbd33931SGrant Likely return mem; 339bbd33931SGrant Likely } 340bbd33931SGrant Likely *p += 4; 341bbd33931SGrant Likely return mem; 342bbd33931SGrant Likely } 34341f88009SGrant Likely 344fe140423SStephen Neuendorffer /** 345fe140423SStephen Neuendorffer * __unflatten_device_tree - create tree of device_nodes from flat blob 346fe140423SStephen Neuendorffer * 347fe140423SStephen Neuendorffer * unflattens a device-tree, creating the 348fe140423SStephen Neuendorffer * tree of struct device_node. It also fills the "name" and "type" 349fe140423SStephen Neuendorffer * pointers of the nodes so the normal device-tree walking functions 350fe140423SStephen Neuendorffer * can be used. 351fe140423SStephen Neuendorffer * @blob: The blob to expand 352fe140423SStephen Neuendorffer * @mynodes: The device_node tree created by the call 353fe140423SStephen Neuendorffer * @dt_alloc: An allocator that provides a virtual address to memory 354fe140423SStephen Neuendorffer * for the resulting tree 355fe140423SStephen Neuendorffer */ 356a7006c97SAndres Salomon static void __unflatten_device_tree(struct boot_param_header *blob, 357fe140423SStephen Neuendorffer struct device_node **mynodes, 358fe140423SStephen Neuendorffer void * (*dt_alloc)(u64 size, u64 align)) 359fe140423SStephen Neuendorffer { 360fe140423SStephen Neuendorffer unsigned long start, mem, size; 361fe140423SStephen Neuendorffer struct device_node **allnextp = mynodes; 362fe140423SStephen Neuendorffer 363fe140423SStephen Neuendorffer pr_debug(" -> unflatten_device_tree()\n"); 364fe140423SStephen Neuendorffer 365fe140423SStephen Neuendorffer if (!blob) { 366fe140423SStephen Neuendorffer pr_debug("No device tree pointer\n"); 367fe140423SStephen Neuendorffer return; 368fe140423SStephen Neuendorffer } 369fe140423SStephen Neuendorffer 370fe140423SStephen Neuendorffer pr_debug("Unflattening device tree:\n"); 371fe140423SStephen Neuendorffer pr_debug("magic: %08x\n", be32_to_cpu(blob->magic)); 372fe140423SStephen Neuendorffer pr_debug("size: %08x\n", be32_to_cpu(blob->totalsize)); 373fe140423SStephen Neuendorffer pr_debug("version: %08x\n", be32_to_cpu(blob->version)); 374fe140423SStephen Neuendorffer 375fe140423SStephen Neuendorffer if (be32_to_cpu(blob->magic) != OF_DT_HEADER) { 376fe140423SStephen Neuendorffer pr_err("Invalid device tree blob header\n"); 377fe140423SStephen Neuendorffer return; 378fe140423SStephen Neuendorffer } 379fe140423SStephen Neuendorffer 380fe140423SStephen Neuendorffer /* First pass, scan for size */ 381fe140423SStephen Neuendorffer start = ((unsigned long)blob) + 382fe140423SStephen Neuendorffer be32_to_cpu(blob->off_dt_struct); 383fe140423SStephen Neuendorffer size = unflatten_dt_node(blob, 0, &start, NULL, NULL, 0); 384fe140423SStephen Neuendorffer size = (size | 3) + 1; 385fe140423SStephen Neuendorffer 386fe140423SStephen Neuendorffer pr_debug(" size is %lx, allocating...\n", size); 387fe140423SStephen Neuendorffer 388fe140423SStephen Neuendorffer /* Allocate memory for the expanded device tree */ 389fe140423SStephen Neuendorffer mem = (unsigned long) 390fe140423SStephen Neuendorffer dt_alloc(size + 4, __alignof__(struct device_node)); 391fe140423SStephen Neuendorffer 392fe140423SStephen Neuendorffer ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef); 393fe140423SStephen Neuendorffer 394fe140423SStephen Neuendorffer pr_debug(" unflattening %lx...\n", mem); 395fe140423SStephen Neuendorffer 396fe140423SStephen Neuendorffer /* Second pass, do actual unflattening */ 397fe140423SStephen Neuendorffer start = ((unsigned long)blob) + 398fe140423SStephen Neuendorffer be32_to_cpu(blob->off_dt_struct); 399fe140423SStephen Neuendorffer unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0); 400fe140423SStephen Neuendorffer if (be32_to_cpup((__be32 *)start) != OF_DT_END) 401fe140423SStephen Neuendorffer pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start)); 402fe140423SStephen Neuendorffer if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef) 403fe140423SStephen Neuendorffer pr_warning("End of tree marker overwritten: %08x\n", 404fe140423SStephen Neuendorffer be32_to_cpu(((__be32 *)mem)[size / 4])); 405fe140423SStephen Neuendorffer *allnextp = NULL; 406fe140423SStephen Neuendorffer 407fe140423SStephen Neuendorffer pr_debug(" <- unflatten_device_tree()\n"); 408fe140423SStephen Neuendorffer } 409fe140423SStephen Neuendorffer 410fe140423SStephen Neuendorffer static void *kernel_tree_alloc(u64 size, u64 align) 411fe140423SStephen Neuendorffer { 412fe140423SStephen Neuendorffer return kzalloc(size, GFP_KERNEL); 413fe140423SStephen Neuendorffer } 414fe140423SStephen Neuendorffer 415fe140423SStephen Neuendorffer /** 416fe140423SStephen Neuendorffer * of_fdt_unflatten_tree - create tree of device_nodes from flat blob 417fe140423SStephen Neuendorffer * 418fe140423SStephen Neuendorffer * unflattens the device-tree passed by the firmware, creating the 419fe140423SStephen Neuendorffer * tree of struct device_node. It also fills the "name" and "type" 420fe140423SStephen Neuendorffer * pointers of the nodes so the normal device-tree walking functions 421fe140423SStephen Neuendorffer * can be used. 422fe140423SStephen Neuendorffer */ 423fe140423SStephen Neuendorffer void of_fdt_unflatten_tree(unsigned long *blob, 424fe140423SStephen Neuendorffer struct device_node **mynodes) 425fe140423SStephen Neuendorffer { 426fe140423SStephen Neuendorffer struct boot_param_header *device_tree = 427fe140423SStephen Neuendorffer (struct boot_param_header *)blob; 428fe140423SStephen Neuendorffer __unflatten_device_tree(device_tree, mynodes, &kernel_tree_alloc); 429fe140423SStephen Neuendorffer } 430fe140423SStephen Neuendorffer EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree); 431fe140423SStephen Neuendorffer 43257d00ecfSStephen Neuendorffer /* Everything below here references initial_boot_params directly. */ 43357d00ecfSStephen Neuendorffer int __initdata dt_root_addr_cells; 43457d00ecfSStephen Neuendorffer int __initdata dt_root_size_cells; 43557d00ecfSStephen Neuendorffer 43657d00ecfSStephen Neuendorffer struct boot_param_header *initial_boot_params; 43757d00ecfSStephen Neuendorffer 43857d00ecfSStephen Neuendorffer #ifdef CONFIG_OF_EARLY_FLATTREE 43957d00ecfSStephen Neuendorffer 44057d00ecfSStephen Neuendorffer /** 44157d00ecfSStephen Neuendorffer * of_scan_flat_dt - scan flattened tree blob and call callback on each. 44257d00ecfSStephen Neuendorffer * @it: callback function 44357d00ecfSStephen Neuendorffer * @data: context data pointer 44457d00ecfSStephen Neuendorffer * 44557d00ecfSStephen Neuendorffer * This function is used to scan the flattened device-tree, it is 44657d00ecfSStephen Neuendorffer * used to extract the memory information at boot before we can 44757d00ecfSStephen Neuendorffer * unflatten the tree 44857d00ecfSStephen Neuendorffer */ 44957d00ecfSStephen Neuendorffer int __init of_scan_flat_dt(int (*it)(unsigned long node, 45057d00ecfSStephen Neuendorffer const char *uname, int depth, 45157d00ecfSStephen Neuendorffer void *data), 45257d00ecfSStephen Neuendorffer void *data) 45357d00ecfSStephen Neuendorffer { 45457d00ecfSStephen Neuendorffer unsigned long p = ((unsigned long)initial_boot_params) + 45557d00ecfSStephen Neuendorffer be32_to_cpu(initial_boot_params->off_dt_struct); 45657d00ecfSStephen Neuendorffer int rc = 0; 45757d00ecfSStephen Neuendorffer int depth = -1; 45857d00ecfSStephen Neuendorffer 45957d00ecfSStephen Neuendorffer do { 46057d00ecfSStephen Neuendorffer u32 tag = be32_to_cpup((__be32 *)p); 46157d00ecfSStephen Neuendorffer char *pathp; 46257d00ecfSStephen Neuendorffer 46357d00ecfSStephen Neuendorffer p += 4; 46457d00ecfSStephen Neuendorffer if (tag == OF_DT_END_NODE) { 46557d00ecfSStephen Neuendorffer depth--; 46657d00ecfSStephen Neuendorffer continue; 46757d00ecfSStephen Neuendorffer } 46857d00ecfSStephen Neuendorffer if (tag == OF_DT_NOP) 46957d00ecfSStephen Neuendorffer continue; 47057d00ecfSStephen Neuendorffer if (tag == OF_DT_END) 47157d00ecfSStephen Neuendorffer break; 47257d00ecfSStephen Neuendorffer if (tag == OF_DT_PROP) { 47357d00ecfSStephen Neuendorffer u32 sz = be32_to_cpup((__be32 *)p); 47457d00ecfSStephen Neuendorffer p += 8; 47557d00ecfSStephen Neuendorffer if (be32_to_cpu(initial_boot_params->version) < 0x10) 47657d00ecfSStephen Neuendorffer p = ALIGN(p, sz >= 8 ? 8 : 4); 47757d00ecfSStephen Neuendorffer p += sz; 47857d00ecfSStephen Neuendorffer p = ALIGN(p, 4); 47957d00ecfSStephen Neuendorffer continue; 48057d00ecfSStephen Neuendorffer } 48157d00ecfSStephen Neuendorffer if (tag != OF_DT_BEGIN_NODE) { 48257d00ecfSStephen Neuendorffer pr_err("Invalid tag %x in flat device tree!\n", tag); 48357d00ecfSStephen Neuendorffer return -EINVAL; 48457d00ecfSStephen Neuendorffer } 48557d00ecfSStephen Neuendorffer depth++; 48657d00ecfSStephen Neuendorffer pathp = (char *)p; 48757d00ecfSStephen Neuendorffer p = ALIGN(p + strlen(pathp) + 1, 4); 48857d00ecfSStephen Neuendorffer if ((*pathp) == '/') { 48957d00ecfSStephen Neuendorffer char *lp, *np; 49057d00ecfSStephen Neuendorffer for (lp = NULL, np = pathp; *np; np++) 49157d00ecfSStephen Neuendorffer if ((*np) == '/') 49257d00ecfSStephen Neuendorffer lp = np+1; 49357d00ecfSStephen Neuendorffer if (lp != NULL) 49457d00ecfSStephen Neuendorffer pathp = lp; 49557d00ecfSStephen Neuendorffer } 49657d00ecfSStephen Neuendorffer rc = it(p, pathp, depth, data); 49757d00ecfSStephen Neuendorffer if (rc != 0) 49857d00ecfSStephen Neuendorffer break; 49957d00ecfSStephen Neuendorffer } while (1); 50057d00ecfSStephen Neuendorffer 50157d00ecfSStephen Neuendorffer return rc; 50257d00ecfSStephen Neuendorffer } 50357d00ecfSStephen Neuendorffer 50457d00ecfSStephen Neuendorffer /** 50557d00ecfSStephen Neuendorffer * of_get_flat_dt_root - find the root node in the flat blob 50657d00ecfSStephen Neuendorffer */ 50757d00ecfSStephen Neuendorffer unsigned long __init of_get_flat_dt_root(void) 50857d00ecfSStephen Neuendorffer { 50957d00ecfSStephen Neuendorffer unsigned long p = ((unsigned long)initial_boot_params) + 51057d00ecfSStephen Neuendorffer be32_to_cpu(initial_boot_params->off_dt_struct); 51157d00ecfSStephen Neuendorffer 51257d00ecfSStephen Neuendorffer while (be32_to_cpup((__be32 *)p) == OF_DT_NOP) 51357d00ecfSStephen Neuendorffer p += 4; 51457d00ecfSStephen Neuendorffer BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE); 51557d00ecfSStephen Neuendorffer p += 4; 51657d00ecfSStephen Neuendorffer return ALIGN(p + strlen((char *)p) + 1, 4); 51757d00ecfSStephen Neuendorffer } 51857d00ecfSStephen Neuendorffer 51957d00ecfSStephen Neuendorffer /** 52057d00ecfSStephen Neuendorffer * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr 52157d00ecfSStephen Neuendorffer * 52257d00ecfSStephen Neuendorffer * This function can be used within scan_flattened_dt callback to get 52357d00ecfSStephen Neuendorffer * access to properties 52457d00ecfSStephen Neuendorffer */ 52557d00ecfSStephen Neuendorffer void *__init of_get_flat_dt_prop(unsigned long node, const char *name, 52657d00ecfSStephen Neuendorffer unsigned long *size) 52757d00ecfSStephen Neuendorffer { 52857d00ecfSStephen Neuendorffer return of_fdt_get_property(initial_boot_params, node, name, size); 52957d00ecfSStephen Neuendorffer } 53057d00ecfSStephen Neuendorffer 53157d00ecfSStephen Neuendorffer /** 53257d00ecfSStephen Neuendorffer * of_flat_dt_is_compatible - Return true if given node has compat in compatible list 53357d00ecfSStephen Neuendorffer * @node: node to test 53457d00ecfSStephen Neuendorffer * @compat: compatible string to compare with compatible list. 53557d00ecfSStephen Neuendorffer */ 53657d00ecfSStephen Neuendorffer int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) 53757d00ecfSStephen Neuendorffer { 53857d00ecfSStephen Neuendorffer return of_fdt_is_compatible(initial_boot_params, node, compat); 53957d00ecfSStephen Neuendorffer } 54057d00ecfSStephen Neuendorffer 541a4f740cfSGrant Likely /** 542a4f740cfSGrant Likely * of_flat_dt_match - Return true if node matches a list of compatible values 543a4f740cfSGrant Likely */ 544a4f740cfSGrant Likely int __init of_flat_dt_match(unsigned long node, const char **compat) 545a4f740cfSGrant Likely { 546a4f740cfSGrant Likely return of_fdt_match(initial_boot_params, node, compat); 547a4f740cfSGrant Likely } 548a4f740cfSGrant Likely 549f7b3a835SGrant Likely #ifdef CONFIG_BLK_DEV_INITRD 550f7b3a835SGrant Likely /** 551f7b3a835SGrant Likely * early_init_dt_check_for_initrd - Decode initrd location from flat tree 552f7b3a835SGrant Likely * @node: reference to node containing initrd location ('chosen') 553f7b3a835SGrant Likely */ 554f7b3a835SGrant Likely void __init early_init_dt_check_for_initrd(unsigned long node) 555f7b3a835SGrant Likely { 5561406bc2fSJeremy Kerr unsigned long start, end, len; 55733714881SJeremy Kerr __be32 *prop; 558f7b3a835SGrant Likely 559f7b3a835SGrant Likely pr_debug("Looking for initrd properties... "); 560f7b3a835SGrant Likely 561f7b3a835SGrant Likely prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len); 5621406bc2fSJeremy Kerr if (!prop) 5631406bc2fSJeremy Kerr return; 5641406bc2fSJeremy Kerr start = of_read_ulong(prop, len/4); 565f7b3a835SGrant Likely 566f7b3a835SGrant Likely prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len); 5671406bc2fSJeremy Kerr if (!prop) 5681406bc2fSJeremy Kerr return; 5691406bc2fSJeremy Kerr end = of_read_ulong(prop, len/4); 570f7b3a835SGrant Likely 5711406bc2fSJeremy Kerr early_init_dt_setup_initrd_arch(start, end); 5721406bc2fSJeremy Kerr pr_debug("initrd_start=0x%lx initrd_end=0x%lx\n", start, end); 573f7b3a835SGrant Likely } 574f7b3a835SGrant Likely #else 575f7b3a835SGrant Likely inline void early_init_dt_check_for_initrd(unsigned long node) 576f7b3a835SGrant Likely { 577f7b3a835SGrant Likely } 578f7b3a835SGrant Likely #endif /* CONFIG_BLK_DEV_INITRD */ 579f7b3a835SGrant Likely 58041f88009SGrant Likely /** 581f00abd94SGrant Likely * early_init_dt_scan_root - fetch the top level address and size cells 582f00abd94SGrant Likely */ 583f00abd94SGrant Likely int __init early_init_dt_scan_root(unsigned long node, const char *uname, 584f00abd94SGrant Likely int depth, void *data) 585f00abd94SGrant Likely { 58633714881SJeremy Kerr __be32 *prop; 587f00abd94SGrant Likely 588f00abd94SGrant Likely if (depth != 0) 589f00abd94SGrant Likely return 0; 590f00abd94SGrant Likely 59133714881SJeremy Kerr dt_root_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT; 59233714881SJeremy Kerr dt_root_addr_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT; 59333714881SJeremy Kerr 594f00abd94SGrant Likely prop = of_get_flat_dt_prop(node, "#size-cells", NULL); 59533714881SJeremy Kerr if (prop) 59633714881SJeremy Kerr dt_root_size_cells = be32_to_cpup(prop); 597f00abd94SGrant Likely pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells); 598f00abd94SGrant Likely 599f00abd94SGrant Likely prop = of_get_flat_dt_prop(node, "#address-cells", NULL); 60033714881SJeremy Kerr if (prop) 60133714881SJeremy Kerr dt_root_addr_cells = be32_to_cpup(prop); 602f00abd94SGrant Likely pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells); 603f00abd94SGrant Likely 604f00abd94SGrant Likely /* break now */ 605f00abd94SGrant Likely return 1; 606f00abd94SGrant Likely } 607f00abd94SGrant Likely 6082e89e685SJeremy Kerr u64 __init dt_mem_next_cell(int s, __be32 **cellp) 60983f7a06eSGrant Likely { 6102e89e685SJeremy Kerr __be32 *p = *cellp; 61183f7a06eSGrant Likely 61283f7a06eSGrant Likely *cellp = p + s; 61383f7a06eSGrant Likely return of_read_number(p, s); 61483f7a06eSGrant Likely } 61583f7a06eSGrant Likely 61651975db0SGrant Likely /** 61751975db0SGrant Likely * early_init_dt_scan_memory - Look for an parse memory nodes 61851975db0SGrant Likely */ 61951975db0SGrant Likely int __init early_init_dt_scan_memory(unsigned long node, const char *uname, 62051975db0SGrant Likely int depth, void *data) 62151975db0SGrant Likely { 62251975db0SGrant Likely char *type = of_get_flat_dt_prop(node, "device_type", NULL); 62351975db0SGrant Likely __be32 *reg, *endp; 62451975db0SGrant Likely unsigned long l; 62551975db0SGrant Likely 62651975db0SGrant Likely /* We are scanning "memory" nodes only */ 62751975db0SGrant Likely if (type == NULL) { 62851975db0SGrant Likely /* 62951975db0SGrant Likely * The longtrail doesn't have a device_type on the 63051975db0SGrant Likely * /memory node, so look for the node called /memory@0. 63151975db0SGrant Likely */ 63251975db0SGrant Likely if (depth != 1 || strcmp(uname, "memory@0") != 0) 63351975db0SGrant Likely return 0; 63451975db0SGrant Likely } else if (strcmp(type, "memory") != 0) 63551975db0SGrant Likely return 0; 63651975db0SGrant Likely 63751975db0SGrant Likely reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l); 63851975db0SGrant Likely if (reg == NULL) 63951975db0SGrant Likely reg = of_get_flat_dt_prop(node, "reg", &l); 64051975db0SGrant Likely if (reg == NULL) 64151975db0SGrant Likely return 0; 64251975db0SGrant Likely 64351975db0SGrant Likely endp = reg + (l / sizeof(__be32)); 64451975db0SGrant Likely 64551975db0SGrant Likely pr_debug("memory scan node %s, reg size %ld, data: %x %x %x %x,\n", 64651975db0SGrant Likely uname, l, reg[0], reg[1], reg[2], reg[3]); 64751975db0SGrant Likely 64851975db0SGrant Likely while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { 64951975db0SGrant Likely u64 base, size; 65051975db0SGrant Likely 65151975db0SGrant Likely base = dt_mem_next_cell(dt_root_addr_cells, ®); 65251975db0SGrant Likely size = dt_mem_next_cell(dt_root_size_cells, ®); 65351975db0SGrant Likely 65451975db0SGrant Likely if (size == 0) 65551975db0SGrant Likely continue; 65651975db0SGrant Likely pr_debug(" - %llx , %llx\n", (unsigned long long)base, 65751975db0SGrant Likely (unsigned long long)size); 65851975db0SGrant Likely 65951975db0SGrant Likely early_init_dt_add_memory_arch(base, size); 66051975db0SGrant Likely } 66151975db0SGrant Likely 66251975db0SGrant Likely return 0; 66351975db0SGrant Likely } 66451975db0SGrant Likely 66586e03221SGrant Likely int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, 66686e03221SGrant Likely int depth, void *data) 66786e03221SGrant Likely { 66886e03221SGrant Likely unsigned long l; 66986e03221SGrant Likely char *p; 67086e03221SGrant Likely 67186e03221SGrant Likely pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname); 67286e03221SGrant Likely 67386e03221SGrant Likely if (depth != 1 || 67486e03221SGrant Likely (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0)) 67586e03221SGrant Likely return 0; 67686e03221SGrant Likely 67786e03221SGrant Likely early_init_dt_check_for_initrd(node); 67886e03221SGrant Likely 67986e03221SGrant Likely /* Retreive command line */ 68086e03221SGrant Likely p = of_get_flat_dt_prop(node, "bootargs", &l); 68186e03221SGrant Likely if (p != NULL && l > 0) 68286e03221SGrant Likely strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE)); 68386e03221SGrant Likely 68486e03221SGrant Likely #ifdef CONFIG_CMDLINE 68586e03221SGrant Likely #ifndef CONFIG_CMDLINE_FORCE 68686e03221SGrant Likely if (p == NULL || l == 0 || (l == 1 && (*p) == 0)) 68786e03221SGrant Likely #endif 68886e03221SGrant Likely strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); 68986e03221SGrant Likely #endif /* CONFIG_CMDLINE */ 69086e03221SGrant Likely 69186e03221SGrant Likely pr_debug("Command line is: %s\n", cmd_line); 69286e03221SGrant Likely 69386e03221SGrant Likely /* break now */ 69486e03221SGrant Likely return 1; 69586e03221SGrant Likely } 69686e03221SGrant Likely 697f00abd94SGrant Likely /** 69841f88009SGrant Likely * unflatten_device_tree - create tree of device_nodes from flat blob 69941f88009SGrant Likely * 70041f88009SGrant Likely * unflattens the device-tree passed by the firmware, creating the 70141f88009SGrant Likely * tree of struct device_node. It also fills the "name" and "type" 70241f88009SGrant Likely * pointers of the nodes so the normal device-tree walking functions 70341f88009SGrant Likely * can be used. 70441f88009SGrant Likely */ 70541f88009SGrant Likely void __init unflatten_device_tree(void) 70641f88009SGrant Likely { 707fe140423SStephen Neuendorffer __unflatten_device_tree(initial_boot_params, &allnodes, 708672c5446SGrant Likely early_init_dt_alloc_memory_arch); 70941f88009SGrant Likely 71041f88009SGrant Likely /* Get pointer to OF "/chosen" node for use everywhere */ 71141f88009SGrant Likely of_chosen = of_find_node_by_path("/chosen"); 71241f88009SGrant Likely if (of_chosen == NULL) 71341f88009SGrant Likely of_chosen = of_find_node_by_path("/chosen@0"); 71441f88009SGrant Likely } 715e6ce1324SStephen Neuendorffer 716e6ce1324SStephen Neuendorffer #endif /* CONFIG_OF_EARLY_FLATTREE */ 717