1*8b50d526SSimon Glass /* 2*8b50d526SSimon Glass * Copyright 2009 Benjamin Herrenschmidt, IBM Corp 3*8b50d526SSimon Glass * benh@kernel.crashing.org 4*8b50d526SSimon Glass * 5*8b50d526SSimon Glass * Based on parts of drivers/of/fdt.c from Linux v4.9 6*8b50d526SSimon Glass * Modifications for U-Boot 7*8b50d526SSimon Glass * Copyright (c) 2017 Google, Inc 8*8b50d526SSimon Glass * 9*8b50d526SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 10*8b50d526SSimon Glass */ 11*8b50d526SSimon Glass 12*8b50d526SSimon Glass #include <common.h> 13*8b50d526SSimon Glass #include <libfdt.h> 14*8b50d526SSimon Glass #include <of_live.h> 15*8b50d526SSimon Glass #include <malloc.h> 16*8b50d526SSimon Glass #include <dm/of_access.h> 17*8b50d526SSimon Glass #include <linux/err.h> 18*8b50d526SSimon Glass 19*8b50d526SSimon Glass DECLARE_GLOBAL_DATA_PTR; 20*8b50d526SSimon Glass 21*8b50d526SSimon Glass static void *unflatten_dt_alloc(void **mem, unsigned long size, 22*8b50d526SSimon Glass unsigned long align) 23*8b50d526SSimon Glass { 24*8b50d526SSimon Glass void *res; 25*8b50d526SSimon Glass 26*8b50d526SSimon Glass *mem = PTR_ALIGN(*mem, align); 27*8b50d526SSimon Glass res = *mem; 28*8b50d526SSimon Glass *mem += size; 29*8b50d526SSimon Glass 30*8b50d526SSimon Glass return res; 31*8b50d526SSimon Glass } 32*8b50d526SSimon Glass 33*8b50d526SSimon Glass /** 34*8b50d526SSimon Glass * unflatten_dt_node() - Alloc and populate a device_node from the flat tree 35*8b50d526SSimon Glass * @blob: The parent device tree blob 36*8b50d526SSimon Glass * @mem: Memory chunk to use for allocating device nodes and properties 37*8b50d526SSimon Glass * @poffset: pointer to node in flat tree 38*8b50d526SSimon Glass * @dad: Parent struct device_node 39*8b50d526SSimon Glass * @nodepp: The device_node tree created by the call 40*8b50d526SSimon Glass * @fpsize: Size of the node path up at t05he current depth. 41*8b50d526SSimon Glass * @dryrun: If true, do not allocate device nodes but still calculate needed 42*8b50d526SSimon Glass * memory size 43*8b50d526SSimon Glass */ 44*8b50d526SSimon Glass static void *unflatten_dt_node(const void *blob, void *mem, int *poffset, 45*8b50d526SSimon Glass struct device_node *dad, 46*8b50d526SSimon Glass struct device_node **nodepp, 47*8b50d526SSimon Glass unsigned long fpsize, bool dryrun) 48*8b50d526SSimon Glass { 49*8b50d526SSimon Glass const __be32 *p; 50*8b50d526SSimon Glass struct device_node *np; 51*8b50d526SSimon Glass struct property *pp, **prev_pp = NULL; 52*8b50d526SSimon Glass const char *pathp; 53*8b50d526SSimon Glass int l; 54*8b50d526SSimon Glass unsigned int allocl; 55*8b50d526SSimon Glass static int depth; 56*8b50d526SSimon Glass int old_depth; 57*8b50d526SSimon Glass int offset; 58*8b50d526SSimon Glass int has_name = 0; 59*8b50d526SSimon Glass int new_format = 0; 60*8b50d526SSimon Glass 61*8b50d526SSimon Glass pathp = fdt_get_name(blob, *poffset, &l); 62*8b50d526SSimon Glass if (!pathp) 63*8b50d526SSimon Glass return mem; 64*8b50d526SSimon Glass 65*8b50d526SSimon Glass allocl = ++l; 66*8b50d526SSimon Glass 67*8b50d526SSimon Glass /* 68*8b50d526SSimon Glass * version 0x10 has a more compact unit name here instead of the full 69*8b50d526SSimon Glass * path. we accumulate the full path size using "fpsize", we'll rebuild 70*8b50d526SSimon Glass * it later. We detect this because the first character of the name is 71*8b50d526SSimon Glass * not '/'. 72*8b50d526SSimon Glass */ 73*8b50d526SSimon Glass if ((*pathp) != '/') { 74*8b50d526SSimon Glass new_format = 1; 75*8b50d526SSimon Glass if (fpsize == 0) { 76*8b50d526SSimon Glass /* 77*8b50d526SSimon Glass * root node: special case. fpsize accounts for path 78*8b50d526SSimon Glass * plus terminating zero. root node only has '/', so 79*8b50d526SSimon Glass * fpsize should be 2, but we want to avoid the first 80*8b50d526SSimon Glass * level nodes to have two '/' so we use fpsize 1 here 81*8b50d526SSimon Glass */ 82*8b50d526SSimon Glass fpsize = 1; 83*8b50d526SSimon Glass allocl = 2; 84*8b50d526SSimon Glass l = 1; 85*8b50d526SSimon Glass pathp = ""; 86*8b50d526SSimon Glass } else { 87*8b50d526SSimon Glass /* 88*8b50d526SSimon Glass * account for '/' and path size minus terminal 0 89*8b50d526SSimon Glass * already in 'l' 90*8b50d526SSimon Glass */ 91*8b50d526SSimon Glass fpsize += l; 92*8b50d526SSimon Glass allocl = fpsize; 93*8b50d526SSimon Glass } 94*8b50d526SSimon Glass } 95*8b50d526SSimon Glass 96*8b50d526SSimon Glass np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, 97*8b50d526SSimon Glass __alignof__(struct device_node)); 98*8b50d526SSimon Glass if (!dryrun) { 99*8b50d526SSimon Glass char *fn; 100*8b50d526SSimon Glass 101*8b50d526SSimon Glass fn = (char *)np + sizeof(*np); 102*8b50d526SSimon Glass np->full_name = fn; 103*8b50d526SSimon Glass if (new_format) { 104*8b50d526SSimon Glass /* rebuild full path for new format */ 105*8b50d526SSimon Glass if (dad && dad->parent) { 106*8b50d526SSimon Glass strcpy(fn, dad->full_name); 107*8b50d526SSimon Glass #ifdef DEBUG 108*8b50d526SSimon Glass if ((strlen(fn) + l + 1) != allocl) { 109*8b50d526SSimon Glass debug("%s: p: %d, l: %d, a: %d\n", 110*8b50d526SSimon Glass pathp, (int)strlen(fn), l, 111*8b50d526SSimon Glass allocl); 112*8b50d526SSimon Glass } 113*8b50d526SSimon Glass #endif 114*8b50d526SSimon Glass fn += strlen(fn); 115*8b50d526SSimon Glass } 116*8b50d526SSimon Glass *(fn++) = '/'; 117*8b50d526SSimon Glass } 118*8b50d526SSimon Glass memcpy(fn, pathp, l); 119*8b50d526SSimon Glass 120*8b50d526SSimon Glass prev_pp = &np->properties; 121*8b50d526SSimon Glass if (dad != NULL) { 122*8b50d526SSimon Glass np->parent = dad; 123*8b50d526SSimon Glass np->sibling = dad->child; 124*8b50d526SSimon Glass dad->child = np; 125*8b50d526SSimon Glass } 126*8b50d526SSimon Glass } 127*8b50d526SSimon Glass /* process properties */ 128*8b50d526SSimon Glass for (offset = fdt_first_property_offset(blob, *poffset); 129*8b50d526SSimon Glass (offset >= 0); 130*8b50d526SSimon Glass (offset = fdt_next_property_offset(blob, offset))) { 131*8b50d526SSimon Glass const char *pname; 132*8b50d526SSimon Glass int sz; 133*8b50d526SSimon Glass 134*8b50d526SSimon Glass p = fdt_getprop_by_offset(blob, offset, &pname, &sz); 135*8b50d526SSimon Glass if (!p) { 136*8b50d526SSimon Glass offset = -FDT_ERR_INTERNAL; 137*8b50d526SSimon Glass break; 138*8b50d526SSimon Glass } 139*8b50d526SSimon Glass 140*8b50d526SSimon Glass if (pname == NULL) { 141*8b50d526SSimon Glass debug("Can't find property name in list !\n"); 142*8b50d526SSimon Glass break; 143*8b50d526SSimon Glass } 144*8b50d526SSimon Glass if (strcmp(pname, "name") == 0) 145*8b50d526SSimon Glass has_name = 1; 146*8b50d526SSimon Glass pp = unflatten_dt_alloc(&mem, sizeof(struct property), 147*8b50d526SSimon Glass __alignof__(struct property)); 148*8b50d526SSimon Glass if (!dryrun) { 149*8b50d526SSimon Glass /* 150*8b50d526SSimon Glass * We accept flattened tree phandles either in 151*8b50d526SSimon Glass * ePAPR-style "phandle" properties, or the 152*8b50d526SSimon Glass * legacy "linux,phandle" properties. If both 153*8b50d526SSimon Glass * appear and have different values, things 154*8b50d526SSimon Glass * will get weird. Don't do that. */ 155*8b50d526SSimon Glass if ((strcmp(pname, "phandle") == 0) || 156*8b50d526SSimon Glass (strcmp(pname, "linux,phandle") == 0)) { 157*8b50d526SSimon Glass if (np->phandle == 0) 158*8b50d526SSimon Glass np->phandle = be32_to_cpup(p); 159*8b50d526SSimon Glass } 160*8b50d526SSimon Glass /* 161*8b50d526SSimon Glass * And we process the "ibm,phandle" property 162*8b50d526SSimon Glass * used in pSeries dynamic device tree 163*8b50d526SSimon Glass * stuff */ 164*8b50d526SSimon Glass if (strcmp(pname, "ibm,phandle") == 0) 165*8b50d526SSimon Glass np->phandle = be32_to_cpup(p); 166*8b50d526SSimon Glass pp->name = (char *)pname; 167*8b50d526SSimon Glass pp->length = sz; 168*8b50d526SSimon Glass pp->value = (__be32 *)p; 169*8b50d526SSimon Glass *prev_pp = pp; 170*8b50d526SSimon Glass prev_pp = &pp->next; 171*8b50d526SSimon Glass } 172*8b50d526SSimon Glass } 173*8b50d526SSimon Glass /* 174*8b50d526SSimon Glass * with version 0x10 we may not have the name property, recreate 175*8b50d526SSimon Glass * it here from the unit name if absent 176*8b50d526SSimon Glass */ 177*8b50d526SSimon Glass if (!has_name) { 178*8b50d526SSimon Glass const char *p1 = pathp, *ps = pathp, *pa = NULL; 179*8b50d526SSimon Glass int sz; 180*8b50d526SSimon Glass 181*8b50d526SSimon Glass while (*p1) { 182*8b50d526SSimon Glass if ((*p1) == '@') 183*8b50d526SSimon Glass pa = p1; 184*8b50d526SSimon Glass if ((*p1) == '/') 185*8b50d526SSimon Glass ps = p1 + 1; 186*8b50d526SSimon Glass p1++; 187*8b50d526SSimon Glass } 188*8b50d526SSimon Glass if (pa < ps) 189*8b50d526SSimon Glass pa = p1; 190*8b50d526SSimon Glass sz = (pa - ps) + 1; 191*8b50d526SSimon Glass pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, 192*8b50d526SSimon Glass __alignof__(struct property)); 193*8b50d526SSimon Glass if (!dryrun) { 194*8b50d526SSimon Glass pp->name = "name"; 195*8b50d526SSimon Glass pp->length = sz; 196*8b50d526SSimon Glass pp->value = pp + 1; 197*8b50d526SSimon Glass *prev_pp = pp; 198*8b50d526SSimon Glass prev_pp = &pp->next; 199*8b50d526SSimon Glass memcpy(pp->value, ps, sz - 1); 200*8b50d526SSimon Glass ((char *)pp->value)[sz - 1] = 0; 201*8b50d526SSimon Glass debug("fixed up name for %s -> %s\n", pathp, 202*8b50d526SSimon Glass (char *)pp->value); 203*8b50d526SSimon Glass } 204*8b50d526SSimon Glass } 205*8b50d526SSimon Glass if (!dryrun) { 206*8b50d526SSimon Glass *prev_pp = NULL; 207*8b50d526SSimon Glass np->name = of_get_property(np, "name", NULL); 208*8b50d526SSimon Glass np->type = of_get_property(np, "device_type", NULL); 209*8b50d526SSimon Glass 210*8b50d526SSimon Glass if (!np->name) 211*8b50d526SSimon Glass np->name = "<NULL>"; 212*8b50d526SSimon Glass if (!np->type) 213*8b50d526SSimon Glass np->type = "<NULL>"; } 214*8b50d526SSimon Glass 215*8b50d526SSimon Glass old_depth = depth; 216*8b50d526SSimon Glass *poffset = fdt_next_node(blob, *poffset, &depth); 217*8b50d526SSimon Glass if (depth < 0) 218*8b50d526SSimon Glass depth = 0; 219*8b50d526SSimon Glass while (*poffset > 0 && depth > old_depth) 220*8b50d526SSimon Glass mem = unflatten_dt_node(blob, mem, poffset, np, NULL, 221*8b50d526SSimon Glass fpsize, dryrun); 222*8b50d526SSimon Glass 223*8b50d526SSimon Glass if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND) { 224*8b50d526SSimon Glass debug("unflatten: error %d processing FDT\n", *poffset); 225*8b50d526SSimon Glass return NULL; 226*8b50d526SSimon Glass } 227*8b50d526SSimon Glass 228*8b50d526SSimon Glass /* 229*8b50d526SSimon Glass * Reverse the child list. Some drivers assumes node order matches .dts 230*8b50d526SSimon Glass * node order 231*8b50d526SSimon Glass */ 232*8b50d526SSimon Glass if (!dryrun && np->child) { 233*8b50d526SSimon Glass struct device_node *child = np->child; 234*8b50d526SSimon Glass np->child = NULL; 235*8b50d526SSimon Glass while (child) { 236*8b50d526SSimon Glass struct device_node *next = child->sibling; 237*8b50d526SSimon Glass 238*8b50d526SSimon Glass child->sibling = np->child; 239*8b50d526SSimon Glass np->child = child; 240*8b50d526SSimon Glass child = next; 241*8b50d526SSimon Glass } 242*8b50d526SSimon Glass } 243*8b50d526SSimon Glass 244*8b50d526SSimon Glass if (nodepp) 245*8b50d526SSimon Glass *nodepp = np; 246*8b50d526SSimon Glass 247*8b50d526SSimon Glass return mem; 248*8b50d526SSimon Glass } 249*8b50d526SSimon Glass 250*8b50d526SSimon Glass /** 251*8b50d526SSimon Glass * unflatten_device_tree() - create tree of device_nodes from flat blob 252*8b50d526SSimon Glass * 253*8b50d526SSimon Glass * unflattens a device-tree, creating the 254*8b50d526SSimon Glass * tree of struct device_node. It also fills the "name" and "type" 255*8b50d526SSimon Glass * pointers of the nodes so the normal device-tree walking functions 256*8b50d526SSimon Glass * can be used. 257*8b50d526SSimon Glass * @blob: The blob to expand 258*8b50d526SSimon Glass * @mynodes: The device_node tree created by the call 259*8b50d526SSimon Glass * @return 0 if OK, -ve on error 260*8b50d526SSimon Glass */ 261*8b50d526SSimon Glass static int unflatten_device_tree(const void *blob, 262*8b50d526SSimon Glass struct device_node **mynodes) 263*8b50d526SSimon Glass { 264*8b50d526SSimon Glass unsigned long size; 265*8b50d526SSimon Glass int start; 266*8b50d526SSimon Glass void *mem; 267*8b50d526SSimon Glass 268*8b50d526SSimon Glass debug(" -> unflatten_device_tree()\n"); 269*8b50d526SSimon Glass 270*8b50d526SSimon Glass if (!blob) { 271*8b50d526SSimon Glass debug("No device tree pointer\n"); 272*8b50d526SSimon Glass return -EINVAL; 273*8b50d526SSimon Glass } 274*8b50d526SSimon Glass 275*8b50d526SSimon Glass debug("Unflattening device tree:\n"); 276*8b50d526SSimon Glass debug("magic: %08x\n", fdt_magic(blob)); 277*8b50d526SSimon Glass debug("size: %08x\n", fdt_totalsize(blob)); 278*8b50d526SSimon Glass debug("version: %08x\n", fdt_version(blob)); 279*8b50d526SSimon Glass 280*8b50d526SSimon Glass if (fdt_check_header(blob)) { 281*8b50d526SSimon Glass debug("Invalid device tree blob header\n"); 282*8b50d526SSimon Glass return -EINVAL; 283*8b50d526SSimon Glass } 284*8b50d526SSimon Glass 285*8b50d526SSimon Glass /* First pass, scan for size */ 286*8b50d526SSimon Glass start = 0; 287*8b50d526SSimon Glass size = (unsigned long)unflatten_dt_node(blob, NULL, &start, NULL, NULL, 288*8b50d526SSimon Glass 0, true); 289*8b50d526SSimon Glass size = ALIGN(size, 4); 290*8b50d526SSimon Glass 291*8b50d526SSimon Glass debug(" size is %lx, allocating...\n", size); 292*8b50d526SSimon Glass 293*8b50d526SSimon Glass /* Allocate memory for the expanded device tree */ 294*8b50d526SSimon Glass mem = malloc(size + 4); 295*8b50d526SSimon Glass memset(mem, '\0', size); 296*8b50d526SSimon Glass 297*8b50d526SSimon Glass *(__be32 *)(mem + size) = cpu_to_be32(0xdeadbeef); 298*8b50d526SSimon Glass 299*8b50d526SSimon Glass debug(" unflattening %p...\n", mem); 300*8b50d526SSimon Glass 301*8b50d526SSimon Glass /* Second pass, do actual unflattening */ 302*8b50d526SSimon Glass start = 0; 303*8b50d526SSimon Glass unflatten_dt_node(blob, mem, &start, NULL, mynodes, 0, false); 304*8b50d526SSimon Glass if (be32_to_cpup(mem + size) != 0xdeadbeef) { 305*8b50d526SSimon Glass debug("End of tree marker overwritten: %08x\n", 306*8b50d526SSimon Glass be32_to_cpup(mem + size)); 307*8b50d526SSimon Glass return -ENOSPC; 308*8b50d526SSimon Glass } 309*8b50d526SSimon Glass 310*8b50d526SSimon Glass debug(" <- unflatten_device_tree()\n"); 311*8b50d526SSimon Glass 312*8b50d526SSimon Glass return 0; 313*8b50d526SSimon Glass } 314*8b50d526SSimon Glass 315*8b50d526SSimon Glass int of_live_build(const void *fdt_blob, struct device_node **rootp) 316*8b50d526SSimon Glass { 317*8b50d526SSimon Glass int ret; 318*8b50d526SSimon Glass 319*8b50d526SSimon Glass debug("%s: start\n", __func__); 320*8b50d526SSimon Glass ret = unflatten_device_tree(fdt_blob, rootp); 321*8b50d526SSimon Glass if (ret) { 322*8b50d526SSimon Glass debug("Failed to create live tree: err=%d\n", ret); 323*8b50d526SSimon Glass return ret; 324*8b50d526SSimon Glass } 325*8b50d526SSimon Glass ret = of_alias_scan(); 326*8b50d526SSimon Glass if (ret) { 327*8b50d526SSimon Glass debug("Failed to scan live tree aliases: err=%d\n", ret); 328*8b50d526SSimon Glass return ret; 329*8b50d526SSimon Glass } 330*8b50d526SSimon Glass debug("%s: stop\n", __func__); 331*8b50d526SSimon Glass 332*8b50d526SSimon Glass return ret; 333*8b50d526SSimon Glass } 334