From 6d2f3b1b1974d742576b0902e9c4777c9ac1ba67 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 22 Oct 2017 22:21:21 +0200 Subject: [PATCH] package: kernel: dtc: Add DTO support Add patch with the DT overlay support into the DTC package. Signed-off-by: Marek Vasut --- ...-dtc-Update-to-version-with-overlays.patch | 642 ++++++++++++++++++ 1 file changed, 642 insertions(+) create mode 100644 package/kernel/dtc/patches/0001-scripts-dtc-Update-to-version-with-overlays.patch diff --git a/package/kernel/dtc/patches/0001-scripts-dtc-Update-to-version-with-overlays.patch b/package/kernel/dtc/patches/0001-scripts-dtc-Update-to-version-with-overlays.patch new file mode 100644 index 0000000000..605d303c47 --- /dev/null +++ b/package/kernel/dtc/patches/0001-scripts-dtc-Update-to-version-with-overlays.patch @@ -0,0 +1,642 @@ +From 5f84cb93eef9f8a8ff7f49d593893f252744d0fe Mon Sep 17 00:00:00 2001 +From: Pantelis Antoniou +Date: Wed, 26 Aug 2015 18:28:08 +0300 +Subject: [PATCH] scripts/dtc: Update to version with overlays + +Update to mainline dtc with overlay support + +Signed-off-by: Pantelis Antoniou +--- + checks.c | 20 +++++- + dtc-lexer.l | 5 ++ + dtc-parser.y | 54 ++++++++++++++-- + dtc.c | 83 ++++++++++++++++++++++-- + dtc.h | 13 +++- + livetree.c | 202 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + treesource.c | 3 + + util.c | 2 +- + 8 files changed, 367 insertions(+), 15 deletions(-) + +diff --git a/checks.c b/checks.c +index 3bf0fa4..af25c2b 100644 +--- a/checks.c ++++ b/checks.c +@@ -465,8 +465,12 @@ static void fixup_phandle_references(struct check *c, struct node *dt, + + refnode = get_node_by_ref(dt, m->ref); + if (! refnode) { +- FAIL(c, "Reference to non-existent node or label \"%s\"\n", +- m->ref); ++ if (!source_is_plugin) ++ FAIL(c, "Reference to non-existent node or " ++ "label \"%s\"\n", m->ref); ++ else /* mark the entry as unresolved */ ++ *((cell_t *)(prop->val.val + m->offset)) = ++ cpu_to_fdt32(0xffffffff); + continue; + } + +@@ -559,7 +563,7 @@ static void check_reg_format(struct check *c, struct node *dt, + size_cells = node_size_cells(node->parent); + entrylen = (addr_cells + size_cells) * sizeof(cell_t); + +- if ((prop->val.len % entrylen) != 0) ++ if (!entrylen || (prop->val.len % entrylen) != 0) + FAIL(c, "\"reg\" property in %s has invalid length (%d bytes) " + "(#address-cells == %d, #size-cells == %d)", + node->fullpath, prop->val.len, addr_cells, size_cells); +@@ -651,6 +655,15 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c, + } + TREE_WARNING(obsolete_chosen_interrupt_controller, NULL); + ++static void check_deprecated_plugin_syntax(struct check *c, ++ struct node *dt) ++{ ++ if (deprecated_plugin_syntax_warning) ++ FAIL(c, "Use '/dts-v1/ /plugin/'; syntax. /dts-v1/; /plugin/; " ++ "is going to be removed in next versions"); ++} ++TREE_WARNING(deprecated_plugin_syntax, NULL); ++ + static struct check *check_table[] = { + &duplicate_node_names, &duplicate_property_names, + &node_name_chars, &node_name_format, &property_name_chars, +@@ -668,6 +681,7 @@ static struct check *check_table[] = { + + &avoid_default_addr_size, + &obsolete_chosen_interrupt_controller, ++ &deprecated_plugin_syntax, + + &always_fail, + }; +diff --git a/dtc-lexer.l b/dtc-lexer.l +index 0ee1caf..dd44ba2 100644 +--- a/dtc-lexer.l ++++ b/dtc-lexer.l +@@ -113,6 +113,11 @@ static void lexical_error(const char *fmt, ...); + return DT_V1; + } + ++<*>"/plugin/" { ++ DPRINT("Keyword: /plugin/\n"); ++ return DT_PLUGIN; ++ } ++ + <*>"/memreserve/" { + DPRINT("Keyword: /memreserve/\n"); + BEGIN_DEFAULT(); +diff --git a/dtc-parser.y b/dtc-parser.y +index ea57e0a..7d9652d 100644 +--- a/dtc-parser.y ++++ b/dtc-parser.y +@@ -19,6 +19,7 @@ + */ + %{ + #include ++#include + + #include "dtc.h" + #include "srcpos.h" +@@ -52,9 +53,11 @@ extern bool treesource_error; + struct node *nodelist; + struct reserve_info *re; + uint64_t integer; ++ bool is_plugin; + } + + %token DT_V1 ++%token DT_PLUGIN + %token DT_MEMRESERVE + %token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR + %token DT_BITS +@@ -71,6 +74,7 @@ extern bool treesource_error; + + %type propdata + %type propdataprefix ++%type plugindecl + %type memreserve + %type memreserves + %type arrayprefix +@@ -101,10 +105,39 @@ extern bool treesource_error; + %% + + sourcefile: +- DT_V1 ';' memreserves devicetree ++ basesource ++ | pluginsource ++ ; ++ ++basesource: ++ DT_V1 ';' plugindecl memreserves devicetree ++ { ++ source_is_plugin = $3; ++ if (source_is_plugin) ++ deprecated_plugin_syntax_warning = true; ++ the_boot_info = build_boot_info($4, $5, ++ guess_boot_cpuid($5)); ++ } ++ ; ++ ++plugindecl: ++ /* empty */ ++ { ++ $$ = false; ++ } ++ | DT_PLUGIN ';' ++ { ++ $$ = true; ++ } ++ ; ++ ++pluginsource: ++ DT_V1 DT_PLUGIN ';' memreserves devicetree + { +- the_boot_info = build_boot_info($3, $4, +- guess_boot_cpuid($4)); ++ source_is_plugin = true; ++ deprecated_plugin_syntax_warning = false; ++ the_boot_info = build_boot_info($4, $5, ++ guess_boot_cpuid($5)); + } + ; + +@@ -144,10 +177,14 @@ devicetree: + { + struct node *target = get_node_by_ref($1, $2); + +- if (target) ++ if (target) { + merge_nodes(target, $3); +- else +- ERROR(&@2, "Label or path %s not found", $2); ++ } else { ++ if (symbol_fixup_support) ++ add_orphan_node($1, $3, $2); ++ else ++ ERROR(&@2, "Label or path %s not found", $2); ++ } + $$ = $1; + } + | devicetree DT_DEL_NODE DT_REF ';' +@@ -162,6 +199,11 @@ devicetree: + + $$ = $1; + } ++ | /* empty */ ++ { ++ /* build empty node */ ++ $$ = name_node(build_node(NULL, NULL), ""); ++ } + ; + + nodedef: +diff --git a/dtc.c b/dtc.c +index 8c4add6..ee37be9 100644 +--- a/dtc.c ++++ b/dtc.c +@@ -18,6 +18,8 @@ + * USA + */ + ++#include ++ + #include "dtc.h" + #include "srcpos.h" + +@@ -29,6 +31,8 @@ int reservenum; /* Number of memory reservation slots */ + int minsize; /* Minimum blob size */ + int padsize; /* Additional padding to blob */ + int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */ ++int symbol_fixup_support; ++int auto_label_aliases; + + static void fill_fullpaths(struct node *tree, const char *prefix) + { +@@ -51,7 +55,7 @@ static void fill_fullpaths(struct node *tree, const char *prefix) + #define FDT_VERSION(version) _FDT_VERSION(version) + #define _FDT_VERSION(version) #version + static const char usage_synopsis[] = "dtc [options] "; +-static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv"; ++static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:@Ahv"; + static struct option const usage_long_opts[] = { + {"quiet", no_argument, NULL, 'q'}, + {"in-format", a_argument, NULL, 'I'}, +@@ -69,6 +73,8 @@ static struct option const usage_long_opts[] = { + {"phandle", a_argument, NULL, 'H'}, + {"warning", a_argument, NULL, 'W'}, + {"error", a_argument, NULL, 'E'}, ++ {"symbols", no_argument, NULL, '@'}, ++ {"auto-alias", no_argument, NULL, 'A'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, + {NULL, no_argument, NULL, 0x0}, +@@ -99,16 +105,63 @@ static const char * const usage_opts_help[] = { + "\t\tboth - Both \"linux,phandle\" and \"phandle\" properties", + "\n\tEnable/disable warnings (prefix with \"no-\")", + "\n\tEnable/disable errors (prefix with \"no-\")", ++ "\n\tEnable symbols/fixup support", ++ "\n\tEnable auto-alias of labels", + "\n\tPrint this help and exit", + "\n\tPrint version and exit", + NULL, + }; + ++static const char *guess_type_by_name(const char *fname, const char *fallback) ++{ ++ const char *s; ++ ++ s = strrchr(fname, '.'); ++ if (s == NULL) ++ return fallback; ++ if (!strcasecmp(s, ".dts")) ++ return "dts"; ++ if (!strcasecmp(s, ".dtb")) ++ return "dtb"; ++ return fallback; ++} ++ ++static const char *guess_input_format(const char *fname, const char *fallback) ++{ ++ struct stat statbuf; ++ uint32_t magic; ++ FILE *f; ++ ++ if (stat(fname, &statbuf) != 0) ++ return fallback; ++ ++ if (S_ISDIR(statbuf.st_mode)) ++ return "fs"; ++ ++ if (!S_ISREG(statbuf.st_mode)) ++ return fallback; ++ ++ f = fopen(fname, "r"); ++ if (f == NULL) ++ return fallback; ++ if (fread(&magic, 4, 1, f) != 1) { ++ fclose(f); ++ return fallback; ++ } ++ fclose(f); ++ ++ magic = fdt32_to_cpu(magic); ++ if (magic == FDT_MAGIC) ++ return "dtb"; ++ ++ return guess_type_by_name(fname, fallback); ++} ++ + int main(int argc, char *argv[]) + { + struct boot_info *bi; +- const char *inform = "dts"; +- const char *outform = "dts"; ++ const char *inform = NULL; ++ const char *outform = NULL; + const char *outname = "-"; + const char *depname = NULL; + bool force = false, sort = false; +@@ -186,7 +239,12 @@ int main(int argc, char *argv[]) + case 'E': + parse_checks_option(false, true, optarg); + break; +- ++ case '@': ++ symbol_fixup_support = 1; ++ break; ++ case 'A': ++ auto_label_aliases = 1; ++ break; + case 'h': + usage(NULL); + default: +@@ -213,6 +271,17 @@ int main(int argc, char *argv[]) + fprintf(depfile, "%s:", outname); + } + ++ if (inform == NULL) ++ inform = guess_input_format(arg, "dts"); ++ if (outform == NULL) { ++ outform = guess_type_by_name(outname, NULL); ++ if (outform == NULL) { ++ if (streq(inform, "dts")) ++ outform = "dtb"; ++ else ++ outform = "dts"; ++ } ++ } + if (streq(inform, "dts")) + bi = dt_from_source(arg); + else if (streq(inform, "fs")) +@@ -236,6 +305,12 @@ int main(int argc, char *argv[]) + if (sort) + sort_tree(bi); + ++ if (symbol_fixup_support || auto_label_aliases) ++ generate_label_node(bi->dt, bi->dt); ++ ++ if (symbol_fixup_support) ++ generate_fixups_node(bi->dt, bi->dt); ++ + if (streq(outname, "-")) { + outf = stdout; + } else { +diff --git a/dtc.h b/dtc.h +index 56212c8..d025111 100644 +--- a/dtc.h ++++ b/dtc.h +@@ -20,7 +20,7 @@ + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ +- ++#define _GNU_SOURCE + #include + #include + #include +@@ -54,6 +54,14 @@ extern int reservenum; /* Number of memory reservation slots */ + extern int minsize; /* Minimum blob size */ + extern int padsize; /* Additional padding to blob */ + extern int phandle_format; /* Use linux,phandle or phandle properties */ ++extern int symbol_fixup_support;/* enable symbols & fixup support */ ++extern int auto_label_aliases; /* auto generate labels -> aliases */ ++ ++/* ++ * Tree source globals ++ */ ++extern bool source_is_plugin; ++extern bool deprecated_plugin_syntax_warning; + + #define PHANDLE_LEGACY 0x1 + #define PHANDLE_EPAPR 0x2 +@@ -194,6 +202,7 @@ struct node *build_node_delete(void); + 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_orphan_node(struct node *old_node, struct node *new_node, char *ref); + + void add_property(struct node *node, struct property *prop); + void delete_property_by_name(struct node *node, char *name); +@@ -244,6 +253,8 @@ struct boot_info { + struct boot_info *build_boot_info(struct reserve_info *reservelist, + struct node *tree, uint32_t boot_cpuid_phys); + void sort_tree(struct boot_info *bi); ++void generate_label_node(struct node *node, struct node *dt); ++void generate_fixups_node(struct node *node, struct node *dt); + + /* Checks */ + +diff --git a/livetree.c b/livetree.c +index e229b84..1ef9fc4 100644 +--- a/livetree.c ++++ b/livetree.c +@@ -216,6 +216,34 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) + return old_node; + } + ++void add_orphan_node(struct node *dt, struct node *new_node, char *ref) ++{ ++ static unsigned int next_orphan_fragment = 0; ++ struct node *ovl = xmalloc(sizeof(*ovl)); ++ struct property *p; ++ struct data d = empty_data; ++ char *name; ++ int ret; ++ ++ memset(ovl, 0, sizeof(*ovl)); ++ ++ d = data_add_marker(d, REF_PHANDLE, ref); ++ d = data_append_integer(d, 0xffffffff, 32); ++ ++ p = build_property("target", d); ++ add_property(ovl, p); ++ ++ ret = asprintf(&name, "fragment@%u", ++ next_orphan_fragment++); ++ if (ret == -1) ++ die("asprintf() failed\n"); ++ name_node(ovl, name); ++ name_node(new_node, "__overlay__"); ++ ++ add_child(dt, ovl); ++ add_child(ovl, new_node); ++} ++ + struct node *chain_node(struct node *first, struct node *list) + { + assert(first->next_sibling == NULL); +@@ -709,3 +737,177 @@ void sort_tree(struct boot_info *bi) + sort_reserve_entries(bi); + sort_node(bi->dt); + } ++ ++void generate_label_node(struct node *node, struct node *dt) ++{ ++ struct node *c, *an; ++ struct property *p; ++ struct label *l; ++ int has_label; ++ char *gen_node_name; ++ ++ if (auto_label_aliases) ++ gen_node_name = "aliases"; ++ else ++ gen_node_name = "__symbols__"; ++ ++ /* Make sure the label isn't already there */ ++ has_label = 0; ++ for_each_label(node->labels, l) { ++ has_label = 1; ++ break; ++ } ++ ++ if (has_label) { ++ ++ /* an is the aliases/__symbols__ node */ ++ an = get_subnode(dt, gen_node_name); ++ /* if no node exists, create it */ ++ if (!an) { ++ an = build_node(NULL, NULL); ++ name_node(an, gen_node_name); ++ add_child(dt, an); ++ } ++ ++ /* now add the label in the node */ ++ for_each_label(node->labels, l) { ++ /* check whether the label already exists */ ++ p = get_property(an, l->label); ++ if (p) { ++ fprintf(stderr, "WARNING: label %s already" ++ " exists in /%s", l->label, ++ gen_node_name); ++ continue; ++ } ++ ++ /* insert it */ ++ p = build_property(l->label, ++ data_copy_escape_string(node->fullpath, ++ strlen(node->fullpath))); ++ add_property(an, p); ++ } ++ ++ /* force allocation of a phandle for this node */ ++ if (symbol_fixup_support) ++ (void)get_node_phandle(dt, node); ++ } ++ ++ for_each_child(node, c) ++ generate_label_node(c, dt); ++} ++ ++static void add_fixup_entry(struct node *dt, struct node *node, ++ struct property *prop, struct marker *m) ++{ ++ struct node *fn; /* local fixup node */ ++ struct property *p; ++ char *fixups_name = "__fixups__"; ++ struct data d; ++ char *entry; ++ int ret; ++ ++ /* fn is the node we're putting entries in */ ++ fn = get_subnode(dt, fixups_name); ++ /* if no node exists, create it */ ++ if (!fn) { ++ fn = build_node(NULL, NULL); ++ name_node(fn, fixups_name); ++ add_child(dt, fn); ++ } ++ ++ ret = asprintf(&entry, "%s:%s:%u", ++ node->fullpath, prop->name, m->offset); ++ if (ret == -1) ++ die("asprintf() failed\n"); ++ ++ p = get_property(fn, m->ref); ++ d = data_append_data(p ? p->val : empty_data, entry, strlen(entry) + 1); ++ if (!p) ++ add_property(fn, build_property(m->ref, d)); ++ else ++ p->val = d; ++} ++ ++static void add_local_fixup_entry(struct node *dt, struct node *node, ++ struct property *prop, struct marker *m, ++ struct node *refnode) ++{ ++ struct node *lfn, *wn, *nwn; /* local fixup node, walk node, new */ ++ struct property *p; ++ struct data d; ++ char *local_fixups_name = "__local_fixups__"; ++ char *s, *e, *comp; ++ int len; ++ ++ /* fn is the node we're putting entries in */ ++ lfn = get_subnode(dt, local_fixups_name); ++ /* if no node exists, create it */ ++ if (!lfn) { ++ lfn = build_node(NULL, NULL); ++ name_node(lfn, local_fixups_name); ++ add_child(dt, lfn); ++ } ++ ++ /* walk the path components creating nodes if they don't exist */ ++ comp = NULL; ++ /* start skipping the first / */ ++ s = node->fullpath + 1; ++ wn = lfn; ++ while (*s) { ++ /* retrieve path component */ ++ e = strchr(s, '/'); ++ if (e == NULL) ++ e = s + strlen(s); ++ len = e - s; ++ comp = xrealloc(comp, len + 1); ++ memcpy(comp, s, len); ++ comp[len] = '\0'; ++ ++ /* if no node exists, create it */ ++ nwn = get_subnode(wn, comp); ++ if (!nwn) { ++ nwn = build_node(NULL, NULL); ++ name_node(nwn, strdup(comp)); ++ add_child(wn, nwn); ++ } ++ wn = nwn; ++ ++ /* last path component */ ++ if (!*e) ++ break; ++ ++ /* next path component */ ++ s = e + 1; ++ } ++ free(comp); ++ ++ p = get_property(wn, prop->name); ++ d = data_append_cell(p ? p->val : empty_data, (cell_t)m->offset); ++ if (!p) ++ add_property(wn, build_property(prop->name, d)); ++ else ++ p->val = d; ++} ++ ++void generate_fixups_node(struct node *node, struct node *dt) ++{ ++ struct node *c; ++ struct property *prop; ++ struct marker *m; ++ struct node *refnode; ++ ++ for_each_property(node, prop) { ++ m = prop->val.markers; ++ for_each_marker_of_type(m, REF_PHANDLE) { ++ refnode = get_node_by_ref(dt, m->ref); ++ if (!refnode) ++ add_fixup_entry(dt, node, prop, m); ++ else ++ add_local_fixup_entry(dt, node, prop, m, ++ refnode); ++ } ++ } ++ ++ for_each_child(node, c) ++ generate_fixups_node(c, dt); ++} +diff --git a/treesource.c b/treesource.c +index a55d1d1..e1d6657 100644 +--- a/treesource.c ++++ b/treesource.c +@@ -28,6 +28,9 @@ extern YYLTYPE yylloc; + struct boot_info *the_boot_info; + bool treesource_error; + ++bool source_is_plugin; ++bool deprecated_plugin_syntax_warning; ++ + struct boot_info *dt_from_source(const char *fname) + { + the_boot_info = NULL; +diff --git a/util.c b/util.c +index 9d65226..cbb945b 100644 +--- a/util.c ++++ b/util.c +@@ -349,7 +349,6 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size) + void utilfdt_print_data(const char *data, int len) + { + int i; +- const char *p = data; + const char *s; + + /* no data, don't print */ +@@ -376,6 +375,7 @@ void utilfdt_print_data(const char *data, int len) + i < (len - 1) ? " " : ""); + printf(">"); + } else { ++ const unsigned char *p = (const unsigned char *)data; + printf(" = ["); + for (i = 0; i < len; i++) + printf("%02x%s", *p++, i < len - 1 ? " " : ""); +-- +2.7.0 +