Merge tag 'devicetree-for-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 15 Dec 2016 19:49:41 +0000 (11:49 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 15 Dec 2016 19:49:41 +0000 (11:49 -0800)
Pull DeviceTree updates from Rob Herring:

 - add various vendor prefixes.

 - fix NUMA node handling when "numa=off" is passed on kernel command
   line.

 - coding style Clean-up of overlay handling code.

 - DocBook fixes in DT platform driver code

 - Altera SoCFPGA binding addtions for freeze bridge, arria10 FPGA
   manager and FPGA bridges.

 - a couple of printk message fixes.

* tag 'devicetree-for-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux: (33 commits)
  dt: pwm: bcm2835: fix typo in clocks property name
  devicetree: add vendor prefix for National Instruments
  Revert "of: base: add support to get machine model name"
  of: Fix issue where code would fall through to error case.
  drivers/of: fix missing pr_cont()s in of_print_phandle_args
  devicetree: bindings: Add vendor prefix for Oki
  devicetree: bindings: Add vendor prefix for Andes Technology Corporation
  dt-bindings: add MYIR Tech hardware vendor prefix
  add bindings document for altera freeze bridge
  ARM: socfpga: add bindings doc for arria10 fpga manager
  ARM: socfpga: add bindings document for fpga bridge drivers
  of: base: add support to get machine model name
  of/platform: clarify of_find_device_by_node refcounting
  of/platform: fix of_platform_device_destroy comment
  of: Remove unused variable overlay_symbols
  of: Move setting of pointer to beside test for non-null
  of: Add back an error message, restructured
  of: Update comments to reflect changes and increase clarity
  of: Remove redundant size check
  of: Update structure of code to be clearer, also remove BUG_ON()
  ...

Documentation/devicetree/bindings/arm/arm-boards
Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt [new file with mode: 0644]
Documentation/devicetree/bindings/fpga/altera-freeze-bridge.txt [new file with mode: 0644]
Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt [new file with mode: 0644]
Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/pwm-bcm2835.txt
Documentation/devicetree/bindings/vendor-prefixes.txt
drivers/of/base.c
drivers/of/of_numa.c
drivers/of/platform.c
drivers/of/resolver.c

index ab318a5..b6e810c 100644 (file)
@@ -148,11 +148,12 @@ Example:
 
 /dts-v1/;
 #include <dt-bindings/interrupt-controller/irq.h>
