17941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou/* 27941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * Functions for dealing with DT resolution 37941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * 47941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com> 57941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * Copyright (C) 2012 Texas Instruments Inc. 67941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * 77941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * This program is free software; you can redistribute it and/or 87941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * modify it under the terms of the GNU General Public License 97941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * version 2 as published by the Free Software Foundation. 107941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou */ 117941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 127941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou#include <linux/kernel.h> 137941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou#include <linux/module.h> 147941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou#include <linux/of.h> 157941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou#include <linux/of_device.h> 167941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou#include <linux/string.h> 177941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou#include <linux/ctype.h> 187941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou#include <linux/errno.h> 197941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou#include <linux/string.h> 207941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou#include <linux/slab.h> 217941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 227941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou/* illegal phandle value (set when unresolved) */ 237941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou#define OF_PHANDLE_ILLEGAL 0xdeadbeef 247941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 257941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou/** 267941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * Find a node with the give full name by recursively following any of 277941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * the child node links. 287941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou */ 297941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antonioustatic struct device_node *__of_find_node_by_full_name(struct device_node *node, 307941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou const char *full_name) 317941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou{ 327941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou struct device_node *child, *found; 337941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 347941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (node == NULL) 357941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou return NULL; 367941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 377941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* check */ 387941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (of_node_cmp(node->full_name, full_name) == 0) 397941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou return node; 407941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 417941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou for_each_child_of_node(node, child) { 427941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou found = __of_find_node_by_full_name(child, full_name); 437941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (found != NULL) 447941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou return found; 457941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou } 467941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 477941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou return NULL; 487941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou} 497941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 507941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou/* 517941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * Find live tree's maximum phandle value. 527941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou */ 537941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antonioustatic phandle of_get_tree_max_phandle(void) 547941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou{ 557941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou struct device_node *node; 567941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou phandle phandle; 577941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou unsigned long flags; 587941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 597941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* now search recursively */ 607941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou raw_spin_lock_irqsave(&devtree_lock, flags); 617941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou phandle = 0; 627941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou for_each_of_allnodes(node) { 637941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (node->phandle != OF_PHANDLE_ILLEGAL && 647941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou node->phandle > phandle) 657941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou phandle = node->phandle; 667941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou } 677941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou raw_spin_unlock_irqrestore(&devtree_lock, flags); 687941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 697941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou return phandle; 707941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou} 717941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 727941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou/* 737941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * Adjust a subtree's phandle values by a given delta. 747941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * Makes sure not to just adjust the device node's phandle value, 757941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * but modify the phandle properties values as well. 767941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou */ 777941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antonioustatic void __of_adjust_tree_phandles(struct device_node *node, 787941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou int phandle_delta) 797941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou{ 807941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou struct device_node *child; 817941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou struct property *prop; 827941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou phandle phandle; 837941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 847941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* first adjust the node's phandle direct value */ 857941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (node->phandle != 0 && node->phandle != OF_PHANDLE_ILLEGAL) 867941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou node->phandle += phandle_delta; 877941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 887941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* now adjust phandle & linux,phandle values */ 897941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou for_each_property_of_node(node, prop) { 907941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 917941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* only look for these two */ 927941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (of_prop_cmp(prop->name, "phandle") != 0 && 937941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou of_prop_cmp(prop->name, "linux,phandle") != 0) 947941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou continue; 957941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 967941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* must be big enough */ 977941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (prop->length < 4) 987941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou continue; 997941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 1007941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* read phandle value */ 1017941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou phandle = be32_to_cpup(prop->value); 1027941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (phandle == OF_PHANDLE_ILLEGAL) /* unresolved */ 1037941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou continue; 1047941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 1057941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* adjust */ 1067941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou *(uint32_t *)prop->value = cpu_to_be32(node->phandle); 1077941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou } 1087941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 1097941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* now do the children recursively */ 1107941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou for_each_child_of_node(node, child) 1117941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou __of_adjust_tree_phandles(child, phandle_delta); 1127941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou} 1137941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 1147941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antonioustatic int __of_adjust_phandle_ref(struct device_node *node, struct property *rprop, int value, bool is_delta) 1157941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou{ 1167941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou phandle phandle; 1177941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou struct device_node *refnode; 1187941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou struct property *sprop; 1197941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou char *propval, *propcur, *propend, *nodestr, *propstr, *s; 1207941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou int offset, propcurlen; 1217941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou int err = 0; 1227941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 1237941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* make a copy */ 1247941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou propval = kmalloc(rprop->length, GFP_KERNEL); 1257941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (!propval) { 1267941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou pr_err("%s: Could not copy value of '%s'\n", 1277941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou __func__, rprop->name); 1287941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou return -ENOMEM; 1297941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou } 1307941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou memcpy(propval, rprop->value, rprop->length); 1317941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 1327941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou propend = propval + rprop->length; 1337941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou for (propcur = propval; propcur < propend; propcur += propcurlen + 1) { 1347941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou propcurlen = strlen(propcur); 1357941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 1367941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou nodestr = propcur; 1377941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou s = strchr(propcur, ':'); 1387941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (!s) { 1397941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou pr_err("%s: Illegal symbol entry '%s' (1)\n", 1407941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou __func__, propcur); 1417941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou err = -EINVAL; 1427941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou goto err_fail; 1437941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou } 1447941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou *s++ = '\0'; 1457941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 1467941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou propstr = s; 1477941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou s = strchr(s, ':'); 1487941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (!s) { 1497941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou pr_err("%s: Illegal symbol entry '%s' (2)\n", 1507941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou __func__, (char *)rprop->value); 1517941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou err = -EINVAL; 1527941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou goto err_fail; 1537941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou } 1547941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 1557941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou *s++ = '\0'; 1567941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou err = kstrtoint(s, 10, &offset); 1577941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (err != 0) { 1587941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou pr_err("%s: Could get offset '%s'\n", 1597941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou __func__, (char *)rprop->value); 1607941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou goto err_fail; 1617941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou } 1627941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 1637941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* look into the resolve node for the full path */ 1647941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou refnode = __of_find_node_by_full_name(node, nodestr); 1657941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (!refnode) { 1667941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou pr_warn("%s: Could not find refnode '%s'\n", 1677941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou __func__, (char *)rprop->value); 1687941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou continue; 1697941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou } 1707941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 1717941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* now find the property */ 1727941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou for_each_property_of_node(refnode, sprop) { 1737941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (of_prop_cmp(sprop->name, propstr) == 0) 1747941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou break; 1757941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou } 1767941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 1777941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (!sprop) { 1787941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou pr_err("%s: Could not find property '%s'\n", 1797941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou __func__, (char *)rprop->value); 1807941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou err = -ENOENT; 1817941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou goto err_fail; 1827941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou } 1837941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 1847941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou phandle = is_delta ? be32_to_cpup(sprop->value + offset) + value : value; 1857941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou *(__be32 *)(sprop->value + offset) = cpu_to_be32(phandle); 1867941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou } 1877941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 1887941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniouerr_fail: 1897941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou kfree(propval); 1907941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou return err; 1917941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou} 1927941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 1937941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou/* 1947941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * Adjust the local phandle references by the given phandle delta. 1957941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * Assumes the existances of a __local_fixups__ node at the root 1967941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * of the tree. Does not take any devtree locks so make sure you 1977941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * call this on a tree which is at the detached state. 1987941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou */ 1997941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antonioustatic int __of_adjust_tree_phandle_references(struct device_node *node, 2007941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou int phandle_delta) 2017941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou{ 2027941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou struct device_node *child; 2037941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou struct property *rprop; 2047941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou int err; 2057941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 2067941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* locate the symbols & fixups nodes on resolve */ 2077941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou for_each_child_of_node(node, child) 2087941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (of_node_cmp(child->name, "__local_fixups__") == 0) 2097941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou break; 2107941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 2117941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* no local fixups */ 2127941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (!child) 2137941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou return 0; 2147941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 2157941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* find the local fixups property */ 2167941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou for_each_property_of_node(child, rprop) { 2177941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* skip properties added automatically */ 2187941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (of_prop_cmp(rprop->name, "name") == 0) 2197941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou continue; 2207941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 2217941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou err = __of_adjust_phandle_ref(node, rprop, phandle_delta, true); 2227941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (err) 2237941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou return err; 2247941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou } 2257941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 2267941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou return 0; 2277941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou} 2287941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 2297941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou/** 2307941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * of_resolve - Resolve the given node against the live tree. 2317941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * 2327941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * @resolve: Node to resolve 2337941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * 2347941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * Perform dynamic Device Tree resolution against the live tree 2357941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * to the given node to resolve. This depends on the live tree 2367941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * having a __symbols__ node, and the resolve node the __fixups__ & 2377941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * __local_fixups__ nodes (if needed). 2387941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * The result of the operation is a resolve node that it's contents 2397941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * are fit to be inserted or operate upon the live tree. 2407941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou * Returns 0 on success or a negative error value on error. 2417941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou */ 2427941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniouint of_resolve_phandles(struct device_node *resolve) 2437941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou{ 2447941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou struct device_node *child, *refnode; 2457941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou struct device_node *root_sym, *resolve_sym, *resolve_fix; 2467941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou struct property *rprop; 2477941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou const char *refpath; 2487941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou phandle phandle, phandle_delta; 2497941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou int err; 2507941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 2517941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* the resolve node must exist, and be detached */ 2527941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (!resolve || !of_node_check_flag(resolve, OF_DETACHED)) 2537941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou return -EINVAL; 2547941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 2557941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* first we need to adjust the phandles */ 2567941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou phandle_delta = of_get_tree_max_phandle() + 1; 2577941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou __of_adjust_tree_phandles(resolve, phandle_delta); 2587941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou err = __of_adjust_tree_phandle_references(resolve, phandle_delta); 2597941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (err != 0) 2607941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou return err; 2617941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 2627941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou root_sym = NULL; 2637941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou resolve_sym = NULL; 2647941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou resolve_fix = NULL; 2657941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 2667941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* this may fail (if no fixups are required) */ 2677941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou root_sym = of_find_node_by_path("/__symbols__"); 2687941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 2697941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* locate the symbols & fixups nodes on resolve */ 2707941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou for_each_child_of_node(resolve, child) { 2717941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 2727941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (!resolve_sym && 2737941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou of_node_cmp(child->name, "__symbols__") == 0) 2747941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou resolve_sym = child; 2757941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 2767941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (!resolve_fix && 2777941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou of_node_cmp(child->name, "__fixups__") == 0) 2787941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou resolve_fix = child; 2797941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 2807941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* both found, don't bother anymore */ 2817941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (resolve_sym && resolve_fix) 2827941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou break; 2837941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou } 2847941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 2857941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* we do allow for the case where no fixups are needed */ 2867941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (!resolve_fix) { 2877941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou err = 0; /* no error */ 2887941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou goto out; 2897941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou } 2907941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 2917941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* we need to fixup, but no root symbols... */ 2927941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (!root_sym) { 2937941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou err = -EINVAL; 2947941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou goto out; 2957941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou } 2967941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 2977941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou for_each_property_of_node(resolve_fix, rprop) { 2987941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 2997941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* skip properties added automatically */ 3007941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (of_prop_cmp(rprop->name, "name") == 0) 3017941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou continue; 3027941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 3037941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou err = of_property_read_string(root_sym, 3047941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou rprop->name, &refpath); 3057941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (err != 0) { 3067941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou pr_err("%s: Could not find symbol '%s'\n", 3077941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou __func__, rprop->name); 3087941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou goto out; 3097941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou } 3107941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 3117941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou refnode = of_find_node_by_path(refpath); 3127941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (!refnode) { 3137941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou pr_err("%s: Could not find node by path '%s'\n", 3147941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou __func__, refpath); 3157941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou err = -ENOENT; 3167941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou goto out; 3177941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou } 3187941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 3197941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou phandle = refnode->phandle; 3207941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou of_node_put(refnode); 3217941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 3227941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou pr_debug("%s: %s phandle is 0x%08x\n", 3237941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou __func__, rprop->name, phandle); 3247941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 3257941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou err = __of_adjust_phandle_ref(resolve, rprop, phandle, false); 3267941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou if (err) 3277941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou break; 3287941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou } 3297941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 3307941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniouout: 3317941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou /* NULL is handled by of_node_put as NOP */ 3327941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou of_node_put(root_sym); 3337941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou 3347941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou return err; 3357941b27b16e3282f6ec8817e36492f1deec753a7Pantelis Antoniou} 3367941b27b16e3282f6ec8817e36492f1deec753a7Pantelis AntoniouEXPORT_SYMBOL_GPL(of_resolve_phandles); 337