18b50d526SSimon Glass /* 28b50d526SSimon Glass * Copyright 2009 Benjamin Herrenschmidt, IBM Corp 38b50d526SSimon Glass * benh@kernel.crashing.org 48b50d526SSimon Glass * 58b50d526SSimon Glass * Based on parts of drivers/of/fdt.c from Linux v4.9 68b50d526SSimon Glass * Modifications for U-Boot 78b50d526SSimon Glass * Copyright (c) 2017 Google, Inc 88b50d526SSimon Glass * 98b50d526SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 108b50d526SSimon Glass */ 118b50d526SSimon Glass 128b50d526SSimon Glass #include <common.h> 138b50d526SSimon Glass #include <libfdt.h> 148b50d526SSimon Glass #include <of_live.h> 158b50d526SSimon Glass #include <malloc.h> 168b50d526SSimon Glass #include <dm/of_access.h> 178b50d526SSimon Glass #include <linux/err.h> 188b50d526SSimon Glass 198b50d526SSimon Glass DECLARE_GLOBAL_DATA_PTR; 208b50d526SSimon Glass 218b50d526SSimon Glass static void *unflatten_dt_alloc(void **mem, unsigned long size, 228b50d526SSimon Glass unsigned long align) 238b50d526SSimon Glass { 248b50d526SSimon Glass void *res; 258b50d526SSimon Glass 268b50d526SSimon Glass *mem = PTR_ALIGN(*mem, align); 278b50d526SSimon Glass res = *mem; 288b50d526SSimon Glass *mem += size; 298b50d526SSimon Glass 308b50d526SSimon Glass return res; 318b50d526SSimon Glass } 328b50d526SSimon Glass 338b50d526SSimon Glass /** 348b50d526SSimon Glass * unflatten_dt_node() - Alloc and populate a device_node from the flat tree 358b50d526SSimon Glass * @blob: The parent device tree blob 368b50d526SSimon Glass * @mem: Memory chunk to use for allocating device nodes and properties 378b50d526SSimon Glass * @poffset: pointer to node in flat tree 388b50d526SSimon Glass * @dad: Parent struct device_node 398b50d526SSimon Glass * @nodepp: The device_node tree created by the call 408b50d526SSimon Glass * @fpsize: Size of the node path up at t05he current depth. 418b50d526SSimon Glass * @dryrun: If true, do not allocate device nodes but still calculate needed 428b50d526SSimon Glass * memory size 438b50d526SSimon Glass */ 448b50d526SSimon Glass static void *unflatten_dt_node(const void *blob, void *mem, int *poffset, 458b50d526SSimon Glass struct device_node *dad, 468b50d526SSimon Glass struct device_node **nodepp, 478b50d526SSimon Glass unsigned long fpsize, bool dryrun) 488b50d526SSimon Glass { 498b50d526SSimon Glass const __be32 *p; 508b50d526SSimon Glass struct device_node *np; 518b50d526SSimon Glass struct property *pp, **prev_pp = NULL; 528b50d526SSimon Glass const char *pathp; 538b50d526SSimon Glass int l; 548b50d526SSimon Glass unsigned int allocl; 558b50d526SSimon Glass static int depth; 568b50d526SSimon Glass int old_depth; 578b50d526SSimon Glass int offset; 588b50d526SSimon Glass int has_name = 0; 598b50d526SSimon Glass int new_format = 0; 608b50d526SSimon Glass 618b50d526SSimon Glass pathp = fdt_get_name(blob, *poffset, &l); 628b50d526SSimon Glass if (!pathp) 638b50d526SSimon Glass return mem; 648b50d526SSimon Glass 658b50d526SSimon Glass allocl = ++l; 668b50d526SSimon Glass 678b50d526SSimon Glass /* 688b50d526SSimon Glass * version 0x10 has a more compact unit name here instead of the full 698b50d526SSimon Glass * path. we accumulate the full path size using "fpsize", we'll rebuild 708b50d526SSimon Glass * it later. We detect this because the first character of the name is 718b50d526SSimon Glass * not '/'. 728b50d526SSimon Glass */ 738b50d526SSimon Glass if ((*pathp) != '/') { 748b50d526SSimon Glass new_format = 1; 758b50d526SSimon Glass if (fpsize == 0) { 768b50d526SSimon Glass /* 778b50d526SSimon Glass * root node: special case. fpsize accounts for path 788b50d526SSimon Glass * plus terminating zero. root node only has '/', so 798b50d526SSimon Glass * fpsize should be 2, but we want to avoid the first 808b50d526SSimon Glass * level nodes to have two '/' so we use fpsize 1 here 818b50d526SSimon Glass */ 828b50d526SSimon Glass fpsize = 1; 838b50d526SSimon Glass allocl = 2; 848b50d526SSimon Glass l = 1; 858b50d526SSimon Glass pathp = ""; 868b50d526SSimon Glass } else { 878b50d526SSimon Glass /* 888b50d526SSimon Glass * account for '/' and path size minus terminal 0 898b50d526SSimon Glass * already in 'l' 908b50d526SSimon Glass */ 918b50d526SSimon Glass fpsize += l; 928b50d526SSimon Glass allocl = fpsize; 938b50d526SSimon Glass } 948b50d526SSimon Glass } 958b50d526SSimon Glass 968b50d526SSimon Glass np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, 978b50d526SSimon Glass __alignof__(struct device_node)); 988b50d526SSimon Glass if (!dryrun) { 998b50d526SSimon Glass char *fn; 1008b50d526SSimon Glass 1018b50d526SSimon Glass fn = (char *)np + sizeof(*np); 1028b50d526SSimon Glass np->full_name = fn; 1038b50d526SSimon Glass if (new_format) { 1048b50d526SSimon Glass /* rebuild full path for new format */ 1058b50d526SSimon Glass if (dad && dad->parent) { 1068b50d526SSimon Glass strcpy(fn, dad->full_name); 1078b50d526SSimon Glass #ifdef DEBUG 1088b50d526SSimon Glass if ((strlen(fn) + l + 1) != allocl) { 1098b50d526SSimon Glass debug("%s: p: %d, l: %d, a: %d\n", 1108b50d526SSimon Glass pathp, (int)strlen(fn), l, 1118b50d526SSimon Glass allocl); 1128b50d526SSimon Glass } 1138b50d526SSimon Glass #endif 1148b50d526SSimon Glass fn += strlen(fn); 1158b50d526SSimon Glass } 1168b50d526SSimon Glass *(fn++) = '/'; 1178b50d526SSimon Glass } 1188b50d526SSimon Glass memcpy(fn, pathp, l); 1198b50d526SSimon Glass 1208b50d526SSimon Glass prev_pp = &np->properties; 1218b50d526SSimon Glass if (dad != NULL) { 1228b50d526SSimon Glass np->parent = dad; 1238b50d526SSimon Glass np->sibling = dad->child; 1248b50d526SSimon Glass dad->child = np; 1258b50d526SSimon Glass } 1268b50d526SSimon Glass } 1278b50d526SSimon Glass /* process properties */ 1288b50d526SSimon Glass for (offset = fdt_first_property_offset(blob, *poffset); 1298b50d526SSimon Glass (offset >= 0); 1308b50d526SSimon Glass (offset = fdt_next_property_offset(blob, offset))) { 1318b50d526SSimon Glass const char *pname; 1328b50d526SSimon Glass int sz; 1338b50d526SSimon Glass 1348b50d526SSimon Glass p = fdt_getprop_by_offset(blob, offset, &pname, &sz); 1358b50d526SSimon Glass if (!p) { 1368b50d526SSimon Glass offset = -FDT_ERR_INTERNAL; 1378b50d526SSimon Glass break; 1388b50d526SSimon Glass } 1398b50d526SSimon Glass 1408b50d526SSimon Glass if (pname == NULL) { 1418b50d526SSimon Glass debug("Can't find property name in list !\n"); 1428b50d526SSimon Glass break; 1438b50d526SSimon Glass } 1448b50d526SSimon Glass if (strcmp(pname, "name") == 0) 1458b50d526SSimon Glass has_name = 1; 1468b50d526SSimon Glass pp = unflatten_dt_alloc(&mem, sizeof(struct property), 1478b50d526SSimon Glass __alignof__(struct property)); 1488b50d526SSimon Glass if (!dryrun) { 1498b50d526SSimon Glass /* 1508b50d526SSimon Glass * We accept flattened tree phandles either in 1518b50d526SSimon Glass * ePAPR-style "phandle" properties, or the 1528b50d526SSimon Glass * legacy "linux,phandle" properties. If both 1538b50d526SSimon Glass * appear and have different values, things 1548b50d526SSimon Glass * will get weird. Don't do that. */ 1558b50d526SSimon Glass if ((strcmp(pname, "phandle") == 0) || 1568b50d526SSimon Glass (strcmp(pname, "linux,phandle") == 0)) { 1578b50d526SSimon Glass if (np->phandle == 0) 1588b50d526SSimon Glass np->phandle = be32_to_cpup(p); 1598b50d526SSimon Glass } 1608b50d526SSimon Glass /* 1618b50d526SSimon Glass * And we process the "ibm,phandle" property 1628b50d526SSimon Glass * used in pSeries dynamic device tree 1638b50d526SSimon Glass * stuff */ 1648b50d526SSimon Glass if (strcmp(pname, "ibm,phandle") == 0) 1658b50d526SSimon Glass np->phandle = be32_to_cpup(p); 1668b50d526SSimon Glass pp->name = (char *)pname; 1678b50d526SSimon Glass pp->length = sz; 1688b50d526SSimon Glass pp->value = (__be32 *)p; 1698b50d526SSimon Glass *prev_pp = pp; 1708b50d526SSimon Glass prev_pp = &pp->next; 1718b50d526SSimon Glass } 1728b50d526SSimon Glass } 1738b50d526SSimon Glass /* 1748b50d526SSimon Glass * with version 0x10 we may not have the name property, recreate 1758b50d526SSimon Glass * it here from the unit name if absent 1768b50d526SSimon Glass */ 1778b50d526SSimon Glass if (!has_name) { 1788b50d526SSimon Glass const char *p1 = pathp, *ps = pathp, *pa = NULL; 1798b50d526SSimon Glass int sz; 1808b50d526SSimon Glass 1818b50d526SSimon Glass while (*p1) { 1828b50d526SSimon Glass if ((*p1) == '@') 1838b50d526SSimon Glass pa = p1; 1848b50d526SSimon Glass if ((*p1) == '/') 1858b50d526SSimon Glass ps = p1 + 1; 1868b50d526SSimon Glass p1++; 1878b50d526SSimon Glass } 1888b50d526SSimon Glass if (pa < ps) 1898b50d526SSimon Glass pa = p1; 1908b50d526SSimon Glass sz = (pa - ps) + 1; 1918b50d526SSimon Glass pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, 1928b50d526SSimon Glass __alignof__(struct property)); 1938b50d526SSimon Glass if (!dryrun) { 1948b50d526SSimon Glass pp->name = "name"; 1958b50d526SSimon Glass pp->length = sz; 1968b50d526SSimon Glass pp->value = pp + 1; 1978b50d526SSimon Glass *prev_pp = pp; 1988b50d526SSimon Glass prev_pp = &pp->next; 1998b50d526SSimon Glass memcpy(pp->value, ps, sz - 1); 2008b50d526SSimon Glass ((char *)pp->value)[sz - 1] = 0; 2018b50d526SSimon Glass debug("fixed up name for %s -> %s\n", pathp, 2028b50d526SSimon Glass (char *)pp->value); 2038b50d526SSimon Glass } 2048b50d526SSimon Glass } 2058b50d526SSimon Glass if (!dryrun) { 2068b50d526SSimon Glass *prev_pp = NULL; 2078b50d526SSimon Glass np->name = of_get_property(np, "name", NULL); 2088b50d526SSimon Glass np->type = of_get_property(np, "device_type", NULL); 2098b50d526SSimon Glass 2108b50d526SSimon Glass if (!np->name) 2118b50d526SSimon Glass np->name = "<NULL>"; 2128b50d526SSimon Glass if (!np->type) 2138b50d526SSimon Glass np->type = "<NULL>"; } 2148b50d526SSimon Glass 2158b50d526SSimon Glass old_depth = depth; 2168b50d526SSimon Glass *poffset = fdt_next_node(blob, *poffset, &depth); 2178b50d526SSimon Glass if (depth < 0) 2188b50d526SSimon Glass depth = 0; 219*c1eb3d59SSimon Glass while (*poffset > 0 && depth > old_depth) { 2208b50d526SSimon Glass mem = unflatten_dt_node(blob, mem, poffset, np, NULL, 2218b50d526SSimon Glass fpsize, dryrun); 222*c1eb3d59SSimon Glass if (!mem) 223*c1eb3d59SSimon Glass return NULL; 224*c1eb3d59SSimon Glass } 2258b50d526SSimon Glass 2268b50d526SSimon Glass if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND) { 2278b50d526SSimon Glass debug("unflatten: error %d processing FDT\n", *poffset); 2288b50d526SSimon Glass return NULL; 2298b50d526SSimon Glass } 2308b50d526SSimon Glass 2318b50d526SSimon Glass /* 2328b50d526SSimon Glass * Reverse the child list. Some drivers assumes node order matches .dts 2338b50d526SSimon Glass * node order 2348b50d526SSimon Glass */ 2358b50d526SSimon Glass if (!dryrun && np->child) { 2368b50d526SSimon Glass struct device_node *child = np->child; 2378b50d526SSimon Glass np->child = NULL; 2388b50d526SSimon Glass while (child) { 2398b50d526SSimon Glass struct device_node *next = child->sibling; 2408b50d526SSimon Glass 2418b50d526SSimon Glass child->sibling = np->child; 2428b50d526SSimon Glass np->child = child; 2438b50d526SSimon Glass child = next; 2448b50d526SSimon Glass } 2458b50d526SSimon Glass } 2468b50d526SSimon Glass 2478b50d526SSimon Glass if (nodepp) 2488b50d526SSimon Glass *nodepp = np; 2498b50d526SSimon Glass 2508b50d526SSimon Glass return mem; 2518b50d526SSimon Glass } 2528b50d526SSimon Glass 2538b50d526SSimon Glass /** 2548b50d526SSimon Glass * unflatten_device_tree() - create tree of device_nodes from flat blob 2558b50d526SSimon Glass * 2568b50d526SSimon Glass * unflattens a device-tree, creating the 2578b50d526SSimon Glass * tree of struct device_node. It also fills the "name" and "type" 2588b50d526SSimon Glass * pointers of the nodes so the normal device-tree walking functions 2598b50d526SSimon Glass * can be used. 2608b50d526SSimon Glass * @blob: The blob to expand 2618b50d526SSimon Glass * @mynodes: The device_node tree created by the call 2628b50d526SSimon Glass * @return 0 if OK, -ve on error 2638b50d526SSimon Glass */ 2648b50d526SSimon Glass static int unflatten_device_tree(const void *blob, 2658b50d526SSimon Glass struct device_node **mynodes) 2668b50d526SSimon Glass { 2678b50d526SSimon Glass unsigned long size; 2688b50d526SSimon Glass int start; 2698b50d526SSimon Glass void *mem; 2708b50d526SSimon Glass 2718b50d526SSimon Glass debug(" -> unflatten_device_tree()\n"); 2728b50d526SSimon Glass 2738b50d526SSimon Glass if (!blob) { 2748b50d526SSimon Glass debug("No device tree pointer\n"); 2758b50d526SSimon Glass return -EINVAL; 2768b50d526SSimon Glass } 2778b50d526SSimon Glass 2788b50d526SSimon Glass debug("Unflattening device tree:\n"); 2798b50d526SSimon Glass debug("magic: %08x\n", fdt_magic(blob)); 2808b50d526SSimon Glass debug("size: %08x\n", fdt_totalsize(blob)); 2818b50d526SSimon Glass debug("version: %08x\n", fdt_version(blob)); 2828b50d526SSimon Glass 2838b50d526SSimon Glass if (fdt_check_header(blob)) { 2848b50d526SSimon Glass debug("Invalid device tree blob header\n"); 2858b50d526SSimon Glass return -EINVAL; 2868b50d526SSimon Glass } 2878b50d526SSimon Glass 2888b50d526SSimon Glass /* First pass, scan for size */ 2898b50d526SSimon Glass start = 0; 2908b50d526SSimon Glass size = (unsigned long)unflatten_dt_node(blob, NULL, &start, NULL, NULL, 2918b50d526SSimon Glass 0, true); 292*c1eb3d59SSimon Glass if (!size) 293*c1eb3d59SSimon Glass return -EFAULT; 2948b50d526SSimon Glass size = ALIGN(size, 4); 2958b50d526SSimon Glass 2968b50d526SSimon Glass debug(" size is %lx, allocating...\n", size); 2978b50d526SSimon Glass 2988b50d526SSimon Glass /* Allocate memory for the expanded device tree */ 2998b50d526SSimon Glass mem = malloc(size + 4); 3008b50d526SSimon Glass memset(mem, '\0', size); 3018b50d526SSimon Glass 3028b50d526SSimon Glass *(__be32 *)(mem + size) = cpu_to_be32(0xdeadbeef); 3038b50d526SSimon Glass 3048b50d526SSimon Glass debug(" unflattening %p...\n", mem); 3058b50d526SSimon Glass 3068b50d526SSimon Glass /* Second pass, do actual unflattening */ 3078b50d526SSimon Glass start = 0; 3088b50d526SSimon Glass unflatten_dt_node(blob, mem, &start, NULL, mynodes, 0, false); 3098b50d526SSimon Glass if (be32_to_cpup(mem + size) != 0xdeadbeef) { 3108b50d526SSimon Glass debug("End of tree marker overwritten: %08x\n", 3118b50d526SSimon Glass be32_to_cpup(mem + size)); 3128b50d526SSimon Glass return -ENOSPC; 3138b50d526SSimon Glass } 3148b50d526SSimon Glass 3158b50d526SSimon Glass debug(" <- unflatten_device_tree()\n"); 3168b50d526SSimon Glass 3178b50d526SSimon Glass return 0; 3188b50d526SSimon Glass } 3198b50d526SSimon Glass 3208b50d526SSimon Glass int of_live_build(const void *fdt_blob, struct device_node **rootp) 3218b50d526SSimon Glass { 3228b50d526SSimon Glass int ret; 3238b50d526SSimon Glass 3248b50d526SSimon Glass debug("%s: start\n", __func__); 3258b50d526SSimon Glass ret = unflatten_device_tree(fdt_blob, rootp); 3268b50d526SSimon Glass if (ret) { 3278b50d526SSimon Glass debug("Failed to create live tree: err=%d\n", ret); 3288b50d526SSimon Glass return ret; 3298b50d526SSimon Glass } 3308b50d526SSimon Glass ret = of_alias_scan(); 3318b50d526SSimon Glass if (ret) { 3328b50d526SSimon Glass debug("Failed to scan live tree aliases: err=%d\n", ret); 3338b50d526SSimon Glass return ret; 3348b50d526SSimon Glass } 3358b50d526SSimon Glass debug("%s: stop\n", __func__); 3368b50d526SSimon Glass 3378b50d526SSimon Glass return ret; 3388b50d526SSimon Glass } 339