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> 1341f88009SGrant Likely #include <linux/lmb.h> 14f7b3a835SGrant Likely #include <linux/initrd.h> 15e169cfbeSGrant Likely #include <linux/of.h> 16e169cfbeSGrant Likely #include <linux/of_fdt.h> 17e169cfbeSGrant Likely 1851975db0SGrant Likely 1986e03221SGrant Likely #ifdef CONFIG_PPC 2086e03221SGrant Likely #include <asm/machdep.h> 2186e03221SGrant Likely #endif /* CONFIG_PPC */ 2286e03221SGrant Likely 23f00abd94SGrant Likely int __initdata dt_root_addr_cells; 24f00abd94SGrant Likely int __initdata dt_root_size_cells; 25f00abd94SGrant Likely 26e169cfbeSGrant Likely struct boot_param_header *initial_boot_params; 27e169cfbeSGrant Likely 28e169cfbeSGrant Likely char *find_flat_dt_string(u32 offset) 29e169cfbeSGrant Likely { 30e169cfbeSGrant Likely return ((char *)initial_boot_params) + 31e169cfbeSGrant Likely initial_boot_params->off_dt_strings + offset; 32e169cfbeSGrant Likely } 33c8cb7a59SGrant Likely 34c8cb7a59SGrant Likely /** 35c8cb7a59SGrant Likely * of_scan_flat_dt - scan flattened tree blob and call callback on each. 36c8cb7a59SGrant Likely * @it: callback function 37c8cb7a59SGrant Likely * @data: context data pointer 38c8cb7a59SGrant Likely * 39c8cb7a59SGrant Likely * This function is used to scan the flattened device-tree, it is 40c8cb7a59SGrant Likely * used to extract the memory information at boot before we can 41c8cb7a59SGrant Likely * unflatten the tree 42c8cb7a59SGrant Likely */ 43c8cb7a59SGrant Likely int __init of_scan_flat_dt(int (*it)(unsigned long node, 44c8cb7a59SGrant Likely const char *uname, int depth, 45c8cb7a59SGrant Likely void *data), 46c8cb7a59SGrant Likely void *data) 47c8cb7a59SGrant Likely { 48c8cb7a59SGrant Likely unsigned long p = ((unsigned long)initial_boot_params) + 49c8cb7a59SGrant Likely initial_boot_params->off_dt_struct; 50c8cb7a59SGrant Likely int rc = 0; 51c8cb7a59SGrant Likely int depth = -1; 52c8cb7a59SGrant Likely 53c8cb7a59SGrant Likely do { 54c8cb7a59SGrant Likely u32 tag = *((u32 *)p); 55c8cb7a59SGrant Likely char *pathp; 56c8cb7a59SGrant Likely 57c8cb7a59SGrant Likely p += 4; 58c8cb7a59SGrant Likely if (tag == OF_DT_END_NODE) { 59c8cb7a59SGrant Likely depth--; 60c8cb7a59SGrant Likely continue; 61c8cb7a59SGrant Likely } 62c8cb7a59SGrant Likely if (tag == OF_DT_NOP) 63c8cb7a59SGrant Likely continue; 64c8cb7a59SGrant Likely if (tag == OF_DT_END) 65c8cb7a59SGrant Likely break; 66c8cb7a59SGrant Likely if (tag == OF_DT_PROP) { 67c8cb7a59SGrant Likely u32 sz = *((u32 *)p); 68c8cb7a59SGrant Likely p += 8; 69c8cb7a59SGrant Likely if (initial_boot_params->version < 0x10) 70c8cb7a59SGrant Likely p = _ALIGN(p, sz >= 8 ? 8 : 4); 71c8cb7a59SGrant Likely p += sz; 72c8cb7a59SGrant Likely p = _ALIGN(p, 4); 73c8cb7a59SGrant Likely continue; 74c8cb7a59SGrant Likely } 75c8cb7a59SGrant Likely if (tag != OF_DT_BEGIN_NODE) { 76c8cb7a59SGrant Likely pr_err("Invalid tag %x in flat device tree!\n", tag); 77c8cb7a59SGrant Likely return -EINVAL; 78c8cb7a59SGrant Likely } 79c8cb7a59SGrant Likely depth++; 80c8cb7a59SGrant Likely pathp = (char *)p; 81c8cb7a59SGrant Likely p = _ALIGN(p + strlen(pathp) + 1, 4); 82c8cb7a59SGrant Likely if ((*pathp) == '/') { 83c8cb7a59SGrant Likely char *lp, *np; 84c8cb7a59SGrant Likely for (lp = NULL, np = pathp; *np; np++) 85c8cb7a59SGrant Likely if ((*np) == '/') 86c8cb7a59SGrant Likely lp = np+1; 87c8cb7a59SGrant Likely if (lp != NULL) 88c8cb7a59SGrant Likely pathp = lp; 89c8cb7a59SGrant Likely } 90c8cb7a59SGrant Likely rc = it(p, pathp, depth, data); 91c8cb7a59SGrant Likely if (rc != 0) 92c8cb7a59SGrant Likely break; 93c8cb7a59SGrant Likely } while (1); 94c8cb7a59SGrant Likely 95c8cb7a59SGrant Likely return rc; 96c8cb7a59SGrant Likely } 97819d2819SGrant Likely 98819d2819SGrant Likely /** 99819d2819SGrant Likely * of_get_flat_dt_root - find the root node in the flat blob 100819d2819SGrant Likely */ 101819d2819SGrant Likely unsigned long __init of_get_flat_dt_root(void) 102819d2819SGrant Likely { 103819d2819SGrant Likely unsigned long p = ((unsigned long)initial_boot_params) + 104819d2819SGrant Likely initial_boot_params->off_dt_struct; 105819d2819SGrant Likely 106819d2819SGrant Likely while (*((u32 *)p) == OF_DT_NOP) 107819d2819SGrant Likely p += 4; 108819d2819SGrant Likely BUG_ON(*((u32 *)p) != OF_DT_BEGIN_NODE); 109819d2819SGrant Likely p += 4; 110819d2819SGrant Likely return _ALIGN(p + strlen((char *)p) + 1, 4); 111819d2819SGrant Likely } 112819d2819SGrant Likely 113ca900cfaSGrant Likely /** 114ca900cfaSGrant Likely * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr 115ca900cfaSGrant Likely * 116ca900cfaSGrant Likely * This function can be used within scan_flattened_dt callback to get 117ca900cfaSGrant Likely * access to properties 118ca900cfaSGrant Likely */ 119ca900cfaSGrant Likely void *__init of_get_flat_dt_prop(unsigned long node, const char *name, 120ca900cfaSGrant Likely unsigned long *size) 121ca900cfaSGrant Likely { 122ca900cfaSGrant Likely unsigned long p = node; 123ca900cfaSGrant Likely 124ca900cfaSGrant Likely do { 125ca900cfaSGrant Likely u32 tag = *((u32 *)p); 126ca900cfaSGrant Likely u32 sz, noff; 127ca900cfaSGrant Likely const char *nstr; 128ca900cfaSGrant Likely 129ca900cfaSGrant Likely p += 4; 130ca900cfaSGrant Likely if (tag == OF_DT_NOP) 131ca900cfaSGrant Likely continue; 132ca900cfaSGrant Likely if (tag != OF_DT_PROP) 133ca900cfaSGrant Likely return NULL; 134ca900cfaSGrant Likely 135ca900cfaSGrant Likely sz = *((u32 *)p); 136ca900cfaSGrant Likely noff = *((u32 *)(p + 4)); 137ca900cfaSGrant Likely p += 8; 138ca900cfaSGrant Likely if (initial_boot_params->version < 0x10) 139ca900cfaSGrant Likely p = _ALIGN(p, sz >= 8 ? 8 : 4); 140ca900cfaSGrant Likely 141ca900cfaSGrant Likely nstr = find_flat_dt_string(noff); 142ca900cfaSGrant Likely if (nstr == NULL) { 143ca900cfaSGrant Likely pr_warning("Can't find property index name !\n"); 144ca900cfaSGrant Likely return NULL; 145ca900cfaSGrant Likely } 146ca900cfaSGrant Likely if (strcmp(name, nstr) == 0) { 147ca900cfaSGrant Likely if (size) 148ca900cfaSGrant Likely *size = sz; 149ca900cfaSGrant Likely return (void *)p; 150ca900cfaSGrant Likely } 151ca900cfaSGrant Likely p += sz; 152ca900cfaSGrant Likely p = _ALIGN(p, 4); 153ca900cfaSGrant Likely } while (1); 154ca900cfaSGrant Likely } 155ca900cfaSGrant Likely 15600e38efdSGrant Likely /** 15700e38efdSGrant Likely * of_flat_dt_is_compatible - Return true if given node has compat in compatible list 15800e38efdSGrant Likely * @node: node to test 15900e38efdSGrant Likely * @compat: compatible string to compare with compatible list. 16000e38efdSGrant Likely */ 16100e38efdSGrant Likely int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) 16200e38efdSGrant Likely { 16300e38efdSGrant Likely const char *cp; 16400e38efdSGrant Likely unsigned long cplen, l; 16500e38efdSGrant Likely 16600e38efdSGrant Likely cp = of_get_flat_dt_prop(node, "compatible", &cplen); 16700e38efdSGrant Likely if (cp == NULL) 16800e38efdSGrant Likely return 0; 16900e38efdSGrant Likely while (cplen > 0) { 17000e38efdSGrant Likely if (strncasecmp(cp, compat, strlen(compat)) == 0) 17100e38efdSGrant Likely return 1; 17200e38efdSGrant Likely l = strlen(cp) + 1; 17300e38efdSGrant Likely cp += l; 17400e38efdSGrant Likely cplen -= l; 17500e38efdSGrant Likely } 17600e38efdSGrant Likely 17700e38efdSGrant Likely return 0; 17800e38efdSGrant Likely } 17900e38efdSGrant Likely 180bbd33931SGrant Likely static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, 181bbd33931SGrant Likely unsigned long align) 182bbd33931SGrant Likely { 183bbd33931SGrant Likely void *res; 184bbd33931SGrant Likely 185bbd33931SGrant Likely *mem = _ALIGN(*mem, align); 186bbd33931SGrant Likely res = (void *)*mem; 187bbd33931SGrant Likely *mem += size; 188bbd33931SGrant Likely 189bbd33931SGrant Likely return res; 190bbd33931SGrant Likely } 191bbd33931SGrant Likely 192bbd33931SGrant Likely /** 193bbd33931SGrant Likely * unflatten_dt_node - Alloc and populate a device_node from the flat tree 194bbd33931SGrant Likely * @p: pointer to node in flat tree 195bbd33931SGrant Likely * @dad: Parent struct device_node 196bbd33931SGrant Likely * @allnextpp: pointer to ->allnext from last allocated device_node 197bbd33931SGrant Likely * @fpsize: Size of the node path up at the current depth. 198bbd33931SGrant Likely */ 199bbd33931SGrant Likely unsigned long __init unflatten_dt_node(unsigned long mem, 200bbd33931SGrant Likely unsigned long *p, 201bbd33931SGrant Likely struct device_node *dad, 202bbd33931SGrant Likely struct device_node ***allnextpp, 203bbd33931SGrant Likely unsigned long fpsize) 204bbd33931SGrant Likely { 205bbd33931SGrant Likely struct device_node *np; 206bbd33931SGrant Likely struct property *pp, **prev_pp = NULL; 207bbd33931SGrant Likely char *pathp; 208bbd33931SGrant Likely u32 tag; 209bbd33931SGrant Likely unsigned int l, allocl; 210bbd33931SGrant Likely int has_name = 0; 211bbd33931SGrant Likely int new_format = 0; 212bbd33931SGrant Likely 213bbd33931SGrant Likely tag = *((u32 *)(*p)); 214bbd33931SGrant Likely if (tag != OF_DT_BEGIN_NODE) { 215bbd33931SGrant Likely pr_err("Weird tag at start of node: %x\n", tag); 216bbd33931SGrant Likely return mem; 217bbd33931SGrant Likely } 218bbd33931SGrant Likely *p += 4; 219bbd33931SGrant Likely pathp = (char *)*p; 220bbd33931SGrant Likely l = allocl = strlen(pathp) + 1; 221bbd33931SGrant Likely *p = _ALIGN(*p + l, 4); 222bbd33931SGrant Likely 223bbd33931SGrant Likely /* version 0x10 has a more compact unit name here instead of the full 224bbd33931SGrant Likely * path. we accumulate the full path size using "fpsize", we'll rebuild 225bbd33931SGrant Likely * it later. We detect this because the first character of the name is 226bbd33931SGrant Likely * not '/'. 227bbd33931SGrant Likely */ 228bbd33931SGrant Likely if ((*pathp) != '/') { 229bbd33931SGrant Likely new_format = 1; 230bbd33931SGrant Likely if (fpsize == 0) { 231bbd33931SGrant Likely /* root node: special case. fpsize accounts for path 232bbd33931SGrant Likely * plus terminating zero. root node only has '/', so 233bbd33931SGrant Likely * fpsize should be 2, but we want to avoid the first 234bbd33931SGrant Likely * level nodes to have two '/' so we use fpsize 1 here 235bbd33931SGrant Likely */ 236bbd33931SGrant Likely fpsize = 1; 237bbd33931SGrant Likely allocl = 2; 238bbd33931SGrant Likely } else { 239bbd33931SGrant Likely /* account for '/' and path size minus terminal 0 240bbd33931SGrant Likely * already in 'l' 241bbd33931SGrant Likely */ 242bbd33931SGrant Likely fpsize += l; 243bbd33931SGrant Likely allocl = fpsize; 244bbd33931SGrant Likely } 245bbd33931SGrant Likely } 246bbd33931SGrant Likely 247bbd33931SGrant Likely np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, 248bbd33931SGrant Likely __alignof__(struct device_node)); 249bbd33931SGrant Likely if (allnextpp) { 250bbd33931SGrant Likely memset(np, 0, sizeof(*np)); 251bbd33931SGrant Likely np->full_name = ((char *)np) + sizeof(struct device_node); 252bbd33931SGrant Likely if (new_format) { 253bbd33931SGrant Likely char *fn = np->full_name; 254bbd33931SGrant Likely /* rebuild full path for new format */ 255bbd33931SGrant Likely if (dad && dad->parent) { 256bbd33931SGrant Likely strcpy(fn, dad->full_name); 257bbd33931SGrant Likely #ifdef DEBUG 258bbd33931SGrant Likely if ((strlen(fn) + l + 1) != allocl) { 259bbd33931SGrant Likely pr_debug("%s: p: %d, l: %d, a: %d\n", 260bbd33931SGrant Likely pathp, (int)strlen(fn), 261bbd33931SGrant Likely l, allocl); 262bbd33931SGrant Likely } 263bbd33931SGrant Likely #endif 264bbd33931SGrant Likely fn += strlen(fn); 265bbd33931SGrant Likely } 266bbd33931SGrant Likely *(fn++) = '/'; 267bbd33931SGrant Likely memcpy(fn, pathp, l); 268bbd33931SGrant Likely } else 269bbd33931SGrant Likely memcpy(np->full_name, pathp, l); 270bbd33931SGrant Likely prev_pp = &np->properties; 271bbd33931SGrant Likely **allnextpp = np; 272bbd33931SGrant Likely *allnextpp = &np->allnext; 273bbd33931SGrant Likely if (dad != NULL) { 274bbd33931SGrant Likely np->parent = dad; 275bbd33931SGrant Likely /* we temporarily use the next field as `last_child'*/ 276bbd33931SGrant Likely if (dad->next == NULL) 277bbd33931SGrant Likely dad->child = np; 278bbd33931SGrant Likely else 279bbd33931SGrant Likely dad->next->sibling = np; 280bbd33931SGrant Likely dad->next = np; 281bbd33931SGrant Likely } 282bbd33931SGrant Likely kref_init(&np->kref); 283bbd33931SGrant Likely } 284bbd33931SGrant Likely while (1) { 285bbd33931SGrant Likely u32 sz, noff; 286bbd33931SGrant Likely char *pname; 287bbd33931SGrant Likely 288bbd33931SGrant Likely tag = *((u32 *)(*p)); 289bbd33931SGrant Likely if (tag == OF_DT_NOP) { 290bbd33931SGrant Likely *p += 4; 291bbd33931SGrant Likely continue; 292bbd33931SGrant Likely } 293bbd33931SGrant Likely if (tag != OF_DT_PROP) 294bbd33931SGrant Likely break; 295bbd33931SGrant Likely *p += 4; 296bbd33931SGrant Likely sz = *((u32 *)(*p)); 297bbd33931SGrant Likely noff = *((u32 *)((*p) + 4)); 298bbd33931SGrant Likely *p += 8; 299bbd33931SGrant Likely if (initial_boot_params->version < 0x10) 300bbd33931SGrant Likely *p = _ALIGN(*p, sz >= 8 ? 8 : 4); 301bbd33931SGrant Likely 302bbd33931SGrant Likely pname = find_flat_dt_string(noff); 303bbd33931SGrant Likely if (pname == NULL) { 304bbd33931SGrant Likely pr_info("Can't find property name in list !\n"); 305bbd33931SGrant Likely break; 306bbd33931SGrant Likely } 307bbd33931SGrant Likely if (strcmp(pname, "name") == 0) 308bbd33931SGrant Likely has_name = 1; 309bbd33931SGrant Likely l = strlen(pname) + 1; 310bbd33931SGrant Likely pp = unflatten_dt_alloc(&mem, sizeof(struct property), 311bbd33931SGrant Likely __alignof__(struct property)); 312bbd33931SGrant Likely if (allnextpp) { 313bbd33931SGrant Likely if (strcmp(pname, "linux,phandle") == 0) { 3146016a363SGrant Likely if (np->phandle == 0) 3156016a363SGrant Likely np->phandle = *((u32 *)*p); 316bbd33931SGrant Likely } 317bbd33931SGrant Likely if (strcmp(pname, "ibm,phandle") == 0) 3186016a363SGrant Likely np->phandle = *((u32 *)*p); 319bbd33931SGrant Likely pp->name = pname; 320bbd33931SGrant Likely pp->length = sz; 321bbd33931SGrant Likely pp->value = (void *)*p; 322bbd33931SGrant Likely *prev_pp = pp; 323bbd33931SGrant Likely prev_pp = &pp->next; 324bbd33931SGrant Likely } 325bbd33931SGrant Likely *p = _ALIGN((*p) + sz, 4); 326bbd33931SGrant Likely } 327bbd33931SGrant Likely /* with version 0x10 we may not have the name property, recreate 328bbd33931SGrant Likely * it here from the unit name if absent 329bbd33931SGrant Likely */ 330bbd33931SGrant Likely if (!has_name) { 331bbd33931SGrant Likely char *p1 = pathp, *ps = pathp, *pa = NULL; 332bbd33931SGrant Likely int sz; 333bbd33931SGrant Likely 334bbd33931SGrant Likely while (*p1) { 335bbd33931SGrant Likely if ((*p1) == '@') 336bbd33931SGrant Likely pa = p1; 337bbd33931SGrant Likely if ((*p1) == '/') 338bbd33931SGrant Likely ps = p1 + 1; 339bbd33931SGrant Likely p1++; 340bbd33931SGrant Likely } 341bbd33931SGrant Likely if (pa < ps) 342bbd33931SGrant Likely pa = p1; 343bbd33931SGrant Likely sz = (pa - ps) + 1; 344bbd33931SGrant Likely pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, 345bbd33931SGrant Likely __alignof__(struct property)); 346bbd33931SGrant Likely if (allnextpp) { 347bbd33931SGrant Likely pp->name = "name"; 348bbd33931SGrant Likely pp->length = sz; 349bbd33931SGrant Likely pp->value = pp + 1; 350bbd33931SGrant Likely *prev_pp = pp; 351bbd33931SGrant Likely prev_pp = &pp->next; 352bbd33931SGrant Likely memcpy(pp->value, ps, sz - 1); 353bbd33931SGrant Likely ((char *)pp->value)[sz - 1] = 0; 354bbd33931SGrant Likely pr_debug("fixed up name for %s -> %s\n", pathp, 355bbd33931SGrant Likely (char *)pp->value); 356bbd33931SGrant Likely } 357bbd33931SGrant Likely } 358bbd33931SGrant Likely if (allnextpp) { 359bbd33931SGrant Likely *prev_pp = NULL; 360bbd33931SGrant Likely np->name = of_get_property(np, "name", NULL); 361bbd33931SGrant Likely np->type = of_get_property(np, "device_type", NULL); 362bbd33931SGrant Likely 363bbd33931SGrant Likely if (!np->name) 364bbd33931SGrant Likely np->name = "<NULL>"; 365bbd33931SGrant Likely if (!np->type) 366bbd33931SGrant Likely np->type = "<NULL>"; 367bbd33931SGrant Likely } 368bbd33931SGrant Likely while (tag == OF_DT_BEGIN_NODE) { 369bbd33931SGrant Likely mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize); 370bbd33931SGrant Likely tag = *((u32 *)(*p)); 371bbd33931SGrant Likely } 372bbd33931SGrant Likely if (tag != OF_DT_END_NODE) { 373bbd33931SGrant Likely pr_err("Weird tag at end of node: %x\n", tag); 374bbd33931SGrant Likely return mem; 375bbd33931SGrant Likely } 376bbd33931SGrant Likely *p += 4; 377bbd33931SGrant Likely return mem; 378bbd33931SGrant Likely } 37941f88009SGrant Likely 380f7b3a835SGrant Likely #ifdef CONFIG_BLK_DEV_INITRD 381f7b3a835SGrant Likely /** 382f7b3a835SGrant Likely * early_init_dt_check_for_initrd - Decode initrd location from flat tree 383f7b3a835SGrant Likely * @node: reference to node containing initrd location ('chosen') 384f7b3a835SGrant Likely */ 385f7b3a835SGrant Likely void __init early_init_dt_check_for_initrd(unsigned long node) 386f7b3a835SGrant Likely { 3871406bc2fSJeremy Kerr unsigned long start, end, len; 388f7b3a835SGrant Likely u32 *prop; 389f7b3a835SGrant Likely 390f7b3a835SGrant Likely pr_debug("Looking for initrd properties... "); 391f7b3a835SGrant Likely 392f7b3a835SGrant Likely prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len); 3931406bc2fSJeremy Kerr if (!prop) 3941406bc2fSJeremy Kerr return; 3951406bc2fSJeremy Kerr start = of_read_ulong(prop, len/4); 396f7b3a835SGrant Likely 397f7b3a835SGrant Likely prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len); 3981406bc2fSJeremy Kerr if (!prop) 3991406bc2fSJeremy Kerr return; 4001406bc2fSJeremy Kerr end = of_read_ulong(prop, len/4); 401f7b3a835SGrant Likely 4021406bc2fSJeremy Kerr early_init_dt_setup_initrd_arch(start, end); 4031406bc2fSJeremy Kerr pr_debug("initrd_start=0x%lx initrd_end=0x%lx\n", start, end); 404f7b3a835SGrant Likely } 405f7b3a835SGrant Likely #else 406f7b3a835SGrant Likely inline void early_init_dt_check_for_initrd(unsigned long node) 407f7b3a835SGrant Likely { 408f7b3a835SGrant Likely } 409f7b3a835SGrant Likely #endif /* CONFIG_BLK_DEV_INITRD */ 410f7b3a835SGrant Likely 41141f88009SGrant Likely /** 412f00abd94SGrant Likely * early_init_dt_scan_root - fetch the top level address and size cells 413f00abd94SGrant Likely */ 414f00abd94SGrant Likely int __init early_init_dt_scan_root(unsigned long node, const char *uname, 415f00abd94SGrant Likely int depth, void *data) 416f00abd94SGrant Likely { 417f00abd94SGrant Likely u32 *prop; 418f00abd94SGrant Likely 419f00abd94SGrant Likely if (depth != 0) 420f00abd94SGrant Likely return 0; 421f00abd94SGrant Likely 422f00abd94SGrant Likely prop = of_get_flat_dt_prop(node, "#size-cells", NULL); 42336b9d307SJeremy Kerr dt_root_size_cells = prop ? *prop : OF_ROOT_NODE_SIZE_CELLS_DEFAULT; 424f00abd94SGrant Likely pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells); 425f00abd94SGrant Likely 426f00abd94SGrant Likely prop = of_get_flat_dt_prop(node, "#address-cells", NULL); 42736b9d307SJeremy Kerr dt_root_addr_cells = prop ? *prop : OF_ROOT_NODE_ADDR_CELLS_DEFAULT; 428f00abd94SGrant Likely pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells); 429f00abd94SGrant Likely 430f00abd94SGrant Likely /* break now */ 431f00abd94SGrant Likely return 1; 432f00abd94SGrant Likely } 433f00abd94SGrant Likely 43483f7a06eSGrant Likely u64 __init dt_mem_next_cell(int s, u32 **cellp) 43583f7a06eSGrant Likely { 43683f7a06eSGrant Likely u32 *p = *cellp; 43783f7a06eSGrant Likely 43883f7a06eSGrant Likely *cellp = p + s; 43983f7a06eSGrant Likely return of_read_number(p, s); 44083f7a06eSGrant Likely } 44183f7a06eSGrant Likely 44251975db0SGrant Likely /** 44351975db0SGrant Likely * early_init_dt_scan_memory - Look for an parse memory nodes 44451975db0SGrant Likely */ 44551975db0SGrant Likely int __init early_init_dt_scan_memory(unsigned long node, const char *uname, 44651975db0SGrant Likely int depth, void *data) 44751975db0SGrant Likely { 44851975db0SGrant Likely char *type = of_get_flat_dt_prop(node, "device_type", NULL); 44951975db0SGrant Likely __be32 *reg, *endp; 45051975db0SGrant Likely unsigned long l; 45151975db0SGrant Likely 45251975db0SGrant Likely /* We are scanning "memory" nodes only */ 45351975db0SGrant Likely if (type == NULL) { 45451975db0SGrant Likely /* 45551975db0SGrant Likely * The longtrail doesn't have a device_type on the 45651975db0SGrant Likely * /memory node, so look for the node called /memory@0. 45751975db0SGrant Likely */ 45851975db0SGrant Likely if (depth != 1 || strcmp(uname, "memory@0") != 0) 45951975db0SGrant Likely return 0; 46051975db0SGrant Likely } else if (strcmp(type, "memory") != 0) 46151975db0SGrant Likely return 0; 46251975db0SGrant Likely 46351975db0SGrant Likely reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l); 46451975db0SGrant Likely if (reg == NULL) 46551975db0SGrant Likely reg = of_get_flat_dt_prop(node, "reg", &l); 46651975db0SGrant Likely if (reg == NULL) 46751975db0SGrant Likely return 0; 46851975db0SGrant Likely 46951975db0SGrant Likely endp = reg + (l / sizeof(__be32)); 47051975db0SGrant Likely 47151975db0SGrant Likely pr_debug("memory scan node %s, reg size %ld, data: %x %x %x %x,\n", 47251975db0SGrant Likely uname, l, reg[0], reg[1], reg[2], reg[3]); 47351975db0SGrant Likely 47451975db0SGrant Likely while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { 47551975db0SGrant Likely u64 base, size; 47651975db0SGrant Likely 47751975db0SGrant Likely base = dt_mem_next_cell(dt_root_addr_cells, ®); 47851975db0SGrant Likely size = dt_mem_next_cell(dt_root_size_cells, ®); 47951975db0SGrant Likely 48051975db0SGrant Likely if (size == 0) 48151975db0SGrant Likely continue; 48251975db0SGrant Likely pr_debug(" - %llx , %llx\n", (unsigned long long)base, 48351975db0SGrant Likely (unsigned long long)size); 48451975db0SGrant Likely 48551975db0SGrant Likely early_init_dt_add_memory_arch(base, size); 48651975db0SGrant Likely } 48751975db0SGrant Likely 48851975db0SGrant Likely return 0; 48951975db0SGrant Likely } 49051975db0SGrant Likely 49186e03221SGrant Likely int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, 49286e03221SGrant Likely int depth, void *data) 49386e03221SGrant Likely { 49486e03221SGrant Likely unsigned long l; 49586e03221SGrant Likely char *p; 49686e03221SGrant Likely 49786e03221SGrant Likely pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname); 49886e03221SGrant Likely 49986e03221SGrant Likely if (depth != 1 || 50086e03221SGrant Likely (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0)) 50186e03221SGrant Likely return 0; 50286e03221SGrant Likely 50386e03221SGrant Likely early_init_dt_check_for_initrd(node); 50486e03221SGrant Likely 50586e03221SGrant Likely /* Retreive command line */ 50686e03221SGrant Likely p = of_get_flat_dt_prop(node, "bootargs", &l); 50786e03221SGrant Likely if (p != NULL && l > 0) 50886e03221SGrant Likely strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE)); 50986e03221SGrant Likely 51086e03221SGrant Likely #ifdef CONFIG_CMDLINE 51186e03221SGrant Likely #ifndef CONFIG_CMDLINE_FORCE 51286e03221SGrant Likely if (p == NULL || l == 0 || (l == 1 && (*p) == 0)) 51386e03221SGrant Likely #endif 51486e03221SGrant Likely strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); 51586e03221SGrant Likely #endif /* CONFIG_CMDLINE */ 51686e03221SGrant Likely 51786e03221SGrant Likely early_init_dt_scan_chosen_arch(node); 51886e03221SGrant Likely 51986e03221SGrant Likely pr_debug("Command line is: %s\n", cmd_line); 52086e03221SGrant Likely 52186e03221SGrant Likely /* break now */ 52286e03221SGrant Likely return 1; 52386e03221SGrant Likely } 52486e03221SGrant Likely 525f00abd94SGrant Likely /** 52641f88009SGrant Likely * unflatten_device_tree - create tree of device_nodes from flat blob 52741f88009SGrant Likely * 52841f88009SGrant Likely * unflattens the device-tree passed by the firmware, creating the 52941f88009SGrant Likely * tree of struct device_node. It also fills the "name" and "type" 53041f88009SGrant Likely * pointers of the nodes so the normal device-tree walking functions 53141f88009SGrant Likely * can be used. 53241f88009SGrant Likely */ 53341f88009SGrant Likely void __init unflatten_device_tree(void) 53441f88009SGrant Likely { 53541f88009SGrant Likely unsigned long start, mem, size; 53641f88009SGrant Likely struct device_node **allnextp = &allnodes; 53741f88009SGrant Likely 53841f88009SGrant Likely pr_debug(" -> unflatten_device_tree()\n"); 53941f88009SGrant Likely 54041f88009SGrant Likely /* First pass, scan for size */ 54141f88009SGrant Likely start = ((unsigned long)initial_boot_params) + 54241f88009SGrant Likely initial_boot_params->off_dt_struct; 54341f88009SGrant Likely size = unflatten_dt_node(0, &start, NULL, NULL, 0); 54441f88009SGrant Likely size = (size | 3) + 1; 54541f88009SGrant Likely 54641f88009SGrant Likely pr_debug(" size is %lx, allocating...\n", size); 54741f88009SGrant Likely 54841f88009SGrant Likely /* Allocate memory for the expanded device tree */ 54941f88009SGrant Likely mem = lmb_alloc(size + 4, __alignof__(struct device_node)); 55041f88009SGrant Likely mem = (unsigned long) __va(mem); 55141f88009SGrant Likely 55241f88009SGrant Likely ((u32 *)mem)[size / 4] = 0xdeadbeef; 55341f88009SGrant Likely 55441f88009SGrant Likely pr_debug(" unflattening %lx...\n", mem); 55541f88009SGrant Likely 55641f88009SGrant Likely /* Second pass, do actual unflattening */ 55741f88009SGrant Likely start = ((unsigned long)initial_boot_params) + 55841f88009SGrant Likely initial_boot_params->off_dt_struct; 55941f88009SGrant Likely unflatten_dt_node(mem, &start, NULL, &allnextp, 0); 56041f88009SGrant Likely if (*((u32 *)start) != OF_DT_END) 56141f88009SGrant Likely pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start)); 56241f88009SGrant Likely if (((u32 *)mem)[size / 4] != 0xdeadbeef) 56341f88009SGrant Likely pr_warning("End of tree marker overwritten: %08x\n", 56441f88009SGrant Likely ((u32 *)mem)[size / 4]); 56541f88009SGrant Likely *allnextp = NULL; 56641f88009SGrant Likely 56741f88009SGrant Likely /* Get pointer to OF "/chosen" node for use everywhere */ 56841f88009SGrant Likely of_chosen = of_find_node_by_path("/chosen"); 56941f88009SGrant Likely if (of_chosen == NULL) 57041f88009SGrant Likely of_chosen = of_find_node_by_path("/chosen@0"); 57141f88009SGrant Likely 57241f88009SGrant Likely pr_debug(" <- unflatten_device_tree()\n"); 57341f88009SGrant Likely } 574