[go: nahoru, domu]

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