dtc: add ability to make nodes conditional on them being referenced
authorMaxime Ripard <maxime.ripard@bootlin.com>
Tue, 21 Jan 2020 10:23:17 +0000 (10:23 +0000)
committerSimon Glass <sjg@chromium.org>
Thu, 6 Feb 2020 02:33:46 +0000 (19:33 -0700)
This is needed when importing mainline DTs into U-Boot, as some started
using this /omit-if-no-ref/ tag, so won't compile with U-Boot's current
dtc copy. This is just a cherry-pick of the patch introducing this
feature.
Original commit message from Maxime:
------------------
A number of platforms have a need to reduce the number of DT nodes,
mostly because of two similar constraints: the size of the DT blob, and
the time it takes to parse it.

As the DT is used in more and more SoCs, and by more projects, some
constraints start to appear in bootloaders running from SRAM with an
order of magnitude of 10kB. A typical DT is in the same order of
magnitude, so any effort to reduce the blob size is welcome in such an
environment.

Some platforms also want to reach very fast boot time, and the time it
takes to parse a typical DT starts to be noticeable.

Both of these issues can be mitigated by reducing the number of nodes in
the DT. The biggest provider of nodes is usually the pin controller and
its subnodes, usually one for each valid pin configuration in a given
SoC.

Obviously, a single, fixed, set of these nodes will be used by a given
board, so we can introduce a node property that will tell the DT
compiler to drop the nodes when they are not referenced in the tree, and
as such wouldn't be useful in the targetted system.

Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
scripts/dtc/checks.c
scripts/dtc/dtc-lexer.l
scripts/dtc/dtc-parser.y
scripts/dtc/dtc.h
scripts/dtc/livetree.c

index c07ba4da9e36119bfb5c8732f5b2178a46b09997..40879677c8c3af28bc646a98bd2c67c73ad55989 100644 (file)
@@ -579,6 +579,8 @@ static void fixup_phandle_references(struct check *c, struct dt_info *dti,
 
                        phandle = get_node_phandle(dt, refnode);
                        *((fdt32_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
+
+                       reference_node(refnode);
                }
        }
 }
@@ -609,11 +611,21 @@ static void fixup_path_references(struct check *c, struct dt_info *dti,
                        path = refnode->fullpath;
                        prop->val = data_insert_at_marker(prop->val, m, path,
                                                          strlen(path) + 1);
+
+                       reference_node(refnode);
                }
        }
 }
 ERROR(path_references, fixup_path_references, NULL, &duplicate_node_names);
 
+static void fixup_omit_unused_nodes(struct check *c, struct dt_info *dti,
+                                   struct node *node)
+{
+       if (node->omit_if_unused && !node->is_referenced)
+               delete_node(node);
+}
+ERROR(omit_unused_nodes, fixup_omit_unused_nodes, NULL, &phandle_references, &path_references);
+
 /*
  * Semantic checks
  */
@@ -1367,6 +1379,7 @@ static struct check *check_table[] = {
 
        &explicit_phandles,
        &phandle_references, &path_references,
+       &omit_unused_nodes,
 
        &address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell,
        &device_type_is_string, &model_is_string, &status_is_string,
index 24af549977584c33b302a470fe90fd9b42e6539d..d3694d6cf202d40cee9c14b07d6bc17d25314a76 100644 (file)
@@ -152,6 +152,13 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
                        return DT_DEL_NODE;
                }
 
+<*>"/omit-if-no-ref/"  {
+                       DPRINT("Keyword: /omit-if-no-ref/\n");
+                       DPRINT("<PROPNODENAME>\n");
+                       BEGIN(PROPNODENAME);
+                       return DT_OMIT_NO_REF;
+               }
+
 <*>{LABEL}:    {
                        DPRINT("Label: %s\n", yytext);
                        yylval.labelref = xstrdup(yytext);
index 44af170abfeaca34a94217d0cf7519568e27b72a..66ff7f7d8eb73ca4c4a2d1275caf788741366ed3 100644 (file)
@@ -63,6 +63,7 @@ extern bool treesource_error;
 %token DT_BITS
 %token DT_DEL_PROP
 %token DT_DEL_NODE
+%token DT_OMIT_NO_REF
 %token <propnodename> DT_PROPNODENAME
 %token <integer> DT_LITERAL
 %token <integer> DT_CHAR_LITERAL
@@ -217,6 +218,18 @@ devicetree:
                                ERROR(&@3, "Label or path %s not found", $3);
 
 
+                       $$ = $1;
+               }
+       | devicetree DT_OMIT_NO_REF DT_REF ';'
+               {
+                       struct node *target = get_node_by_ref($1, $3);
+
+                       if (target)
+                               omit_node_if_unused(target);
+                       else
+                               ERROR(&@3, "Label or path %s not found", $3);
+
+
                        $$ = $1;
                }
        ;
@@ -523,6 +536,10 @@ subnode:
                {
                        $$ = name_node(build_node_delete(), $2);
                }
+       | DT_OMIT_NO_REF subnode
+               {
+                       $$ = omit_node_if_unused($2);
+               }
        | DT_LABEL subnode
                {
                        add_label(&$2->labels, $1);
index 3b18a42b866e73323c0335997a79322f385312ed..6d667701ab6aa9027510b57eedc3f12ed5d9f8d5 100644 (file)
@@ -168,6 +168,8 @@ struct node {
 
        struct label *labels;
        const struct bus_type *bus;
+
+       bool omit_if_unused, is_referenced;
 };
 
 #define for_each_label_withdel(l0, l) \
@@ -202,6 +204,8 @@ struct property *reverse_properties(struct property *first);
 struct node *build_node(struct property *proplist, struct node *children);
 struct node *build_node_delete(void);
 struct node *name_node(struct node *node, char *name);
+struct node *omit_node_if_unused(struct node *node);
+struct node *reference_node(struct node *node);
 struct node *chain_node(struct node *first, struct node *list);
 struct node *merge_nodes(struct node *old_node, struct node *new_node);
 struct node *add_orphan_node(struct node *old_node, struct node *new_node, char *ref);
index 57b7db2ed1534873ea8f382c958d19038ba86916..81b6c484542d16eeee10d2c56d07f71be5b9022c 100644 (file)
@@ -134,6 +134,20 @@ struct node *name_node(struct node *node, char *name)
        return node;
 }
 
+struct node *omit_node_if_unused(struct node *node)
+{
+       node->omit_if_unused = 1;
+
+       return node;
+}
+
+struct node *reference_node(struct node *node)
+{
+       node->is_referenced = 1;
+
+       return node;
+}
+
 struct node *merge_nodes(struct node *old_node, struct node *new_node)
 {
        struct property *new_prop, *old_prop;