Browse Source

Allow device tree to be modified by additonal device tree sections

This patch allows the following construct:

/ {
	property-a = "old";
	property-b = "does not change";
};

/ {
	property-a = "changed";
	property-c = "new";
	node-a {
	};
};

Where the later device tree overrides the properties found in the
earlier tree.  This is useful for laying down a template device tree
in an include file and modifying it for a specific board without having
to clone the entire tree.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
main
Grant Likely 15 years ago committed by Jon Loeliger
parent
commit
83da1b2a4e
  1. 14
      dtc-parser.y
  2. 1
      dtc.h
  3. 75
      livetree.c
  4. 12
      tests/multilabel.dts
  5. 66
      tests/multilabel_merge.dts
  6. 7
      tests/run_tests.sh
  7. 45
      tests/test_tree1_merge.dts

14
dtc-parser.y

@ -75,6 +75,7 @@ static unsigned long long eval_literal(const char *s, int base, int bits); @@ -75,6 +75,7 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
%type <proplist> proplist

%type <node> devicetree
%type <node> devicetrees
%type <node> nodedef
%type <node> subnode
%type <nodelist> subnodes
@ -82,7 +83,7 @@ static unsigned long long eval_literal(const char *s, int base, int bits); @@ -82,7 +83,7 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
%%

sourcefile:
DT_V1 ';' memreserves devicetree
DT_V1 ';' memreserves devicetrees
{
the_boot_info = build_boot_info($3, $4,
guess_boot_cpuid($4));
@ -119,6 +120,17 @@ addr: @@ -119,6 +120,17 @@ addr:
}
;

devicetrees:
devicetree
{
$$ = $1;
}
| devicetrees devicetree
{
$$ = merge_nodes($1, $2);
}
;

