17941b27bSPantelis Antoniou /* 27941b27bSPantelis Antoniou * Functions for dealing with DT resolution 37941b27bSPantelis Antoniou * 47941b27bSPantelis Antoniou * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com> 57941b27bSPantelis Antoniou * Copyright (C) 2012 Texas Instruments Inc. 67941b27bSPantelis Antoniou * 77941b27bSPantelis Antoniou * This program is free software; you can redistribute it and/or 87941b27bSPantelis Antoniou * modify it under the terms of the GNU General Public License 97941b27bSPantelis Antoniou * version 2 as published by the Free Software Foundation. 107941b27bSPantelis Antoniou */ 117941b27bSPantelis Antoniou 127941b27bSPantelis Antoniou #include <linux/kernel.h> 137941b27bSPantelis Antoniou #include <linux/module.h> 147941b27bSPantelis Antoniou #include <linux/of.h> 157941b27bSPantelis Antoniou #include <linux/of_device.h> 167941b27bSPantelis Antoniou #include <linux/string.h> 177941b27bSPantelis Antoniou #include <linux/ctype.h> 187941b27bSPantelis Antoniou #include <linux/errno.h> 197941b27bSPantelis Antoniou #include <linux/string.h> 207941b27bSPantelis Antoniou #include <linux/slab.h> 217941b27bSPantelis Antoniou 227941b27bSPantelis Antoniou /* illegal phandle value (set when unresolved) */ 237941b27bSPantelis Antoniou #define OF_PHANDLE_ILLEGAL 0xdeadbeef 247941b27bSPantelis Antoniou 257941b27bSPantelis Antoniou /** 267941b27bSPantelis Antoniou * Find a node with the give full name by recursively following any of 277941b27bSPantelis Antoniou * the child node links. 287941b27bSPantelis Antoniou */ 297941b27bSPantelis Antoniou static struct device_node *__of_find_node_by_full_name(struct device_node *node, 307941b27bSPantelis Antoniou const char *full_name) 317941b27bSPantelis Antoniou { 327941b27bSPantelis Antoniou struct device_node *child, *found; 337941b27bSPantelis Antoniou 347941b27bSPantelis Antoniou if (node == NULL) 357941b27bSPantelis Antoniou return NULL; 367941b27bSPantelis Antoniou 377941b27bSPantelis Antoniou /* check */ 387941b27bSPantelis Antoniou if (of_node_cmp(node->full_name, full_name) == 0) 397941b27bSPantelis Antoniou return node; 407941b27bSPantelis Antoniou 417941b27bSPantelis Antoniou for_each_child_of_node(node, child) { 427941b27bSPantelis Antoniou found = __of_find_node_by_full_name(child, full_name); 437941b27bSPantelis Antoniou if (found != NULL) 447941b27bSPantelis Antoniou return found; 457941b27bSPantelis Antoniou } 467941b27bSPantelis Antoniou 477941b27bSPantelis Antoniou return NULL; 487941b27bSPantelis Antoniou } 497941b27bSPantelis Antoniou 507941b27bSPantelis Antoniou /* 517941b27bSPantelis Antoniou * Find live tree's maximum phandle value. 527941b27bSPantelis Antoniou */ 537941b27bSPantelis Antoniou static phandle of_get_tree_max_phandle(void) 547941b27bSPantelis Antoniou { 557941b27bSPantelis Antoniou struct device_node *node; 567941b27bSPantelis Antoniou phandle phandle; 577941b27bSPantelis Antoniou unsigned long flags; 587941b27bSPantelis Antoniou 597941b27bSPantelis Antoniou /* now search recursively */ 607941b27bSPantelis Antoniou raw_spin_lock_irqsave(&devtree_lock, flags); 617941b27bSPantelis Antoniou phandle = 0; 627941b27bSPantelis Antoniou for_each_of_allnodes(node) { 637941b27bSPantelis Antoniou if (node->phandle != OF_PHANDLE_ILLEGAL && 647941b27bSPantelis Antoniou node->phandle > phandle) 657941b27bSPantelis Antoniou phandle = node->phandle; 667941b27bSPantelis Antoniou } 677941b27bSPantelis Antoniou raw_spin_unlock_irqrestore(&devtree_lock, flags); 687941b27bSPantelis Antoniou 697941b27bSPantelis Antoniou return phandle; 707941b27bSPantelis Antoniou } 717941b27bSPantelis Antoniou 727941b27bSPantelis Antoniou /* 737941b27bSPantelis Antoniou * Adjust a subtree's phandle values by a given delta. 747941b27bSPantelis Antoniou * Makes sure not to just adjust the device node's phandle value, 757941b27bSPantelis Antoniou * but modify the phandle properties values as well. 767941b27bSPantelis Antoniou */ 777941b27bSPantelis Antoniou static void __of_adjust_tree_phandles(struct device_node *node, 787941b27bSPantelis Antoniou int phandle_delta) 797941b27bSPantelis Antoniou { 807941b27bSPantelis Antoniou struct device_node *child; 817941b27bSPantelis Antoniou struct property *prop; 827941b27bSPantelis Antoniou phandle phandle; 837941b27bSPantelis Antoniou 847941b27bSPantelis Antoniou /* first adjust the node's phandle direct value */ 857941b27bSPantelis Antoniou if (node->phandle != 0 && node->phandle != OF_PHANDLE_ILLEGAL) 867941b27bSPantelis Antoniou node->phandle += phandle_delta; 877941b27bSPantelis Antoniou 887941b27bSPantelis Antoniou /* now adjust phandle & linux,phandle values */ 897941b27bSPantelis Antoniou for_each_property_of_node(node, prop) { 907941b27bSPantelis Antoniou 917941b27bSPantelis Antoniou /* only look for these two */ 927941b27bSPantelis Antoniou if (of_prop_cmp(prop->name, "phandle") != 0 && 937941b27bSPantelis Antoniou of_prop_cmp(prop->name, "linux,phandle") != 0) 947941b27bSPantelis Antoniou continue; 957941b27bSPantelis Antoniou 967941b27bSPantelis Antoniou /* must be big enough */ 977941b27bSPantelis Antoniou if (prop->length < 4) 987941b27bSPantelis Antoniou continue; 997941b27bSPantelis Antoniou 1007941b27bSPantelis Antoniou /* read phandle value */ 1017941b27bSPantelis Antoniou phandle = be32_to_cpup(prop->value); 1027941b27bSPantelis Antoniou if (phandle == OF_PHANDLE_ILLEGAL) /* unresolved */ 1037941b27bSPantelis Antoniou continue; 1047941b27bSPantelis Antoniou 1057941b27bSPantelis Antoniou /* adjust */ 1067941b27bSPantelis Antoniou *(uint32_t *)prop->value = cpu_to_be32(node->phandle); 1077941b27bSPantelis Antoniou } 1087941b27bSPantelis Antoniou 1097941b27bSPantelis Antoniou /* now do the children recursively */ 1107941b27bSPantelis Antoniou for_each_child_of_node(node, child) 1117941b27bSPantelis Antoniou __of_adjust_tree_phandles(child, phandle_delta); 1127941b27bSPantelis Antoniou } 1137941b27bSPantelis Antoniou 114da56d04cSPantelis Antoniou static int __of_adjust_phandle_ref(struct device_node *node, 115da56d04cSPantelis Antoniou struct property *rprop, int value) 1167941b27bSPantelis Antoniou { 1177941b27bSPantelis Antoniou phandle phandle; 1187941b27bSPantelis Antoniou struct device_node *refnode; 1197941b27bSPantelis Antoniou struct property *sprop; 1207941b27bSPantelis Antoniou char *propval, *propcur, *propend, *nodestr, *propstr, *s; 1217941b27bSPantelis Antoniou int offset, propcurlen; 1227941b27bSPantelis Antoniou int err = 0; 1237941b27bSPantelis Antoniou 1247941b27bSPantelis Antoniou /* make a copy */ 1257941b27bSPantelis Antoniou propval = kmalloc(rprop->length, GFP_KERNEL); 1267941b27bSPantelis Antoniou if (!propval) { 1277941b27bSPantelis Antoniou pr_err("%s: Could not copy value of '%s'\n", 1287941b27bSPantelis Antoniou __func__, rprop->name); 1297941b27bSPantelis Antoniou return -ENOMEM; 1307941b27bSPantelis Antoniou } 1317941b27bSPantelis Antoniou memcpy(propval, rprop->value, rprop->length); 1327941b27bSPantelis Antoniou 1337941b27bSPantelis Antoniou propend = propval + rprop->length; 1347941b27bSPantelis Antoniou for (propcur = propval; propcur < propend; propcur += propcurlen + 1) { 1357941b27bSPantelis Antoniou propcurlen = strlen(propcur); 1367941b27bSPantelis Antoniou 1377941b27bSPantelis Antoniou nodestr = propcur; 1387941b27bSPantelis Antoniou s = strchr(propcur, ':'); 1397941b27bSPantelis Antoniou if (!s) { 1407941b27bSPantelis Antoniou pr_err("%s: Illegal symbol entry '%s' (1)\n", 1417941b27bSPantelis Antoniou __func__, propcur); 1427941b27bSPantelis Antoniou err = -EINVAL; 1437941b27bSPantelis Antoniou goto err_fail; 1447941b27bSPantelis Antoniou } 1457941b27bSPantelis Antoniou *s++ = '\0'; 1467941b27bSPantelis Antoniou 1477941b27bSPantelis Antoniou propstr = s; 1487941b27bSPantelis Antoniou s = strchr(s, ':'); 1497941b27bSPantelis Antoniou if (!s) { 1507941b27bSPantelis Antoniou pr_err("%s: Illegal symbol entry '%s' (2)\n", 1517941b27bSPantelis Antoniou __func__, (char *)rprop->value); 1527941b27bSPantelis Antoniou err = -EINVAL; 1537941b27bSPantelis Antoniou goto err_fail; 1547941b27bSPantelis Antoniou } 1557941b27bSPantelis Antoniou 1567941b27bSPantelis Antoniou *s++ = '\0'; 1577941b27bSPantelis Antoniou err = kstrtoint(s, 10, &offset); 1587941b27bSPantelis Antoniou if (err != 0) { 1597941b27bSPantelis Antoniou pr_err("%s: Could get offset '%s'\n", 1607941b27bSPantelis Antoniou __func__, (char *)rprop->value); 1617941b27bSPantelis Antoniou goto err_fail; 1627941b27bSPantelis Antoniou } 1637941b27bSPantelis Antoniou 1647941b27bSPantelis Antoniou /* look into the resolve node for the full path */ 1657941b27bSPantelis Antoniou refnode = __of_find_node_by_full_name(node, nodestr); 1667941b27bSPantelis Antoniou if (!refnode) { 1677941b27bSPantelis Antoniou pr_warn("%s: Could not find refnode '%s'\n", 1687941b27bSPantelis Antoniou __func__, (char *)rprop->value); 1697941b27bSPantelis Antoniou continue; 1707941b27bSPantelis Antoniou } 1717941b27bSPantelis Antoniou 1727941b27bSPantelis Antoniou /* now find the property */ 1737941b27bSPantelis Antoniou for_each_property_of_node(refnode, sprop) { 1747941b27bSPantelis Antoniou if (of_prop_cmp(sprop->name, propstr) == 0) 1757941b27bSPantelis Antoniou break; 1767941b27bSPantelis Antoniou } 1777941b27bSPantelis Antoniou 1787941b27bSPantelis Antoniou if (!sprop) { 1797941b27bSPantelis Antoniou pr_err("%s: Could not find property '%s'\n", 1807941b27bSPantelis Antoniou __func__, (char *)rprop->value); 1817941b27bSPantelis Antoniou err = -ENOENT; 1827941b27bSPantelis Antoniou goto err_fail; 1837941b27bSPantelis Antoniou } 1847941b27bSPantelis Antoniou 185da56d04cSPantelis Antoniou phandle = value; 1867941b27bSPantelis Antoniou *(__be32 *)(sprop->value + offset) = cpu_to_be32(phandle); 1877941b27bSPantelis Antoniou } 1887941b27bSPantelis Antoniou 1897941b27bSPantelis Antoniou err_fail: 1907941b27bSPantelis Antoniou kfree(propval); 1917941b27bSPantelis Antoniou return err; 1927941b27bSPantelis Antoniou } 1937941b27bSPantelis Antoniou 194da56d04cSPantelis Antoniou /* compare nodes taking into account that 'name' strips out the @ part */ 195da56d04cSPantelis Antoniou static int __of_node_name_cmp(const struct device_node *dn1, 196da56d04cSPantelis Antoniou const struct device_node *dn2) 197da56d04cSPantelis Antoniou { 198da56d04cSPantelis Antoniou const char *n1 = strrchr(dn1->full_name, '/') ? : "/"; 199da56d04cSPantelis Antoniou const char *n2 = strrchr(dn2->full_name, '/') ? : "/"; 200da56d04cSPantelis Antoniou 201da56d04cSPantelis Antoniou return of_node_cmp(n1, n2); 202da56d04cSPantelis Antoniou } 203da56d04cSPantelis Antoniou 2047941b27bSPantelis Antoniou /* 2057941b27bSPantelis Antoniou * Adjust the local phandle references by the given phandle delta. 206da56d04cSPantelis Antoniou * Assumes the existances of a __local_fixups__ node at the root. 207da56d04cSPantelis Antoniou * Assumes that __of_verify_tree_phandle_references has been called. 208da56d04cSPantelis Antoniou * Does not take any devtree locks so make sure you call this on a tree 209da56d04cSPantelis Antoniou * which is at the detached state. 2107941b27bSPantelis Antoniou */ 2117941b27bSPantelis Antoniou static int __of_adjust_tree_phandle_references(struct device_node *node, 212da56d04cSPantelis Antoniou struct device_node *target, int phandle_delta) 2137941b27bSPantelis Antoniou { 214da56d04cSPantelis Antoniou struct device_node *child, *childtarget; 215da56d04cSPantelis Antoniou struct property *rprop, *sprop; 216da56d04cSPantelis Antoniou int err, i, count; 217da56d04cSPantelis Antoniou unsigned int off; 218da56d04cSPantelis Antoniou phandle phandle; 2197941b27bSPantelis Antoniou 220da56d04cSPantelis Antoniou if (node == NULL) 2217941b27bSPantelis Antoniou return 0; 2227941b27bSPantelis Antoniou 223da56d04cSPantelis Antoniou for_each_property_of_node(node, rprop) { 224da56d04cSPantelis Antoniou 2257941b27bSPantelis Antoniou /* skip properties added automatically */ 226da56d04cSPantelis Antoniou if (of_prop_cmp(rprop->name, "name") == 0 || 227da56d04cSPantelis Antoniou of_prop_cmp(rprop->name, "phandle") == 0 || 228da56d04cSPantelis Antoniou of_prop_cmp(rprop->name, "linux,phandle") == 0) 2297941b27bSPantelis Antoniou continue; 2307941b27bSPantelis Antoniou 231da56d04cSPantelis Antoniou if ((rprop->length % 4) != 0 || rprop->length == 0) { 232da56d04cSPantelis Antoniou pr_err("%s: Illegal property (size) '%s' @%s\n", 233da56d04cSPantelis Antoniou __func__, rprop->name, node->full_name); 234da56d04cSPantelis Antoniou return -EINVAL; 235da56d04cSPantelis Antoniou } 236da56d04cSPantelis Antoniou count = rprop->length / sizeof(__be32); 237da56d04cSPantelis Antoniou 238da56d04cSPantelis Antoniou /* now find the target property */ 239da56d04cSPantelis Antoniou for_each_property_of_node(target, sprop) { 240da56d04cSPantelis Antoniou if (of_prop_cmp(sprop->name, rprop->name) == 0) 241da56d04cSPantelis Antoniou break; 242da56d04cSPantelis Antoniou } 243da56d04cSPantelis Antoniou 244da56d04cSPantelis Antoniou if (sprop == NULL) { 245da56d04cSPantelis Antoniou pr_err("%s: Could not find target property '%s' @%s\n", 246da56d04cSPantelis Antoniou __func__, rprop->name, node->full_name); 247da56d04cSPantelis Antoniou return -EINVAL; 248da56d04cSPantelis Antoniou } 249da56d04cSPantelis Antoniou 250da56d04cSPantelis Antoniou for (i = 0; i < count; i++) { 251da56d04cSPantelis Antoniou off = be32_to_cpu(((__be32 *)rprop->value)[i]); 252da56d04cSPantelis Antoniou /* make sure the offset doesn't overstep (even wrap) */ 253da56d04cSPantelis Antoniou if (off >= sprop->length || 254da56d04cSPantelis Antoniou (off + 4) > sprop->length) { 255da56d04cSPantelis Antoniou pr_err("%s: Illegal property '%s' @%s\n", 256da56d04cSPantelis Antoniou __func__, rprop->name, 257da56d04cSPantelis Antoniou node->full_name); 258da56d04cSPantelis Antoniou return -EINVAL; 259da56d04cSPantelis Antoniou } 260da56d04cSPantelis Antoniou 261da56d04cSPantelis Antoniou if (phandle_delta) { 262da56d04cSPantelis Antoniou /* adjust */ 263da56d04cSPantelis Antoniou phandle = be32_to_cpu(*(__be32 *)(sprop->value + off)); 264da56d04cSPantelis Antoniou phandle += phandle_delta; 265da56d04cSPantelis Antoniou *(__be32 *)(sprop->value + off) = cpu_to_be32(phandle); 266da56d04cSPantelis Antoniou } 267da56d04cSPantelis Antoniou } 268da56d04cSPantelis Antoniou } 269da56d04cSPantelis Antoniou 270da56d04cSPantelis Antoniou for_each_child_of_node(node, child) { 271da56d04cSPantelis Antoniou 272da56d04cSPantelis Antoniou for_each_child_of_node(target, childtarget) 273da56d04cSPantelis Antoniou if (__of_node_name_cmp(child, childtarget) == 0) 274da56d04cSPantelis Antoniou break; 275da56d04cSPantelis Antoniou 276da56d04cSPantelis Antoniou if (!childtarget) { 277da56d04cSPantelis Antoniou pr_err("%s: Could not find target child '%s' @%s\n", 278da56d04cSPantelis Antoniou __func__, child->name, node->full_name); 279da56d04cSPantelis Antoniou return -EINVAL; 280da56d04cSPantelis Antoniou } 281da56d04cSPantelis Antoniou 282da56d04cSPantelis Antoniou err = __of_adjust_tree_phandle_references(child, childtarget, 283da56d04cSPantelis Antoniou phandle_delta); 284da56d04cSPantelis Antoniou if (err != 0) 2857941b27bSPantelis Antoniou return err; 2867941b27bSPantelis Antoniou } 2877941b27bSPantelis Antoniou 2887941b27bSPantelis Antoniou return 0; 2897941b27bSPantelis Antoniou } 2907941b27bSPantelis Antoniou 2917941b27bSPantelis Antoniou /** 2927941b27bSPantelis Antoniou * of_resolve - Resolve the given node against the live tree. 2937941b27bSPantelis Antoniou * 2947941b27bSPantelis Antoniou * @resolve: Node to resolve 2957941b27bSPantelis Antoniou * 2967941b27bSPantelis Antoniou * Perform dynamic Device Tree resolution against the live tree 2977941b27bSPantelis Antoniou * to the given node to resolve. This depends on the live tree 2987941b27bSPantelis Antoniou * having a __symbols__ node, and the resolve node the __fixups__ & 2997941b27bSPantelis Antoniou * __local_fixups__ nodes (if needed). 3007941b27bSPantelis Antoniou * The result of the operation is a resolve node that it's contents 3017941b27bSPantelis Antoniou * are fit to be inserted or operate upon the live tree. 3027941b27bSPantelis Antoniou * Returns 0 on success or a negative error value on error. 3037941b27bSPantelis Antoniou */ 3047941b27bSPantelis Antoniou int of_resolve_phandles(struct device_node *resolve) 3057941b27bSPantelis Antoniou { 306da56d04cSPantelis Antoniou struct device_node *child, *childroot, *refnode; 3077941b27bSPantelis Antoniou struct device_node *root_sym, *resolve_sym, *resolve_fix; 3087941b27bSPantelis Antoniou struct property *rprop; 3097941b27bSPantelis Antoniou const char *refpath; 3107941b27bSPantelis Antoniou phandle phandle, phandle_delta; 3117941b27bSPantelis Antoniou int err; 3127941b27bSPantelis Antoniou 3137941b27bSPantelis Antoniou /* the resolve node must exist, and be detached */ 3147941b27bSPantelis Antoniou if (!resolve || !of_node_check_flag(resolve, OF_DETACHED)) 3157941b27bSPantelis Antoniou return -EINVAL; 3167941b27bSPantelis Antoniou 3177941b27bSPantelis Antoniou /* first we need to adjust the phandles */ 3187941b27bSPantelis Antoniou phandle_delta = of_get_tree_max_phandle() + 1; 3197941b27bSPantelis Antoniou __of_adjust_tree_phandles(resolve, phandle_delta); 320da56d04cSPantelis Antoniou 321da56d04cSPantelis Antoniou /* locate the local fixups */ 322da56d04cSPantelis Antoniou childroot = NULL; 323da56d04cSPantelis Antoniou for_each_child_of_node(resolve, childroot) 324da56d04cSPantelis Antoniou if (of_node_cmp(childroot->name, "__local_fixups__") == 0) 325da56d04cSPantelis Antoniou break; 326da56d04cSPantelis Antoniou 327da56d04cSPantelis Antoniou if (childroot != NULL) { 328da56d04cSPantelis Antoniou /* resolve root is guaranteed to be the '/' */ 329da56d04cSPantelis Antoniou err = __of_adjust_tree_phandle_references(childroot, 330da56d04cSPantelis Antoniou resolve, 0); 3317941b27bSPantelis Antoniou if (err != 0) 3327941b27bSPantelis Antoniou return err; 3337941b27bSPantelis Antoniou 334da56d04cSPantelis Antoniou BUG_ON(__of_adjust_tree_phandle_references(childroot, 335da56d04cSPantelis Antoniou resolve, phandle_delta)); 336da56d04cSPantelis Antoniou } 337da56d04cSPantelis Antoniou 3387941b27bSPantelis Antoniou root_sym = NULL; 3397941b27bSPantelis Antoniou resolve_sym = NULL; 3407941b27bSPantelis Antoniou resolve_fix = NULL; 3417941b27bSPantelis Antoniou 3427941b27bSPantelis Antoniou /* this may fail (if no fixups are required) */ 3437941b27bSPantelis Antoniou root_sym = of_find_node_by_path("/__symbols__"); 3447941b27bSPantelis Antoniou 3457941b27bSPantelis Antoniou /* locate the symbols & fixups nodes on resolve */ 3467941b27bSPantelis Antoniou for_each_child_of_node(resolve, child) { 3477941b27bSPantelis Antoniou 3487941b27bSPantelis Antoniou if (!resolve_sym && 3497941b27bSPantelis Antoniou of_node_cmp(child->name, "__symbols__") == 0) 3507941b27bSPantelis Antoniou resolve_sym = child; 3517941b27bSPantelis Antoniou 3527941b27bSPantelis Antoniou if (!resolve_fix && 3537941b27bSPantelis Antoniou of_node_cmp(child->name, "__fixups__") == 0) 3547941b27bSPantelis Antoniou resolve_fix = child; 3557941b27bSPantelis Antoniou 3567941b27bSPantelis Antoniou /* both found, don't bother anymore */ 3577941b27bSPantelis Antoniou if (resolve_sym && resolve_fix) 3587941b27bSPantelis Antoniou break; 3597941b27bSPantelis Antoniou } 3607941b27bSPantelis Antoniou 3617941b27bSPantelis Antoniou /* we do allow for the case where no fixups are needed */ 3627941b27bSPantelis Antoniou if (!resolve_fix) { 3637941b27bSPantelis Antoniou err = 0; /* no error */ 3647941b27bSPantelis Antoniou goto out; 3657941b27bSPantelis Antoniou } 3667941b27bSPantelis Antoniou 3677941b27bSPantelis Antoniou /* we need to fixup, but no root symbols... */ 3687941b27bSPantelis Antoniou if (!root_sym) { 3697941b27bSPantelis Antoniou err = -EINVAL; 3707941b27bSPantelis Antoniou goto out; 3717941b27bSPantelis Antoniou } 3727941b27bSPantelis Antoniou 3737941b27bSPantelis Antoniou for_each_property_of_node(resolve_fix, rprop) { 3747941b27bSPantelis Antoniou 3757941b27bSPantelis Antoniou /* skip properties added automatically */ 3767941b27bSPantelis Antoniou if (of_prop_cmp(rprop->name, "name") == 0) 3777941b27bSPantelis Antoniou continue; 3787941b27bSPantelis Antoniou 3797941b27bSPantelis Antoniou err = of_property_read_string(root_sym, 3807941b27bSPantelis Antoniou rprop->name, &refpath); 3817941b27bSPantelis Antoniou if (err != 0) { 3827941b27bSPantelis Antoniou pr_err("%s: Could not find symbol '%s'\n", 3837941b27bSPantelis Antoniou __func__, rprop->name); 3847941b27bSPantelis Antoniou goto out; 3857941b27bSPantelis Antoniou } 3867941b27bSPantelis Antoniou 3877941b27bSPantelis Antoniou refnode = of_find_node_by_path(refpath); 3887941b27bSPantelis Antoniou if (!refnode) { 3897941b27bSPantelis Antoniou pr_err("%s: Could not find node by path '%s'\n", 3907941b27bSPantelis Antoniou __func__, refpath); 3917941b27bSPantelis Antoniou err = -ENOENT; 3927941b27bSPantelis Antoniou goto out; 3937941b27bSPantelis Antoniou } 3947941b27bSPantelis Antoniou 3957941b27bSPantelis Antoniou phandle = refnode->phandle; 3967941b27bSPantelis Antoniou of_node_put(refnode); 3977941b27bSPantelis Antoniou 3987941b27bSPantelis Antoniou pr_debug("%s: %s phandle is 0x%08x\n", 3997941b27bSPantelis Antoniou __func__, rprop->name, phandle); 4007941b27bSPantelis Antoniou 401da56d04cSPantelis Antoniou err = __of_adjust_phandle_ref(resolve, rprop, phandle); 4027941b27bSPantelis Antoniou if (err) 4037941b27bSPantelis Antoniou break; 4047941b27bSPantelis Antoniou } 4057941b27bSPantelis Antoniou 4067941b27bSPantelis Antoniou out: 4077941b27bSPantelis Antoniou /* NULL is handled by of_node_put as NOP */ 4087941b27bSPantelis Antoniou of_node_put(root_sym); 4097941b27bSPantelis Antoniou 4107941b27bSPantelis Antoniou return err; 4117941b27bSPantelis Antoniou } 4127941b27bSPantelis Antoniou EXPORT_SYMBOL_GPL(of_resolve_phandles); 413