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> 14e169cfbeSGrant Likely #include <linux/of.h> 15e169cfbeSGrant Likely #include <linux/of_fdt.h> 164ef7b373SJeremy Kerr #include <linux/string.h> 174ef7b373SJeremy Kerr #include <linux/errno.h> 1851975db0SGrant Likely 1986e03221SGrant Likely #ifdef CONFIG_PPC 2086e03221SGrant Likely #include <asm/machdep.h> 2186e03221SGrant Likely #endif /* CONFIG_PPC */ 2286e03221SGrant Likely 234ef7b373SJeremy Kerr #include <asm/page.h> 244ef7b373SJeremy Kerr 25f00abd94SGrant Likely int __initdata dt_root_addr_cells; 26f00abd94SGrant Likely int __initdata dt_root_size_cells; 27f00abd94SGrant Likely 28e169cfbeSGrant Likely struct boot_param_header *initial_boot_params; 29e169cfbeSGrant Likely 30e169cfbeSGrant Likely char *find_flat_dt_string(u32 offset) 31e169cfbeSGrant Likely { 32e169cfbeSGrant Likely return ((char *)initial_boot_params) + 33087f79c4SJeremy Kerr be32_to_cpu(initial_boot_params->off_dt_strings) + offset; 34e169cfbeSGrant Likely } 35c8cb7a59SGrant Likely 36c8cb7a59SGrant Likely /** 37c8cb7a59SGrant Likely * of_scan_flat_dt - scan flattened tree blob and call callback on each. 38c8cb7a59SGrant Likely * @it: callback function 39c8cb7a59SGrant Likely * @data: context data pointer 40c8cb7a59SGrant Likely * 41c8cb7a59SGrant Likely * This function is used to scan the flattened device-tree, it is 42c8cb7a59SGrant Likely * used to extract the memory information at boot before we can 43c8cb7a59SGrant Likely * unflatten the tree 44c8cb7a59SGrant Likely */ 45c8cb7a59SGrant Likely int __init of_scan_flat_dt(int (*it)(unsigned long node, 46c8cb7a59SGrant Likely const char *uname, int depth, 47c8cb7a59SGrant Likely void *data), 48c8cb7a59SGrant Likely void *data) 49c8cb7a59SGrant Likely { 50c8cb7a59SGrant Likely unsigned long p = ((unsigned long)initial_boot_params) + 51087f79c4SJeremy Kerr be32_to_cpu(initial_boot_params->off_dt_struct); 52c8cb7a59SGrant Likely int rc = 0; 53c8cb7a59SGrant Likely int depth = -1; 54c8cb7a59SGrant Likely 55c8cb7a59SGrant Likely do { 5633714881SJeremy Kerr u32 tag = be32_to_cpup((__be32 *)p); 57c8cb7a59SGrant Likely char *pathp; 58c8cb7a59SGrant Likely 59c8cb7a59SGrant Likely p += 4; 60c8cb7a59SGrant Likely if (tag == OF_DT_END_NODE) { 61c8cb7a59SGrant Likely depth--; 62c8cb7a59SGrant Likely continue; 63c8cb7a59SGrant Likely } 64c8cb7a59SGrant Likely if (tag == OF_DT_NOP) 65c8cb7a59SGrant Likely continue; 66c8cb7a59SGrant Likely if (tag == OF_DT_END) 67c8cb7a59SGrant Likely break; 68c8cb7a59SGrant Likely if (tag == OF_DT_PROP) { 6933714881SJeremy Kerr u32 sz = be32_to_cpup((__be32 *)p); 70c8cb7a59SGrant Likely p += 8; 71087f79c4SJeremy Kerr if (be32_to_cpu(initial_boot_params->version) < 0x10) 72c8cb7a59SGrant Likely p = _ALIGN(p, sz >= 8 ? 8 : 4); 73c8cb7a59SGrant Likely p += sz; 74c8cb7a59SGrant Likely p = _ALIGN(p, 4); 75c8cb7a59SGrant Likely continue; 76c8cb7a59SGrant Likely } 77c8cb7a59SGrant Likely if (tag != OF_DT_BEGIN_NODE) { 78c8cb7a59SGrant Likely pr_err("Invalid tag %x in flat device tree!\n", tag); 79c8cb7a59SGrant Likely return -EINVAL; 80c8cb7a59SGrant Likely } 81c8cb7a59SGrant Likely depth++; 82c8cb7a59SGrant Likely pathp = (char *)p; 83c8cb7a59SGrant Likely p = _ALIGN(p + strlen(pathp) + 1, 4); 84c8cb7a59SGrant Likely if ((*pathp) == '/') { 85c8cb7a59SGrant Likely char *lp, *np; 86c8cb7a59SGrant Likely for (lp = NULL, np = pathp; *np; np++) 87c8cb7a59SGrant Likely if ((*np) == '/') 88c8cb7a59SGrant Likely lp = np+1; 89c8cb7a59SGrant Likely if (lp != NULL) 90c8cb7a59SGrant Likely pathp = lp; 91c8cb7a59SGrant Likely } 92c8cb7a59SGrant Likely rc = it(p, pathp, depth, data); 93c8cb7a59SGrant Likely if (rc != 0) 94c8cb7a59SGrant Likely break; 95c8cb7a59SGrant Likely } while (1); 96c8cb7a59SGrant Likely 97c8cb7a59SGrant Likely return rc; 98c8cb7a59SGrant Likely } 99819d2819SGrant Likely 100819d2819SGrant Likely /** 101819d2819SGrant Likely * of_get_flat_dt_root - find the root node in the flat blob 102819d2819SGrant Likely */ 103819d2819SGrant Likely unsigned long __init of_get_flat_dt_root(void) 104819d2819SGrant Likely { 105819d2819SGrant Likely unsigned long p = ((unsigned long)initial_boot_params) + 106087f79c4SJeremy Kerr be32_to_cpu(initial_boot_params->off_dt_struct); 107819d2819SGrant Likely 10833714881SJeremy Kerr while (be32_to_cpup((__be32 *)p) == OF_DT_NOP) 109819d2819SGrant Likely p += 4; 11033714881SJeremy Kerr BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE); 111819d2819SGrant Likely p += 4; 112819d2819SGrant Likely return _ALIGN(p + strlen((char *)p) + 1, 4); 113819d2819SGrant Likely } 114819d2819SGrant Likely 115ca900cfaSGrant Likely /** 116ca900cfaSGrant Likely * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr 117ca900cfaSGrant Likely * 118ca900cfaSGrant Likely * This function can be used within scan_flattened_dt callback to get 119ca900cfaSGrant Likely * access to properties 120ca900cfaSGrant Likely */ 121ca900cfaSGrant Likely void *__init of_get_flat_dt_prop(unsigned long node, const char *name, 122ca900cfaSGrant Likely unsigned long *size) 123ca900cfaSGrant Likely { 124ca900cfaSGrant Likely unsigned long p = node; 125ca900cfaSGrant Likely 126ca900cfaSGrant Likely do { 12733714881SJeremy Kerr u32 tag = be32_to_cpup((__be32 *)p); 128ca900cfaSGrant Likely u32 sz, noff; 129ca900cfaSGrant Likely const char *nstr; 130ca900cfaSGrant Likely 131ca900cfaSGrant Likely p += 4; 132ca900cfaSGrant Likely if (tag == OF_DT_NOP) 133ca900cfaSGrant Likely continue; 134ca900cfaSGrant Likely if (tag != OF_DT_PROP) 135ca900cfaSGrant Likely return NULL; 136ca900cfaSGrant Likely 13733714881SJeremy Kerr sz = be32_to_cpup((__be32 *)p); 13833714881SJeremy Kerr noff = be32_to_cpup((__be32 *)(p + 4)); 139ca900cfaSGrant Likely p += 8; 140087f79c4SJeremy Kerr if (be32_to_cpu(initial_boot_params->version) < 0x10) 141ca900cfaSGrant Likely p = _ALIGN(p, sz >= 8 ? 8 : 4); 142ca900cfaSGrant Likely 143ca900cfaSGrant Likely nstr = find_flat_dt_string(noff); 144ca900cfaSGrant Likely if (nstr == NULL) { 145ca900cfaSGrant Likely pr_warning("Can't find property index name !\n"); 146ca900cfaSGrant Likely return NULL; 147ca900cfaSGrant Likely } 148ca900cfaSGrant Likely if (strcmp(name, nstr) == 0) { 149ca900cfaSGrant Likely if (size) 150ca900cfaSGrant Likely *size = sz; 151ca900cfaSGrant Likely return (void *)p; 152ca900cfaSGrant Likely } 153ca900cfaSGrant Likely p += sz; 154ca900cfaSGrant Likely p = _ALIGN(p, 4); 155ca900cfaSGrant Likely } while (1); 156ca900cfaSGrant Likely } 157ca900cfaSGrant Likely 15800e38efdSGrant Likely /** 15900e38efdSGrant Likely * of_flat_dt_is_compatible - Return true if given node has compat in compatible list 16000e38efdSGrant Likely * @node: node to test 16100e38efdSGrant Likely * @compat: compatible string to compare with compatible list. 16200e38efdSGrant Likely */ 16300e38efdSGrant Likely int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) 16400e38efdSGrant Likely { 16500e38efdSGrant Likely const char *cp; 16600e38efdSGrant Likely unsigned long cplen, l; 16700e38efdSGrant Likely 16800e38efdSGrant Likely cp = of_get_flat_dt_prop(node, "compatible", &cplen); 16900e38efdSGrant Likely if (cp == NULL) 17000e38efdSGrant Likely return 0; 17100e38efdSGrant Likely while (cplen > 0) { 17200e38efdSGrant Likely if (strncasecmp(cp, compat, strlen(compat)) == 0) 17300e38efdSGrant Likely return 1; 17400e38efdSGrant Likely l = strlen(cp) + 1; 17500e38efdSGrant Likely cp += l; 17600e38efdSGrant Likely cplen -= l; 17700e38efdSGrant Likely } 17800e38efdSGrant Likely 17900e38efdSGrant Likely return 0; 18000e38efdSGrant Likely } 18100e38efdSGrant Likely 182bbd33931SGrant Likely static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, 183bbd33931SGrant Likely unsigned long align) 184bbd33931SGrant Likely { 185bbd33931SGrant Likely void *res; 186bbd33931SGrant Likely 187bbd33931SGrant Likely *mem = _ALIGN(*mem, align); 188bbd33931SGrant Likely res = (void *)*mem; 189bbd33931SGrant Likely *mem += size; 190bbd33931SGrant Likely 191bbd33931SGrant Likely return res; 192bbd33931SGrant Likely } 193bbd33931SGrant Likely 194bbd33931SGrant Likely /** 195bbd33931SGrant Likely * unflatten_dt_node - Alloc and populate a device_node from the flat tree 196bbd33931SGrant Likely * @p: pointer to node in flat tree 197bbd33931SGrant Likely * @dad: Parent struct device_node 198bbd33931SGrant Likely * @allnextpp: pointer to ->allnext from last allocated device_node 199bbd33931SGrant Likely * @fpsize: Size of the node path up at the current depth. 200bbd33931SGrant Likely */ 201bbd33931SGrant Likely unsigned long __init unflatten_dt_node(unsigned long mem, 202bbd33931SGrant Likely unsigned long *p, 203bbd33931SGrant Likely struct device_node *dad, 204bbd33931SGrant Likely struct device_node ***allnextpp, 205bbd33931SGrant Likely unsigned long fpsize) 206bbd33931SGrant Likely { 207bbd33931SGrant Likely struct device_node *np; 208bbd33931SGrant Likely struct property *pp, **prev_pp = NULL; 209bbd33931SGrant Likely char *pathp; 210bbd33931SGrant Likely u32 tag; 211bbd33931SGrant Likely unsigned int l, allocl; 212bbd33931SGrant Likely int has_name = 0; 213bbd33931SGrant Likely int new_format = 0; 214bbd33931SGrant Likely 21533714881SJeremy Kerr tag = be32_to_cpup((__be32 *)(*p)); 216bbd33931SGrant Likely if (tag != OF_DT_BEGIN_NODE) { 217bbd33931SGrant Likely pr_err("Weird tag at start of node: %x\n", tag); 218bbd33931SGrant Likely return mem; 219bbd33931SGrant Likely } 220bbd33931SGrant Likely *p += 4; 221bbd33931SGrant Likely pathp = (char *)*p; 222bbd33931SGrant Likely l = allocl = strlen(pathp) + 1; 223bbd33931SGrant Likely *p = _ALIGN(*p + l, 4); 224bbd33931SGrant Likely 225bbd33931SGrant Likely /* version 0x10 has a more compact unit name here instead of the full 226bbd33931SGrant Likely * path. we accumulate the full path size using "fpsize", we'll rebuild 227bbd33931SGrant Likely * it later. We detect this because the first character of the name is 228bbd33931SGrant Likely * not '/'. 229bbd33931SGrant Likely */ 230bbd33931SGrant Likely if ((*pathp) != '/') { 231bbd33931SGrant Likely new_format = 1; 232bbd33931SGrant Likely if (fpsize == 0) { 233bbd33931SGrant Likely /* root node: special case. fpsize accounts for path 234bbd33931SGrant Likely * plus terminating zero. root node only has '/', so 235bbd33931SGrant Likely * fpsize should be 2, but we want to avoid the first 236bbd33931SGrant Likely * level nodes to have two '/' so we use fpsize 1 here 237bbd33931SGrant Likely */ 238bbd33931SGrant Likely fpsize = 1; 239bbd33931SGrant Likely allocl = 2; 240bbd33931SGrant Likely } else { 241bbd33931SGrant Likely /* account for '/' and path size minus terminal 0 242bbd33931SGrant Likely * already in 'l' 243bbd33931SGrant Likely */ 244bbd33931SGrant Likely fpsize += l; 245bbd33931SGrant Likely allocl = fpsize; 246bbd33931SGrant Likely } 247bbd33931SGrant Likely } 248bbd33931SGrant Likely 249bbd33931SGrant Likely np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, 250bbd33931SGrant Likely __alignof__(struct device_node)); 251bbd33931SGrant Likely if (allnextpp) { 252bbd33931SGrant Likely memset(np, 0, sizeof(*np)); 253bbd33931SGrant Likely np->full_name = ((char *)np) + sizeof(struct device_node); 254bbd33931SGrant Likely if (new_format) { 255bbd33931SGrant Likely char *fn = np->full_name; 256bbd33931SGrant Likely /* rebuild full path for new format */ 257bbd33931SGrant Likely if (dad && dad->parent) { 258bbd33931SGrant Likely strcpy(fn, dad->full_name); 259bbd33931SGrant Likely #ifdef DEBUG 260bbd33931SGrant Likely if ((strlen(fn) + l + 1) != allocl) { 261bbd33931SGrant Likely pr_debug("%s: p: %d, l: %d, a: %d\n", 262bbd33931SGrant Likely pathp, (int)strlen(fn), 263bbd33931SGrant Likely l, allocl); 264bbd33931SGrant Likely } 265bbd33931SGrant Likely #endif 266bbd33931SGrant Likely fn += strlen(fn); 267bbd33931SGrant Likely } 268bbd33931SGrant Likely *(fn++) = '/'; 269bbd33931SGrant Likely memcpy(fn, pathp, l); 270bbd33931SGrant Likely } else 271bbd33931SGrant Likely memcpy(np->full_name, pathp, l); 272bbd33931SGrant Likely prev_pp = &np->properties; 273bbd33931SGrant Likely **allnextpp = np; 274bbd33931SGrant Likely *allnextpp = &np->allnext; 275bbd33931SGrant Likely if (dad != NULL) { 276bbd33931SGrant Likely np->parent = dad; 277bbd33931SGrant Likely /* we temporarily use the next field as `last_child'*/ 278bbd33931SGrant Likely if (dad->next == NULL) 279bbd33931SGrant Likely dad->child = np; 280bbd33931SGrant Likely else 281bbd33931SGrant Likely dad->next->sibling = np; 282bbd33931SGrant Likely dad->next = np; 283bbd33931SGrant Likely } 284bbd33931SGrant Likely kref_init(&np->kref); 285bbd33931SGrant Likely } 286bbd33931SGrant Likely while (1) { 287bbd33931SGrant Likely u32 sz, noff; 288bbd33931SGrant Likely char *pname; 289bbd33931SGrant Likely 29033714881SJeremy Kerr tag = be32_to_cpup((__be32 *)(*p)); 291bbd33931SGrant Likely if (tag == OF_DT_NOP) { 292bbd33931SGrant Likely *p += 4; 293bbd33931SGrant Likely continue; 294bbd33931SGrant Likely } 295bbd33931SGrant Likely if (tag != OF_DT_PROP) 296bbd33931SGrant Likely break; 297bbd33931SGrant Likely *p += 4; 29833714881SJeremy Kerr sz = be32_to_cpup((__be32 *)(*p)); 29933714881SJeremy Kerr noff = be32_to_cpup((__be32 *)((*p) + 4)); 300bbd33931SGrant Likely *p += 8; 301087f79c4SJeremy Kerr if (be32_to_cpu(initial_boot_params->version) < 0x10) 302bbd33931SGrant Likely *p = _ALIGN(*p, sz >= 8 ? 8 : 4); 303bbd33931SGrant Likely 304bbd33931SGrant Likely pname = find_flat_dt_string(noff); 305bbd33931SGrant Likely if (pname == NULL) { 306bbd33931SGrant Likely pr_info("Can't find property name in list !\n"); 307bbd33931SGrant Likely break; 308bbd33931SGrant Likely } 309bbd33931SGrant Likely if (strcmp(pname, "name") == 0) 310bbd33931SGrant Likely has_name = 1; 311bbd33931SGrant Likely l = strlen(pname) + 1; 312bbd33931SGrant Likely pp = unflatten_dt_alloc(&mem, sizeof(struct property), 313bbd33931SGrant Likely __alignof__(struct property)); 314bbd33931SGrant Likely if (allnextpp) { 31504b954a6SDavid Gibson /* We accept flattened tree phandles either in 31604b954a6SDavid Gibson * ePAPR-style "phandle" properties, or the 31704b954a6SDavid Gibson * legacy "linux,phandle" properties. If both 31804b954a6SDavid Gibson * appear and have different values, things 31904b954a6SDavid Gibson * will get weird. Don't do that. */ 32004b954a6SDavid Gibson if ((strcmp(pname, "phandle") == 0) || 32104b954a6SDavid Gibson (strcmp(pname, "linux,phandle") == 0)) { 3226016a363SGrant Likely if (np->phandle == 0) 3236016a363SGrant Likely np->phandle = *((u32 *)*p); 324bbd33931SGrant Likely } 32504b954a6SDavid Gibson /* And we process the "ibm,phandle" property 32604b954a6SDavid Gibson * used in pSeries dynamic device tree 32704b954a6SDavid Gibson * stuff */ 328bbd33931SGrant Likely if (strcmp(pname, "ibm,phandle") == 0) 3296016a363SGrant Likely np->phandle = *((u32 *)*p); 330bbd33931SGrant Likely pp->name = pname; 331bbd33931SGrant Likely pp->length = sz; 332bbd33931SGrant Likely pp->value = (void *)*p; 333bbd33931SGrant Likely *prev_pp = pp; 334bbd33931SGrant Likely prev_pp = &pp->next; 335bbd33931SGrant Likely } 336bbd33931SGrant Likely *p = _ALIGN((*p) + sz, 4); 337bbd33931SGrant Likely } 338bbd33931SGrant Likely /* with version 0x10 we may not have the name property, recreate 339bbd33931SGrant Likely * it here from the unit name if absent 340bbd33931SGrant Likely */ 341bbd33931SGrant Likely if (!has_name) { 342bbd33931SGrant Likely char *p1 = pathp, *ps = pathp, *pa = NULL; 343bbd33931SGrant Likely int sz; 344bbd33931SGrant Likely 345bbd33931SGrant Likely while (*p1) { 346bbd33931SGrant Likely if ((*p1) == '@') 347bbd33931SGrant Likely pa = p1; 348bbd33931SGrant Likely if ((*p1) == '/') 349bbd33931SGrant Likely ps = p1 + 1; 350bbd33931SGrant Likely p1++; 351bbd33931SGrant Likely } 352bbd33931SGrant Likely if (pa < ps) 353bbd33931SGrant Likely pa = p1; 354bbd33931SGrant Likely sz = (pa - ps) + 1; 355bbd33931SGrant Likely pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, 356bbd33931SGrant Likely __alignof__(struct property)); 357bbd33931SGrant Likely if (allnextpp) { 358bbd33931SGrant Likely pp->name = "name"; 359bbd33931SGrant Likely pp->length = sz; 360bbd33931SGrant Likely pp->value = pp + 1; 361bbd33931SGrant Likely *prev_pp = pp; 362bbd33931SGrant Likely prev_pp = &pp->next; 363bbd33931SGrant Likely memcpy(pp->value, ps, sz - 1); 364bbd33931SGrant Likely ((char *)pp->value)[sz - 1] = 0; 365bbd33931SGrant Likely pr_debug("fixed up name for %s -> %s\n", pathp, 366bbd33931SGrant Likely (char *)pp->value); 367bbd33931SGrant Likely } 368bbd33931SGrant Likely } 369bbd33931SGrant Likely if (allnextpp) { 370bbd33931SGrant Likely *prev_pp = NULL; 371bbd33931SGrant Likely np->name = of_get_property(np, "name", NULL); 372bbd33931SGrant Likely np->type = of_get_property(np, "device_type", NULL); 373bbd33931SGrant Likely 374bbd33931SGrant Likely if (!np->name) 375bbd33931SGrant Likely np->name = "<NULL>"; 376bbd33931SGrant Likely if (!np->type) 377bbd33931SGrant Likely np->type = "<NULL>"; 378bbd33931SGrant Likely } 3797f809e1fSJason Gunthorpe while (tag == OF_DT_BEGIN_NODE || tag == OF_DT_NOP) { 3807f809e1fSJason Gunthorpe if (tag == OF_DT_NOP) 3817f809e1fSJason Gunthorpe *p += 4; 3827f809e1fSJason Gunthorpe else 383bbd33931SGrant Likely mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize); 38433714881SJeremy Kerr tag = be32_to_cpup((__be32 *)(*p)); 385bbd33931SGrant Likely } 386bbd33931SGrant Likely if (tag != OF_DT_END_NODE) { 387bbd33931SGrant Likely pr_err("Weird tag at end of node: %x\n", tag); 388bbd33931SGrant Likely return mem; 389bbd33931SGrant Likely } 390bbd33931SGrant Likely *p += 4; 391bbd33931SGrant Likely return mem; 392bbd33931SGrant Likely } 39341f88009SGrant Likely 394f7b3a835SGrant Likely #ifdef CONFIG_BLK_DEV_INITRD 395f7b3a835SGrant Likely /** 396f7b3a835SGrant Likely * early_init_dt_check_for_initrd - Decode initrd location from flat tree 397f7b3a835SGrant Likely * @node: reference to node containing initrd location ('chosen') 398f7b3a835SGrant Likely */ 399f7b3a835SGrant Likely void __init early_init_dt_check_for_initrd(unsigned long node) 400f7b3a835SGrant Likely { 4011406bc2fSJeremy Kerr unsigned long start, end, len; 40233714881SJeremy Kerr __be32 *prop; 403f7b3a835SGrant Likely 404f7b3a835SGrant Likely pr_debug("Looking for initrd properties... "); 405f7b3a835SGrant Likely 406f7b3a835SGrant Likely prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len); 4071406bc2fSJeremy Kerr if (!prop) 4081406bc2fSJeremy Kerr return; 4091406bc2fSJeremy Kerr start = of_read_ulong(prop, len/4); 410f7b3a835SGrant Likely 411f7b3a835SGrant Likely prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len); 4121406bc2fSJeremy Kerr if (!prop) 4131406bc2fSJeremy Kerr return; 4141406bc2fSJeremy Kerr end = of_read_ulong(prop, len/4); 415f7b3a835SGrant Likely 4161406bc2fSJeremy Kerr early_init_dt_setup_initrd_arch(start, end); 4171406bc2fSJeremy Kerr pr_debug("initrd_start=0x%lx initrd_end=0x%lx\n", start, end); 418f7b3a835SGrant Likely } 419f7b3a835SGrant Likely #else 420f7b3a835SGrant Likely inline void early_init_dt_check_for_initrd(unsigned long node) 421f7b3a835SGrant Likely { 422f7b3a835SGrant Likely } 423f7b3a835SGrant Likely #endif /* CONFIG_BLK_DEV_INITRD */ 424f7b3a835SGrant Likely 42541f88009SGrant Likely /** 426f00abd94SGrant Likely * early_init_dt_scan_root - fetch the top level address and size cells 427f00abd94SGrant Likely */ 428f00abd94SGrant Likely int __init early_init_dt_scan_root(unsigned long node, const char *uname, 429f00abd94SGrant Likely int depth, void *data) 430f00abd94SGrant Likely { 43133714881SJeremy Kerr __be32 *prop; 432f00abd94SGrant Likely 433f00abd94SGrant Likely if (depth != 0) 434f00abd94SGrant Likely return 0; 435f00abd94SGrant Likely 43633714881SJeremy Kerr dt_root_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT; 43733714881SJeremy Kerr dt_root_addr_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT; 43833714881SJeremy Kerr 439f00abd94SGrant Likely prop = of_get_flat_dt_prop(node, "#size-cells", NULL); 44033714881SJeremy Kerr if (prop) 44133714881SJeremy Kerr dt_root_size_cells = be32_to_cpup(prop); 442f00abd94SGrant Likely pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells); 443f00abd94SGrant Likely 444f00abd94SGrant Likely prop = of_get_flat_dt_prop(node, "#address-cells", NULL); 44533714881SJeremy Kerr if (prop) 44633714881SJeremy Kerr dt_root_addr_cells = be32_to_cpup(prop); 447f00abd94SGrant Likely pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells); 448f00abd94SGrant Likely 449f00abd94SGrant Likely /* break now */ 450f00abd94SGrant Likely return 1; 451f00abd94SGrant Likely } 452f00abd94SGrant Likely 4532e89e685SJeremy Kerr u64 __init dt_mem_next_cell(int s, __be32 **cellp) 45483f7a06eSGrant Likely { 4552e89e685SJeremy Kerr __be32 *p = *cellp; 45683f7a06eSGrant Likely 45783f7a06eSGrant Likely *cellp = p + s; 45883f7a06eSGrant Likely return of_read_number(p, s); 45983f7a06eSGrant Likely } 46083f7a06eSGrant Likely 46151975db0SGrant Likely /** 46251975db0SGrant Likely * early_init_dt_scan_memory - Look for an parse memory nodes 46351975db0SGrant Likely */ 46451975db0SGrant Likely int __init early_init_dt_scan_memory(unsigned long node, const char *uname, 46551975db0SGrant Likely int depth, void *data) 46651975db0SGrant Likely { 46751975db0SGrant Likely char *type = of_get_flat_dt_prop(node, "device_type", NULL); 46851975db0SGrant Likely __be32 *reg, *endp; 46951975db0SGrant Likely unsigned long l; 47051975db0SGrant Likely 47151975db0SGrant Likely /* We are scanning "memory" nodes only */ 47251975db0SGrant Likely if (type == NULL) { 47351975db0SGrant Likely /* 47451975db0SGrant Likely * The longtrail doesn't have a device_type on the 47551975db0SGrant Likely * /memory node, so look for the node called /memory@0. 47651975db0SGrant Likely */ 47751975db0SGrant Likely if (depth != 1 || strcmp(uname, "memory@0") != 0) 47851975db0SGrant Likely return 0; 47951975db0SGrant Likely } else if (strcmp(type, "memory") != 0) 48051975db0SGrant Likely return 0; 48151975db0SGrant Likely 48251975db0SGrant Likely reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l); 48351975db0SGrant Likely if (reg == NULL) 48451975db0SGrant Likely reg = of_get_flat_dt_prop(node, "reg", &l); 48551975db0SGrant Likely if (reg == NULL) 48651975db0SGrant Likely return 0; 48751975db0SGrant Likely 48851975db0SGrant Likely endp = reg + (l / sizeof(__be32)); 48951975db0SGrant Likely 49051975db0SGrant Likely pr_debug("memory scan node %s, reg size %ld, data: %x %x %x %x,\n", 49151975db0SGrant Likely uname, l, reg[0], reg[1], reg[2], reg[3]); 49251975db0SGrant Likely 49351975db0SGrant Likely while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { 49451975db0SGrant Likely u64 base, size; 49551975db0SGrant Likely 49651975db0SGrant Likely base = dt_mem_next_cell(dt_root_addr_cells, ®); 49751975db0SGrant Likely size = dt_mem_next_cell(dt_root_size_cells, ®); 49851975db0SGrant Likely 49951975db0SGrant Likely if (size == 0) 50051975db0SGrant Likely continue; 50151975db0SGrant Likely pr_debug(" - %llx , %llx\n", (unsigned long long)base, 50251975db0SGrant Likely (unsigned long long)size); 50351975db0SGrant Likely 50451975db0SGrant Likely early_init_dt_add_memory_arch(base, size); 50551975db0SGrant Likely } 50651975db0SGrant Likely 50751975db0SGrant Likely return 0; 50851975db0SGrant Likely } 50951975db0SGrant Likely 51086e03221SGrant Likely int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, 51186e03221SGrant Likely int depth, void *data) 51286e03221SGrant Likely { 51386e03221SGrant Likely unsigned long l; 51486e03221SGrant Likely char *p; 51586e03221SGrant Likely 51686e03221SGrant Likely pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname); 51786e03221SGrant Likely 51886e03221SGrant Likely if (depth != 1 || 51986e03221SGrant Likely (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0)) 52086e03221SGrant Likely return 0; 52186e03221SGrant Likely 52286e03221SGrant Likely early_init_dt_check_for_initrd(node); 52386e03221SGrant Likely 52486e03221SGrant Likely /* Retreive command line */ 52586e03221SGrant Likely p = of_get_flat_dt_prop(node, "bootargs", &l); 52686e03221SGrant Likely if (p != NULL && l > 0) 52786e03221SGrant Likely strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE)); 52886e03221SGrant Likely 52986e03221SGrant Likely #ifdef CONFIG_CMDLINE 53086e03221SGrant Likely #ifndef CONFIG_CMDLINE_FORCE 53186e03221SGrant Likely if (p == NULL || l == 0 || (l == 1 && (*p) == 0)) 53286e03221SGrant Likely #endif 53386e03221SGrant Likely strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); 53486e03221SGrant Likely #endif /* CONFIG_CMDLINE */ 53586e03221SGrant Likely 53686e03221SGrant Likely early_init_dt_scan_chosen_arch(node); 53786e03221SGrant Likely 53886e03221SGrant Likely pr_debug("Command line is: %s\n", cmd_line); 53986e03221SGrant Likely 54086e03221SGrant Likely /* break now */ 54186e03221SGrant Likely return 1; 54286e03221SGrant Likely } 54386e03221SGrant Likely 544f00abd94SGrant Likely /** 54541f88009SGrant Likely * unflatten_device_tree - create tree of device_nodes from flat blob 54641f88009SGrant Likely * 54741f88009SGrant Likely * unflattens the device-tree passed by the firmware, creating the 54841f88009SGrant Likely * tree of struct device_node. It also fills the "name" and "type" 54941f88009SGrant Likely * pointers of the nodes so the normal device-tree walking functions 55041f88009SGrant Likely * can be used. 55141f88009SGrant Likely */ 55241f88009SGrant Likely void __init unflatten_device_tree(void) 55341f88009SGrant Likely { 55441f88009SGrant Likely unsigned long start, mem, size; 55541f88009SGrant Likely struct device_node **allnextp = &allnodes; 55641f88009SGrant Likely 55741f88009SGrant Likely pr_debug(" -> unflatten_device_tree()\n"); 55841f88009SGrant Likely 55941f88009SGrant Likely /* First pass, scan for size */ 56041f88009SGrant Likely start = ((unsigned long)initial_boot_params) + 561087f79c4SJeremy Kerr be32_to_cpu(initial_boot_params->off_dt_struct); 56241f88009SGrant Likely size = unflatten_dt_node(0, &start, NULL, NULL, 0); 56341f88009SGrant Likely size = (size | 3) + 1; 56441f88009SGrant Likely 56541f88009SGrant Likely pr_debug(" size is %lx, allocating...\n", size); 56641f88009SGrant Likely 56741f88009SGrant Likely /* Allocate memory for the expanded device tree */ 5684ef7b373SJeremy Kerr mem = early_init_dt_alloc_memory_arch(size + 4, 5694ef7b373SJeremy Kerr __alignof__(struct device_node)); 57041f88009SGrant Likely mem = (unsigned long) __va(mem); 57141f88009SGrant Likely 57233714881SJeremy Kerr ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef); 57341f88009SGrant Likely 57441f88009SGrant Likely pr_debug(" unflattening %lx...\n", mem); 57541f88009SGrant Likely 57641f88009SGrant Likely /* Second pass, do actual unflattening */ 57741f88009SGrant Likely start = ((unsigned long)initial_boot_params) + 578087f79c4SJeremy Kerr be32_to_cpu(initial_boot_params->off_dt_struct); 57941f88009SGrant Likely unflatten_dt_node(mem, &start, NULL, &allnextp, 0); 58033714881SJeremy Kerr if (be32_to_cpup((__be32 *)start) != OF_DT_END) 58141f88009SGrant Likely pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start)); 58233714881SJeremy Kerr if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef) 58341f88009SGrant Likely pr_warning("End of tree marker overwritten: %08x\n", 58433714881SJeremy Kerr be32_to_cpu(((__be32 *)mem)[size / 4])); 58541f88009SGrant Likely *allnextp = NULL; 58641f88009SGrant Likely 58741f88009SGrant Likely /* Get pointer to OF "/chosen" node for use everywhere */ 58841f88009SGrant Likely of_chosen = of_find_node_by_path("/chosen"); 58941f88009SGrant Likely if (of_chosen == NULL) 59041f88009SGrant Likely of_chosen = of_find_node_by_path("/chosen@0"); 59141f88009SGrant Likely 59241f88009SGrant Likely pr_debug(" <- unflatten_device_tree()\n"); 59341f88009SGrant Likely } 594