devicetree:
'/' nodedef
{

1
dtc.h

@ -174,6 +174,7 @@ struct property *reverse_properties(struct property *first); @@ -174,6 +174,7 @@ struct property *reverse_properties(struct property *first);
struct node *build_node(struct property *proplist, struct node *children);
struct node *name_node(struct node *node, char *name);
struct node *chain_node(struct node *first, struct node *list);
struct node *merge_nodes(struct node *old_node, struct node *new_node);

void add_property(struct node *node, struct property *prop);
void add_child(struct node *parent, struct node *child);

75
livetree.c

@ -26,8 +26,14 @@ @@ -26,8 +26,14 @@

void add_label(struct label **labels, char *label)
{
struct label *new = xmalloc(sizeof(*new));
struct label *new;

/* Make sure the label isn't already there */
for_each_label(*labels, new)
if (streq(new->label, label))
return;

new = xmalloc(sizeof(*new));
new->label = label;
new->next = *labels;
*labels = new;
@ -94,6 +100,73 @@ struct node *name_node(struct node *node, char *name) @@ -94,6 +100,73 @@ struct node *name_node(struct node *node, char *name)
return node;
}

struct node *merge_nodes(struct node *old_node, struct node *new_node)
{
struct property *new_prop, *old_prop;
struct node *new_child, *old_child;
struct label *l;

/* Add new node labels to old node */
for_each_label(new_node->labels, l)
add_label(&old_node->labels, l->label);

/* Move properties from the new node to the old node. If there
* is a collision, replace the old value with the new */
while (new_node->proplist) {
/* Pop the property off the list */
new_prop = new_node->proplist;
new_node->proplist = new_prop->next;
new_prop->next = NULL;

/* Look for a collision, set new value if there is */
for_each_property(old_node, old_prop) {
if (streq(old_prop->name, new_prop->name)) {
/* Add new labels to old property */
for_each_label(new_prop->labels, l)
add_label(&old_prop->labels, l->label);

old_prop->val = new_prop->val;
free(new_prop);
new_prop = NULL;
break;
}
}

/* if no collision occurred, add property to the old node. */
if (new_prop)
add_property(old_node, new_prop);
}

/* Move the override child nodes into the primary node. If
* there is a collision, then merge the nodes. */
while (new_node->children) {
/* Pop the child node off the list */
new_child = new_node->children;
new_node->children = new_child->next_sibling;
new_child->parent = NULL;
new_child->next_sibling = NULL;

/* Search for a collision. Merge if there is */
for_each_child(old_node, old_child) {
if (streq(old_child->name, new_child->name)) {
merge_nodes(old_child, new_child);
new_child = NULL;
break;
}
}

/* if no collision occured, add child to the old node. */
if (new_child)
add_child(old_node, new_child);
}

/* The new node contents are now merged into the old node. Free
* the new node. */
free(new_node);

return old_node;
}

struct node *chain_node(struct node *first, struct node *list)
{
assert(first->next_sibling == NULL);

12
tests/multilabel.dts

@ -3,26 +3,27 @@ @@ -3,26 +3,27 @@
m1: mq: /memreserve/ 0 0x1000;

/ {
p1: px: prop = "foo";
p0: pw: prop = "foo";

/* Explicit phandles */
n1: nx: node1 {
linux,phandle = <0x2000>;
ref = <&{/node2}>; /* reference precedes target */
lref = <&ny>;
p1: px: lref = <&ny>;
};
ny: n2: node2 {
phandle = <0x1>;
p2: py: phandle = <0x1>;
ref = <&{/node1}>; /* reference after target */
lref = <&nx>;
};

/* Implicit phandles */
n3: node3 {
ref = <&{/node4}>;
p3: ref = <&{/node4}>;
lref = <&n4>;
};
n4: node4 {
p4: prop;
};

/* Explicit phandle with implicit value */
@ -34,5 +35,8 @@ m1: mq: /memreserve/ 0 0x1000; @@ -34,5 +35,8 @@ m1: mq: /memreserve/ 0 0x1000;
n5: nz: node5 {
linux,phandle = <&n5>;
phandle = <&nz>;
n1 = &n1;
n2 = &n2;
n3 = &n3;
};
};

66
tests/multilabel_merge.dts

@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
/dts-v1/;

m1: mq: /memreserve/ 0 0x1000;

/ {
p0: pw: prop = "foo";

/* Explicit phandles */
n1: node1 {
linux,phandle = <0x2000>;
ref = <&{/node2}>; /* reference precedes target */
p1: lref;
};
node2 {
phandle = <0x1>;
ref = <&{/node1}>; /* reference after target */
lref = <&nx>;
};

/* Implicit phandles */
n3: node3 {
p3: ref = <&{/node4}>;
lref = <&n4>;
};
n4: node4 {
p4: prop = "foo";
};

/* Explicit phandle with implicit value */
/* This self-reference is the standard way to tag a node as requiring
* a phandle (perhaps for reference by nodes that will be dynamically
* added) without explicitly allocating it a phandle.
* The self-reference requires some special internal handling, though
* so check it actually works */
n5: nz: node5 {
linux,phandle = <&n5>;
phandle = <&nz>;
n1 = &n1;
n2 = &n2;
n3 = &n3;
};
};

/ {
/* Append labels (also changes property content) */
nx: node1 {
px: lref = <&ny>;
};

/* Add multiple labels */
ny: n2: node2 {
/* Add a label to a property */
p2: py: phandle = <0x1>;
};

/* Reassigning the same label should be a no-op */
n3: node3 {
p3: ref = <&{/node4}>;
};

/* Redefining a node/property should not remove labels */
node4 {
prop;
};

};

7
tests/run_tests.sh

@ -297,6 +297,13 @@ dtc_tests () { @@ -297,6 +297,13 @@ dtc_tests () {
done
done

# Check merge/overlay functionality
run_dtc_test -I dts -O dtb -o dtc_tree1_merge.test.dtb test_tree1_merge.dts
tree1_tests dtc_tree1_merge.test.dtb test_tree1.dtb
run_dtc_test -I dts -O dtb -o multilabel_merge.test.dtb multilabel_merge.dts
run_test references multilabel.test.dtb
run_test dtbs_equal_ordered multilabel.test.dtb multilabel_merge.test.dtb

# Check some checks
check_tests dup-nodename.dts duplicate_node_names
check_tests dup-propname.dts duplicate_property_names

45
tests/test_tree1_merge.dts

@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
/dts-v1/;
/memreserve/ 0xdeadbeef00000000 0x100000;
/memreserve/ 123456789 010000;

/ {
compatible = "test_tree1";
prop-int = "wrong!";
prop-str = "hello world";

subnode@1 {
compatible = "subnode1";

subsubnode {
compatible = "subsubnode1", "subsubnode";
prop-int = <0xdeadbeef>;
};

ss1 {
};
};

subnode@2 {
linux,phandle = <0x2000>;
prop-int = <123456789>;

ss2 {
};
};
};

/ {
prop-int = <0xdeadbeef>;
subnode@1 {
prop-int = [deadbeef];
};
subnode@2 {
subsubnode@0 {
phandle = <0x2001>;
compatible = "subsubnode2", "subsubnode";
prop-int = <0726746425>;
};
};
};


Loading…
Cancel
Save