-#include "skeleton.dtsi"
 
 / {
        model = "ARM RealView PB1176 with device tree";
        compatible = "arm,realview-pb1176";
+       #address-cells = <1>;
+       #size-cells = <1>;
 
        soc {
                #address-cells = <1>;
diff --git a/Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt b/Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt
new file mode 100644 (file)
index 0000000..817a8d4
--- /dev/null
@@ -0,0 +1,16 @@
+Altera FPGA To SDRAM Bridge Driver
+
+Required properties:
+- compatible           : Should contain "altr,socfpga-fpga2sdram-bridge"
+
+Optional properties:
+- bridge-enable                : 0 if driver should disable bridge at startup
+                         1 if driver should enable bridge at startup
+                         Default is to leave bridge in current state.
+
+Example:
+       fpga_bridge3: fpga-bridge@ffc25080 {
+               compatible = "altr,socfpga-fpga2sdram-bridge";
+               reg = <0xffc25080 0x4>;
+               bridge-enable = <0>;
+       };
diff --git a/Documentation/devicetree/bindings/fpga/altera-freeze-bridge.txt b/Documentation/devicetree/bindings/fpga/altera-freeze-bridge.txt
new file mode 100644 (file)
index 0000000..f8e288c
--- /dev/null
@@ -0,0 +1,23 @@
+Altera Freeze Bridge Controller Driver
+
+The Altera Freeze Bridge Controller manages one or more freeze bridges.
+The controller can freeze/disable the bridges which prevents signal
+changes from passing through the bridge.  The controller can also
+unfreeze/enable the bridges which allows traffic to pass through the
+bridge normally.
+
+Required properties:
+- compatible           : Should contain "altr,freeze-bridge-controller"
+- regs                 : base address and size for freeze bridge module
+
+Optional properties:
+- bridge-enable                : 0 if driver should disable bridge at startup
+                         1 if driver should enable bridge at startup
+                         Default is to leave bridge in current state.
+
+Example:
+       freeze-controller@100000450 {
+               compatible = "altr,freeze-bridge-controller";
+               regs = <0x1000 0x10>;
+               bridge-enable = <0>;
+       };
diff --git a/Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt b/Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt
new file mode 100644 (file)
index 0000000..6406f93
--- /dev/null
@@ -0,0 +1,39 @@
+Altera FPGA/HPS Bridge Driver
+
+Required properties:
+- regs         : base address and size for AXI bridge module
+- compatible   : Should contain one of:
+                 "altr,socfpga-lwhps2fpga-bridge",
+                 "altr,socfpga-hps2fpga-bridge", or
+                 "altr,socfpga-fpga2hps-bridge"
+- resets       : Phandle and reset specifier for this bridge's reset
+- clocks       : Clocks used by this module.
+
+Optional properties:
+- bridge-enable        : 0 if driver should disable bridge at startup.
+                 1 if driver should enable bridge at startup.
+                 Default is to leave bridge in its current state.
+
+Example:
+       fpga_bridge0: fpga-bridge@ff400000 {
+               compatible = "altr,socfpga-lwhps2fpga-bridge";
+               reg = <0xff400000 0x100000>;
+               resets = <&rst LWHPS2FPGA_RESET>;
+               clocks = <&l4_main_clk>;
+               bridge-enable = <0>;
+       };
+
+       fpga_bridge1: fpga-bridge@ff500000 {
+               compatible = "altr,socfpga-hps2fpga-bridge";
+               reg = <0xff500000 0x10000>;
+               resets = <&rst HPS2FPGA_RESET>;
+               clocks = <&l4_main_clk>;
+               bridge-enable = <1>;
+       };
+
+       fpga_bridge2: fpga-bridge@ff600000 {
+               compatible = "altr,socfpga-fpga2hps-bridge";
+               reg = <0xff600000 0x100000>;
+               resets = <&rst FPGA2HPS_RESET>;
+               clocks = <&l4_main_clk>;
+       };
diff --git a/Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt b/Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt
new file mode 100644 (file)
index 0000000..2fd8e7a
--- /dev/null
@@ -0,0 +1,19 @@
+Altera SOCFPGA Arria10 FPGA Manager
+
+Required properties:
+- compatible : should contain "altr,socfpga-a10-fpga-mgr"
+- reg        : base address and size for memory mapped io.
+               - The first index is for FPGA manager register access.
+               - The second index is for writing FPGA configuration data.
+- resets     : Phandle and reset specifier for the device's reset.
+- clocks     : Clocks used by the device.
+
+Example:
+
+       fpga_mgr: fpga-mgr@ffd03000 {
+               compatible = "altr,socfpga-a10-fpga-mgr";
+               reg = <0xffd03000 0x100
+                      0xffcfe400 0x20>;
+               clocks = <&l4_mp_clk>;
+               resets = <&rst FPGAMGR_RESET>;
+       };
index fb6fb31..cf573e8 100644 (file)
@@ -3,7 +3,7 @@ BCM2835 PWM controller (Raspberry Pi controller)
 Required properties:
 - compatible: should be "brcm,bcm2835-pwm"
 - reg: physical base address and length of the controller's registers
-- clock: This clock defines the base clock frequency of the PWM hardware
+- clocks: This clock defines the base clock frequency of the PWM hardware
   system, the period and the duty_cycle of the PWM signal is a multiple of
   the base period.
 - #pwm-cells: Should be 2. See pwm.txt in this directory for a description of
index 078834a..6e25c91 100644 (file)
@@ -24,9 +24,11 @@ ampire       Ampire Co., Ltd.
 ams    AMS AG
 amstaos        AMS-Taos Inc.
 analogix       Analogix Semiconductor, Inc.
+andestech      Andes Technology Corporation
 apm    Applied Micro Circuits Corporation (APM)
 aptina Aptina Imaging
 arasan Arasan Chip Systems
+aries  Aries Embedded GmbH
 arm    ARM Ltd.
 armadeus       ARMadeus Systems SARL
 arrow  Arrow Electronics
@@ -161,6 +163,7 @@ lg  LG Corporation
 linux  Linux-specific binding
 lltc   Linear Technology Corporation
 lsi    LSI Corp. (LSI Logic)
+macnica        Macnica Americas
 marvell        Marvell Technology Group Ltd.
 maxim  Maxim Integrated Products
 mcube  mCube
@@ -186,6 +189,7 @@ mti Imagination Technologies Ltd. (formerly MIPS Technologies Inc.)
 mundoreader    Mundo Reader S.L.
 murata Murata Manufacturing Co., Ltd.
 mxicy  Macronix International Co., Ltd.
+myir   MYIR Tech Limited
 national       National Semiconductor
 nec    NEC LCD Technologies, Ltd.
 neonode                Neonode Inc.
@@ -193,13 +197,15 @@ netgear   NETGEAR
 netlogic       Broadcom Corporation (formerly NetLogic Microsystems)
 netxeon                Shenzhen Netxeon Technology CO., LTD
 newhaven       Newhaven Display International
-nvd    New Vision Display
+ni     National Instruments
 nintendo       Nintendo
 nokia  Nokia
 nuvoton        Nuvoton Technology Corporation
+nvd    New Vision Display
 nvidia NVIDIA
 nxp    NXP Semiconductors
 okaya  Okaya Electric America, Inc.
+oki    Oki Electric Industry Co., Ltd.
 olimex OLIMEX Ltd.
 onion  Onion Corporation
 onnn   ON Semiconductor Corp.
@@ -238,6 +244,7 @@ richtek     Richtek Technology Corporation
 ricoh  Ricoh Co. Ltd.
 rockchip       Fuzhou Rockchip Electronics Co., Ltd
 samsung        Samsung Semiconductor
+samtec Samtec/Softing company
 sandisk        Sandisk Corporation
 sbs    Smart Battery System
 schindler      Schindler
@@ -282,6 +289,7 @@ tcg Trusted Computing Group
 tcl    Toby Churchill Ltd.
 technexion     TechNexion
 technologic    Technologic Systems
+terasic        Terasic Inc.
 thine  THine Electronics, Inc.
 ti     Texas Instruments
 tlm    Trusted Logic Mobility
@@ -296,6 +304,7 @@ tronfy      Tronfy
 tronsmart      Tronsmart
 truly  Truly Semiconductors Limited
 tyan   Tyan Computer Corporation
+udoo   Udoo
 uniwest        United Western Technologies Corp (UniWest)
 upisemi        uPI Semiconductor Corp.
 urt    United Radiant Technology Corporation
index a0bccb5..d4bea3c 100644 (file)
@@ -1534,9 +1534,12 @@ void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
 {
        int i;
        printk("%s %s", msg, of_node_full_name(args->np));
-       for (i = 0; i < args->args_count; i++)
-               printk(i ? ",%08x" : ":%08x", args->args[i]);
-       printk("\n");
+       for (i = 0; i < args->args_count; i++) {
+               const char delim = i ? ',' : ':';
+
+               pr_cont("%c%08x", delim, args->args[i]);
+       }
+       pr_cont("\n");
 }
 
 int of_phandle_iterator_init(struct of_phandle_iterator *it,
index f63d4b0..a53982a 100644 (file)
@@ -176,7 +176,12 @@ int of_node_to_nid(struct device_node *device)
                        np->name);
        of_node_put(np);
 
-       if (!r)
+       /*
+        * If numa=off passed on command line, or with a defective
+        * device tree, the nid may not be in the set of possible
+        * nodes.  Check for this case and return NUMA_NO_NODE.
+        */
+       if (!r && nid < MAX_NUMNODES && node_possible(nid))
                return nid;
 
        return NUMA_NO_NODE;
index e4bf07d..b8064bc 100644 (file)
@@ -45,6 +45,9 @@ static int of_dev_node_match(struct device *dev, void *data)
  * of_find_device_by_node - Find the platform_device associated with a node
  * @np: Pointer to device tree node
  *
+ * Takes a reference to the embedded struct device which needs to be dropped
+ * after use.
+ *
  * Returns platform_device pointer, or NULL if not found
  */
 struct platform_device *of_find_device_by_node(struct device_node *np)
@@ -558,9 +561,6 @@ static int of_platform_device_destroy(struct device *dev, void *data)
  * of the given device (and, recurrently, their children) that have been
  * created from their respective device tree nodes (and only those,
  * leaving others - eg. manually created - unharmed).
- *
- * Returns 0 when all children devices have been removed or
- * -EBUSY when some children remained.
  */
 void of_platform_depopulate(struct device *parent)
 {
index 46325d6..8bf12e9 100644 (file)
  * Find a node with the give full name by recursively following any of
  * the child node links.
  */
-static struct device_node *__of_find_node_by_full_name(struct device_node *node,
+static struct device_node *find_node_by_full_name(struct device_node *node,
                const char *full_name)
 {
        struct device_node *child, *found;
 
-       if (node == NULL)
+       if (!node)
                return NULL;
 
-       /* check */
-       if (of_node_cmp(node->full_name, full_name) == 0)
+       if (!of_node_cmp(node->full_name, full_name))
                return of_node_get(node);
 
        for_each_child_of_node(node, child) {
-               found = __of_find_node_by_full_name(child, full_name);
+               found = find_node_by_full_name(child, full_name);
                if (found != NULL) {
                        of_node_put(child);
                        return found;
@@ -51,16 +50,12 @@ static struct device_node *__of_find_node_by_full_name(struct device_node *node,
        return NULL;
 }
 
-/*
- * Find live tree's maximum phandle value.
- */
-static phandle of_get_tree_max_phandle(void)
+static phandle live_tree_max_phandle(void)
 {
        struct device_node *node;
        phandle phandle;
        unsigned long flags;
 
-       /* now search recursively */
        raw_spin_lock_irqsave(&devtree_lock, flags);
        phandle = 0;
        for_each_of_allnodes(node) {
@@ -73,131 +68,102 @@ static phandle of_get_tree_max_phandle(void)
        return phandle;
 }
 
-/*
- * Adjust a subtree's phandle values by a given delta.
- * Makes sure not to just adjust the device node's phandle value,
- * but modify the phandle properties values as well.
- */
-static void __of_adjust_tree_phandles(struct device_node *node,
+static void adjust_overlay_phandles(struct device_node *overlay,
                int phandle_delta)
 {
        struct device_node *child;
        struct property *prop;
        phandle phandle;
 
-       /* first adjust the node's phandle direct value */
-       if (node->phandle != 0 && node->phandle != OF_PHANDLE_ILLEGAL)
-               node->phandle += phandle_delta;
+       /* adjust node's phandle in node */
+       if (overlay->phandle != 0 && overlay->phandle != OF_PHANDLE_ILLEGAL)
+               overlay->phandle += phandle_delta;
 
-       /* now adjust phandle & linux,phandle values */
-       for_each_property_of_node(node, prop) {
+       /* copy adjusted phandle into *phandle properties */
+       for_each_property_of_node(overlay, prop) {
 
-               /* only look for these two */
-               if (of_prop_cmp(prop->name, "phandle") != 0 &&
-                   of_prop_cmp(prop->name, "linux,phandle") != 0)
+               if (of_prop_cmp(prop->name, "phandle") &&
+                   of_prop_cmp(prop->name, "linux,phandle"))
                        continue;
 
-               /* must be big enough */
                if (prop->length < 4)
                        continue;
 
-               /* read phandle value */
                phandle = be32_to_cpup(prop->value);
-               if (phandle == OF_PHANDLE_ILLEGAL)      /* unresolved */
+               if (phandle == OF_PHANDLE_ILLEGAL)
                        continue;
 
-               /* adjust */
-               *(uint32_t *)prop->value = cpu_to_be32(node->phandle);
+               *(uint32_t *)prop->value = cpu_to_be32(overlay->phandle);
        }
 
-       /* now do the children recursively */
-       for_each_child_of_node(node, child)
-               __of_adjust_tree_phandles(child, phandle_delta);
+       for_each_child_of_node(overlay, child)
+               adjust_overlay_phandles(child, phandle_delta);
 }
 
-static int __of_adjust_phandle_ref(struct device_node *node,
-               struct property *rprop, int value)
+static int update_usages_of_a_phandle_reference(struct device_node *overlay,
+               struct property *prop_fixup, phandle phandle)
 {
-       phandle phandle;
        struct device_node *refnode;
-       struct property *sprop;
-       char *propval, *propcur, *propend, *nodestr, *propstr, *s;
-       int offset, propcurlen;
+       struct property *prop;
+       char *value, *cur, *end, *node_path, *prop_name, *s;
+       int offset, len;
        int err = 0;
 
-       /* make a copy */
-       propval = kmalloc(rprop->length, GFP_KERNEL);
-       if (!propval) {
-               pr_err("%s: Could not copy value of '%s'\n",
-                               __func__, rprop->name);
+       value = kmalloc(prop_fixup->length, GFP_KERNEL);
+       if (!value)
                return -ENOMEM;
-       }
-       memcpy(propval, rprop->value, rprop->length);
+       memcpy(value, prop_fixup->value, prop_fixup->length);
 
-       propend = propval + rprop->length;
-       for (propcur = propval; propcur < propend; propcur += propcurlen + 1) {
-               propcurlen = strlen(propcur);
+       /* prop_fixup contains a list of tuples of path:property_name:offset */
+       end = value + prop_fixup->length;
+       for (cur = value; cur < end; cur += len + 1) {
+               len = strlen(cur);
 
-               nodestr = propcur;
-               s = strchr(propcur, ':');
+               node_path = cur;
+               s = strchr(cur, ':');
                if (!s) {
-                       pr_err("%s: Illegal symbol entry '%s' (1)\n",
-                               __func__, propcur);
                        err = -EINVAL;
                        goto err_fail;
                }
                *s++ = '\0';
 
-               propstr = s;
+               prop_name = s;
                s = strchr(s, ':');
                if (!s) {
-                       pr_err("%s: Illegal symbol entry '%s' (2)\n",
-                               __func__, (char *)rprop->value);
                        err = -EINVAL;
                        goto err_fail;
                }
-
                *s++ = '\0';
+
                err = kstrtoint(s, 10, &offset);
-               if (err != 0) {
-                       pr_err("%s: Could get offset '%s'\n",
-                               __func__, (char *)rprop->value);
+               if (err)
                        goto err_fail;
-               }
 
-               /* look into the resolve node for the full path */
-               refnode = __of_find_node_by_full_name(node, nodestr);
-               if (!refnode) {
-                       pr_warn("%s: Could not find refnode '%s'\n",
-                               __func__, (char *)rprop->value);
+               refnode = find_node_by_full_name(overlay, node_path);
+               if (!refnode)
                        continue;
-               }
 
-               /* now find the property */
-               for_each_property_of_node(refnode, sprop) {
-                       if (of_prop_cmp(sprop->name, propstr) == 0)
+               for_each_property_of_node(refnode, prop) {
+                       if (!of_prop_cmp(prop->name, prop_name))
                                break;
                }
                of_node_put(refnode);
 
-               if (!sprop) {
-                       pr_err("%s: Could not find property '%s'\n",
-                               __func__, (char *)rprop->value);
+               if (!prop) {
                        err = -ENOENT;
                        goto err_fail;
                }
 
-               phandle = value;
-               *(__be32 *)(sprop->value + offset) = cpu_to_be32(phandle);
+               *(__be32 *)(prop->value + offset) = cpu_to_be32(phandle);
        }
 
 err_fail:
-       kfree(propval);
+       kfree(value);
        return err;
 }
 
 /* compare nodes taking into account that 'name' strips out the @ part */
-static int __of_node_name_cmp(const struct device_node *dn1,
+static int node_name_cmp(const struct device_node *dn1,
                const struct device_node *dn2)
 {
        const char *n1 = strrchr(dn1->full_name, '/') ? : "/";
@@ -208,85 +174,77 @@ static int __of_node_name_cmp(const struct device_node *dn1,
 
 /*
  * Adjust the local phandle references by the given phandle delta.
- * Assumes the existances of a __local_fixups__ node at the root.
- * Assumes that __of_verify_tree_phandle_references has been called.
- * Does not take any devtree locks so make sure you call this on a tree
- * which is at the detached state.
+ *
+ * Subtree @local_fixups, which is overlay node __local_fixups__,
+ * mirrors the fragment node structure at the root of the overlay.
+ *
+ * For each property in the fragments that contains a phandle reference,
+ * @local_fixups has a property of the same name that contains a list
+ * of offsets of the phandle reference(s) within the respective property
+ * value(s).  The values at these offsets will be fixed up.
  */
-static int __of_adjust_tree_phandle_references(struct device_node *node,
-               struct device_node *target, int phandle_delta)
+static int adjust_local_phandle_references(struct device_node *local_fixups,
+               struct device_node *overlay, int phandle_delta)
 {
-       struct device_node *child, *childtarget;
-       struct property *rprop, *sprop;
+       struct device_node *child, *overlay_child;
+       struct property *prop_fix, *prop;
        int err, i, count;
        unsigned int off;
        phandle phandle;
 
-       if (node == NULL)
+       if (!local_fixups)
                return 0;
 
-       for_each_property_of_node(node, rprop) {
+       for_each_property_of_node(local_fixups, prop_fix) {
 
                /* skip properties added automatically */
-               if (of_prop_cmp(rprop->name, "name") == 0 ||
-                   of_prop_cmp(rprop->name, "phandle") == 0 ||
-                   of_prop_cmp(rprop->name, "linux,phandle") == 0)
+               if (!of_prop_cmp(prop_fix->name, "name") ||
+                   !of_prop_cmp(prop_fix->name, "phandle") ||
+                   !of_prop_cmp(prop_fix->name, "linux,phandle"))
                        continue;
 
-               if ((rprop->length % 4) != 0 || rprop->length == 0) {
-                       pr_err("%s: Illegal property (size) '%s' @%s\n",
-                                       __func__, rprop->name, node->full_name);
+               if ((prop_fix->length % 4) != 0 || prop_fix->length == 0)
                        return -EINVAL;
-               }
-               count = rprop->length / sizeof(__be32);
+               count = prop_fix->length / sizeof(__be32);
 
-               /* now find the target property */
-               for_each_property_of_node(target, sprop) {
-                       if (of_prop_cmp(sprop->name, rprop->name) == 0)
+               for_each_property_of_node(overlay, prop) {
+                       if (!of_prop_cmp(prop->name, prop_fix->name))
                                break;
                }
 
-               if (sprop == NULL) {
-                       pr_err("%s: Could not find target property '%s' @%s\n",
-                                       __func__, rprop->name, node->full_name);
+               if (!prop)
                        return -EINVAL;
-               }
 
                for (i = 0; i < count; i++) {
-                       off = be32_to_cpu(((__be32 *)rprop->value)[i]);
-                       /* make sure the offset doesn't overstep (even wrap) */
-                       if (off >= sprop->length ||
-                                       (off + 4) > sprop->length) {
-                               pr_err("%s: Illegal property '%s' @%s\n",
-                                               __func__, rprop->name,
-                                               node->full_name);
+                       off = be32_to_cpu(((__be32 *)prop_fix->value)[i]);
+                       if ((off + 4) > prop->length)
                                return -EINVAL;
-                       }
-
-                       if (phandle_delta) {
-                               /* adjust */
-                               phandle = be32_to_cpu(*(__be32 *)(sprop->value + off));
-                               phandle += phandle_delta;
-                               *(__be32 *)(sprop->value + off) = cpu_to_be32(phandle);
-                       }
+
+                       phandle = be32_to_cpu(*(__be32 *)(prop->value + off));
+                       phandle += phandle_delta;
+                       *(__be32 *)(prop->value + off) = cpu_to_be32(phandle);
                }
        }
 
-       for_each_child_of_node(node, child) {
-
-               for_each_child_of_node(target, childtarget)
-                       if (__of_node_name_cmp(child, childtarget) == 0)
+       /*
+        * These nested loops recurse down two subtrees in parallel, where the
+        * node names in the two subtrees match.
+        *
+        * The roots of the subtrees are the overlay's __local_fixups__ node
+        * and the overlay's root node.
+        */
+       for_each_child_of_node(local_fixups, child) {
+
+               for_each_child_of_node(overlay, overlay_child)
+                       if (!node_name_cmp(child, overlay_child))
                                break;
 
-               if (!childtarget) {
-                       pr_err("%s: Could not find target child '%s' @%s\n",
-                                       __func__, child->name, node->full_name);
+               if (!overlay_child)
                        return -EINVAL;
-               }
 
-               err = __of_adjust_tree_phandle_references(child, childtarget,
+               err = adjust_local_phandle_references(child, overlay_child,
                                phandle_delta);
-               if (err != 0)
+               if (err)
                        return err;
        }
 
@@ -294,111 +252,103 @@ static int __of_adjust_tree_phandle_references(struct device_node *node,
 }
 
 /**
- * of_resolve  - Resolve the given node against the live tree.
+ * of_resolve_phandles - Relocate and resolve overlay against live tree
  *
- * @resolve:   Node to resolve
+ * @overlay:   Pointer to devicetree overlay to relocate and resolve
  *
- * Perform dynamic Device Tree resolution against the live tree
- * to the given node to resolve. This depends on the live tree
- * having a __symbols__ node, and the resolve node the __fixups__ &
- * __local_fixups__ nodes (if needed).
- * The result of the operation is a resolve node that it's contents
- * are fit to be inserted or operate upon the live tree.
- * Returns 0 on success or a negative error value on error.
+ * Modify (relocate) values of local phandles in @overlay to a range that
+ * does not conflict with the live expanded devicetree.  Update references
+ * to the local phandles in @overlay.  Update (resolve) phandle references
+ * in @overlay that refer to the live expanded devicetree.
+ *
+ * Phandle values in the live tree are in the range of
+ * 1 .. live_tree_max_phandle().  The range of phandle values in the overlay
+ * also begin with at 1.  Adjust the phandle values in the overlay to begin
+ * at live_tree_max_phandle() + 1.  Update references to the phandles to
+ * the adjusted phandle values.
+ *
+ * The name of each property in the "__fixups__" node in the overlay matches
+ * the name of a symbol (a label) in the live tree.  The values of each
+ * property in the "__fixups__" node is a list of the property values in the
+ * overlay that need to be updated to contain the phandle reference
+ * corresponding to that symbol in the live tree.  Update the references in
+ * the overlay with the phandle values in the live tree.
+ *
+ * @overlay must be detached.
+ *
+ * Resolving and applying @overlay to the live expanded devicetree must be
+ * protected by a mechanism to ensure that multiple overlays are processed
+ * in a single threaded manner so that multiple overlays will not relocate
+ * phandles to overlapping ranges.  The mechanism to enforce this is not
+ * yet implemented.
+ *
+ * Return: %0 on success or a negative error value on error.
  */
-int of_resolve_phandles(struct device_node *resolve)
+int of_resolve_phandles(struct device_node *overlay)
 {
-       struct device_node *child, *childroot, *refnode;
-       struct device_node *root_sym, *resolve_sym, *resolve_fix;
-       struct property *rprop;
+       struct device_node *child, *local_fixups, *refnode;
+       struct device_node *tree_symbols, *overlay_fixups;
+       struct property *prop;
        const char *refpath;
        phandle phandle, phandle_delta;
        int err;
 
-       if (!resolve)
-               pr_err("%s: null node\n", __func__);
-       if (resolve && !of_node_check_flag(resolve, OF_DETACHED))
-               pr_err("%s: node %s not detached\n", __func__,
-                        resolve->full_name);
-       /* the resolve node must exist, and be detached */
-       if (!resolve || !of_node_check_flag(resolve, OF_DETACHED))
-               return -EINVAL;
-
-       /* first we need to adjust the phandles */
-       phandle_delta = of_get_tree_max_phandle() + 1;
-       __of_adjust_tree_phandles(resolve, phandle_delta);
-
-       /* locate the local fixups */
-       childroot = NULL;
-       for_each_child_of_node(resolve, childroot)
-               if (of_node_cmp(childroot->name, "__local_fixups__") == 0)
-                       break;
-
-       if (childroot != NULL) {
-               /* resolve root is guaranteed to be the '/' */
-               err = __of_adjust_tree_phandle_references(childroot,
-                               resolve, 0);
-               if (err != 0)
-                       return err;
+       tree_symbols = NULL;
 
-               BUG_ON(__of_adjust_tree_phandle_references(childroot,
-                               resolve, phandle_delta));
+       if (!overlay) {
+               pr_err("null overlay\n");
+               err = -EINVAL;
+               goto out;
+       }
+       if (!of_node_check_flag(overlay, OF_DETACHED)) {
+               pr_err("overlay not detached\n");
+               err = -EINVAL;
+               goto out;
        }
 
-       root_sym = NULL;
-       resolve_sym = NULL;
-       resolve_fix = NULL;
-
-       /* this may fail (if no fixups are required) */
-       root_sym = of_find_node_by_path("/__symbols__");
+       phandle_delta = live_tree_max_phandle() + 1;
+       adjust_overlay_phandles(overlay, phandle_delta);
 
-       /* locate the symbols & fixups nodes on resolve */
-       for_each_child_of_node(resolve, child) {
+       for_each_child_of_node(overlay, local_fixups)
+               if (!of_node_cmp(local_fixups->name, "__local_fixups__"))
+                       break;
 
-               if (!resolve_sym &&
-                               of_node_cmp(child->name, "__symbols__") == 0)
-                       resolve_sym = child;
+       err = adjust_local_phandle_references(local_fixups, overlay, phandle_delta);
+       if (err)
+               goto out;
 
-               if (!resolve_fix &&
-                               of_node_cmp(child->name, "__fixups__") == 0)
-                       resolve_fix = child;
+       overlay_fixups = NULL;
 
-               /* both found, don't bother anymore */
-               if (resolve_sym && resolve_fix)
-                       break;
+       for_each_child_of_node(overlay, child) {
+               if (!of_node_cmp(child->name, "__fixups__"))
+                       overlay_fixups = child;
        }
 
-       /* we do allow for the case where no fixups are needed */
-       if (!resolve_fix) {
-               err = 0;        /* no error */
+       if (!overlay_fixups) {
+               err = 0;
                goto out;
        }
 
-       /* we need to fixup, but no root symbols... */
-       if (!root_sym) {
-               pr_err("%s: no symbols in root of device tree.\n", __func__);
+       tree_symbols = of_find_node_by_path("/__symbols__");
+       if (!tree_symbols) {
+               pr_err("no symbols in root of device tree.\n");
                err = -EINVAL;
                goto out;
        }
 
-       for_each_property_of_node(resolve_fix, rprop) {
+       for_each_property_of_node(overlay_fixups, prop) {
 
                /* skip properties added automatically */
-               if (of_prop_cmp(rprop->name, "name") == 0)
+               if (!of_prop_cmp(prop->name, "name"))
                        continue;
 
-               err = of_property_read_string(root_sym,
-                               rprop->name, &refpath);
-               if (err != 0) {
-                       pr_err("%s: Could not find symbol '%s'\n",
-                                       __func__, rprop->name);
+               err = of_property_read_string(tree_symbols,
+                               prop->name, &refpath);
+               if (err)
                        goto out;
-               }
 
                refnode = of_find_node_by_path(refpath);
                if (!refnode) {
-                       pr_err("%s: Could not find node by path '%s'\n",
-                                       __func__, refpath);
                        err = -ENOENT;
                        goto out;
                }
@@ -406,17 +356,15 @@ int of_resolve_phandles(struct device_node *resolve)
                phandle = refnode->phandle;
                of_node_put(refnode);
 
-               pr_debug("%s: %s phandle is 0x%08x\n",
-                               __func__, rprop->name, phandle);
-
-               err = __of_adjust_phandle_ref(resolve, rprop, phandle);
+               err = update_usages_of_a_phandle_reference(overlay, prop, phandle);
                if (err)
                        break;
        }
 
 out:
-       /* NULL is handled by of_node_put as NOP */
-       of_node_put(root_sym);
+       if (err)
+               pr_err("overlay phandle fixup failed: %d\n", err);
+       of_node_put(tree_symbols);
 
        return err;
 }