1168793Sthompsa/* 2168793Sthompsa * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. 3168793Sthompsa * 4168793Sthompsa * 5174721Sthompsa * This program is free software; you can redistribute it and/or 6294615Saraujo * modify it under the terms of the GNU General Public License as 7168793Sthompsa * published by the Free Software Foundation; either version 2 of the 8168793Sthompsa * License, or (at your option) any later version. 9168793Sthompsa * 10168793Sthompsa * This program is distributed in the hope that it will be useful, 11168793Sthompsa * but WITHOUT ANY WARRANTY; without even the implied warranty of 12168793Sthompsa * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13168793Sthompsa * General Public License for more details. 14168793Sthompsa * 15168793Sthompsa * You should have received a copy of the GNU General Public License 16168793Sthompsa * along with this program; if not, write to the Free Software 17168793Sthompsa * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 18168793Sthompsa * USA 19168793Sthompsa */ 20168793Sthompsa 21168793Sthompsa#include "dtc.h" 22168793Sthompsa 23168793Sthompsa/* 24168793Sthompsa * Tree building functions 25168793Sthompsa */ 26168793Sthompsa 27168793Sthompsavoid add_label(struct label **labels, char *label) 28168793Sthompsa{ 29168793Sthompsa struct label *new; 30168793Sthompsa 31168793Sthompsa /* Make sure the label isn't already there */ 32168793Sthompsa for_each_label_withdel(*labels, new) 33168793Sthompsa if (streq(new->label, label)) { 34168793Sthompsa new->deleted = 0; 35168793Sthompsa return; 36168793Sthompsa } 37168793Sthompsa 38168793Sthompsa new = xmalloc(sizeof(*new)); 39169569Sthompsa memset(new, 0, sizeof(*new)); 40255038Sadrian new->label = label; 41318329Smav new->next = *labels; 42169329Sthompsa *labels = new; 43203548Seri} 44168793Sthompsa 45168793Sthompsavoid delete_labels(struct label **labels) 46168793Sthompsa{ 47168793Sthompsa struct label *label; 48168793Sthompsa 49168793Sthompsa for_each_label(*labels, label) 50168793Sthompsa label->deleted = 1; 51168793Sthompsa} 52168793Sthompsa 53168793Sthompsastruct property *build_property(char *name, struct data val) 54272386Shrs{ 55168793Sthompsa struct property *new = xmalloc(sizeof(*new)); 56221130Sbz 57221130Sbz memset(new, 0, sizeof(*new)); 58264498Srmacklem 59221130Sbz new->name = name; 60168793Sthompsa new->val = val; 61168793Sthompsa 62168793Sthompsa return new; 63168793Sthompsa} 64168793Sthompsa 65168793Sthompsastruct property *build_property_delete(char *name) 66168793Sthompsa{ 67252511Shrs struct property *new = xmalloc(sizeof(*new)); 68252511Shrs 69168793Sthompsa memset(new, 0, sizeof(*new)); 70168793Sthompsa 71168793Sthompsa new->name = name; 72168793Sthompsa new->deleted = 1; 73168793Sthompsa 74168793Sthompsa return new; 75168793Sthompsa} 76168793Sthompsa 77168793Sthompsastruct property *chain_property(struct property *first, struct property *list) 78168793Sthompsa{ 79168793Sthompsa assert(first->next == NULL); 80168793Sthompsa 81168793Sthompsa first->next = list; 82168793Sthompsa return first; 83168793Sthompsa} 84168793Sthompsa 85272386Shrsstruct property *reverse_properties(struct property *first) 86272386Shrs{ 87272386Shrs struct property *p = first; 88272386Shrs struct property *head = NULL; 89272386Shrs struct property *next; 90272386Shrs 91272386Shrs while (p) { 92272386Shrs next = p->next; 93272386Shrs p->next = head; 94168793Sthompsa head = p; 95168793Sthompsa p = next; 96168793Sthompsa } 97168793Sthompsa return head; 98272386Shrs} 99272386Shrs 100241610Sglebiusstruct node *build_node(struct property *proplist, struct node *children) 101241610Sglebius{ 102171661Sthompsa struct node *new = xmalloc(sizeof(*new)); 103168793Sthompsa struct node *child; 104168793Sthompsa 105168793Sthompsa memset(new, 0, sizeof(*new)); 106173895Sthompsa 107292402Ssmh new->proplist = reverse_properties(proplist); 108168793Sthompsa new->children = children; 109168793Sthompsa 110249925Sglebius for_each_child(new, child) { 111168793Sthompsa child->parent = new; 112201803Strasz } 113168793Sthompsa 114201803Strasz return new; 115168793Sthompsa} 116168793Sthompsa 117168793Sthompsastruct node *build_node_delete(void) 118168793Sthompsa{ 119318329Smav struct node *new = xmalloc(sizeof(*new)); 120318329Smav 121318329Smav memset(new, 0, sizeof(*new)); 122168793Sthompsa 123168793Sthompsa new->deleted = 1; 124168793Sthompsa 125272211Smelifaro return new; 126240742Sglebius} 127240742Sglebius 128168793Sthompsastruct node *name_node(struct node *node, char *name) 129168793Sthompsa{ 130168793Sthompsa assert(node->name == NULL); 131168793Sthompsa 132168793Sthompsa node->name = name; 133168793Sthompsa 134272161Sglebius return node; 135168793Sthompsa} 136168793Sthompsa 137168793Sthompsastruct node *omit_node_if_unused(struct node *node) 138168793Sthompsa{ 139168793Sthompsa node->omit_if_unused = 1; 140168793Sthompsa 141168793Sthompsa return node; 142168793Sthompsa} 143168793Sthompsa 144168793Sthompsastruct node *reference_node(struct node *node) 145272161Sglebius{ 146272158Sglebius node->is_referenced = 1; 147168793Sthompsa 148168793Sthompsa return node; 149168793Sthompsa} 150168793Sthompsa 151168793Sthompsastruct node *merge_nodes(struct node *old_node, struct node *new_node) 152168793Sthompsa{ 153168793Sthompsa struct property *new_prop, *old_prop; 154271732Saraujo struct node *new_child, *old_child; 155271732Saraujo struct label *l; 156271732Saraujo 157272175Sglebius old_node->deleted = 0; 158271732Saraujo 159168793Sthompsa /* Add new node labels to old node */ 160272161Sglebius for_each_label_withdel(new_node->labels, l) 161272158Sglebius add_label(&old_node->labels, l->label); 162168793Sthompsa 163168793Sthompsa /* Move properties from the new node to the old node. If there 164168793Sthompsa * is a collision, replace the old value with the new */ 165168793Sthompsa while (new_node->proplist) { 166168793Sthompsa /* Pop the property off the list */ 167168793Sthompsa new_prop = new_node->proplist; 168272161Sglebius new_node->proplist = new_prop->next; 169272170Sglebius new_prop->next = NULL; 170272170Sglebius 171272170Sglebius if (new_prop->deleted) { 172272178Sglebius delete_property_by_name(old_node, new_prop->name); 173272178Sglebius free(new_prop); 174272178Sglebius continue; 175272178Sglebius } 176272178Sglebius 177272178Sglebius /* Look for a collision, set new value if there is */ 178272178Sglebius for_each_property_withdel(old_node, old_prop) { 179272178Sglebius if (streq(old_prop->name, new_prop->name)) { 180272178Sglebius /* Add new labels to old property */ 181272178Sglebius for_each_label_withdel(new_prop->labels, l) 182272178Sglebius add_label(&old_prop->labels, l->label); 183168793Sthompsa 184272170Sglebius old_prop->val = new_prop->val; 185272170Sglebius old_prop->deleted = 0; 186272170Sglebius free(new_prop); 187272170Sglebius new_prop = NULL; 188272170Sglebius break; 189272170Sglebius } 190272178Sglebius } 191272178Sglebius 192272170Sglebius /* if no collision occurred, add property to the old node. */ 193272170Sglebius if (new_prop) 194272170Sglebius add_property(old_node, new_prop); 195272178Sglebius } 196272178Sglebius 197272170Sglebius /* Move the override child nodes into the primary node. If 198272170Sglebius * there is a collision, then merge the nodes. */ 199272170Sglebius while (new_node->children) { 200272170Sglebius /* Pop the child node off the list */ 201272170Sglebius new_child = new_node->children; 202272178Sglebius new_node->children = new_child->next_sibling; 203272178Sglebius new_child->parent = NULL; 204272178Sglebius new_child->next_sibling = NULL; 205272178Sglebius 206272170Sglebius if (new_child->deleted) { 207272170Sglebius delete_node_by_name(old_node, new_child->name); 208272170Sglebius free(new_child); 209272170Sglebius continue; 210272170Sglebius } 211272178Sglebius 212272178Sglebius /* Search for a collision. Merge if there is */ 213272178Sglebius for_each_child_withdel(old_node, old_child) { 214272178Sglebius if (streq(old_child->name, new_child->name)) { 215272178Sglebius merge_nodes(old_child, new_child); 216272178Sglebius new_child = NULL; 217272178Sglebius break; 218272178Sglebius } 219272178Sglebius } 220272178Sglebius 221272170Sglebius /* if no collision occurred, add child to the old node. */ 222272170Sglebius if (new_child) 223272170Sglebius add_child(old_node, new_child); 224272178Sglebius } 225272178Sglebius 226272170Sglebius /* The new node contents are now merged into the old node. Free 227168793Sthompsa * the new node. */ 228168793Sthompsa free(new_node); 229212100Semaste 230253314Sadrian return old_node; 231227309Sed} 232212100Semaste 233272386Shrsstruct node * add_orphan_node(struct node *dt, struct node *new_node, char *ref) 234272386Shrs{ 235272386Shrs static unsigned int next_orphan_fragment = 0; 236272386Shrs struct node *node; 237272386Shrs struct property *p; 238212100Semaste struct data d = empty_data; 239272386Shrs char *name; 240275358Shselasky 241332318Ssmh if (ref[0] == '/') { 242272386Shrs d = data_append_data(d, ref, strlen(ref) + 1); 243267992Shselasky 244272386Shrs p = build_property("target-path", d); 245232080Sthompsa } else { 246272386Shrs d = data_add_marker(d, REF_PHANDLE, ref); 247275358Shselasky d = data_append_integer(d, 0xffffffff, 32); 248272386Shrs 249272386Shrs p = build_property("target", d); 250267992Shselasky } 251272386Shrs 252260070Sscottl xasprintf(&name, "fragment@%u", 253212100Semaste next_orphan_fragment++); 254272386Shrs name_node(new_node, "__overlay__"); 255272386Shrs node = build_node(p, new_node); 256272386Shrs name_node(node, name); 257272386Shrs 258272386Shrs add_child(dt, node); 259272386Shrs return dt; 260272386Shrs} 261272386Shrs 262272386Shrsstruct node *chain_node(struct node *first, struct node *list) 263272386Shrs{ 264272386Shrs assert(first->next_sibling == NULL); 265272386Shrs 266272386Shrs first->next_sibling = list; 267272386Shrs return first; 268272386Shrs} 269272386Shrs 270272386Shrsvoid add_property(struct node *node, struct property *prop) 271272386Shrs{ 272272386Shrs struct property **p; 273302054Sbz 274272386Shrs prop->next = NULL; 275272386Shrs 276168793Sthompsa p = &node->proplist; 277168793Sthompsa while (*p) 278168793Sthompsa p = &((*p)->next); 279168793Sthompsa 280168793Sthompsa *p = prop; 281168793Sthompsa} 282168793Sthompsa 283168793Sthompsavoid delete_property_by_name(struct node *node, char *name) 284168793Sthompsa{ 285168793Sthompsa struct property *prop = node->proplist; 286168793Sthompsa 287168793Sthompsa while (prop) { 288168793Sthompsa if (streq(prop->name, name)) { 289168793Sthompsa delete_property(prop); 290168793Sthompsa return; 291168793Sthompsa } 292168793Sthompsa prop = prop->next; 293168793Sthompsa } 294168793Sthompsa} 295168793Sthompsa 296168793Sthompsavoid delete_property(struct property *prop) 297168793Sthompsa{ 298168793Sthompsa prop->deleted = 1; 299168793Sthompsa delete_labels(&prop->labels); 300168793Sthompsa} 301168793Sthompsa 302168793Sthompsavoid add_child(struct node *parent, struct node *child) 303241394Skevlo{ 304168793Sthompsa struct node **p; 305168793Sthompsa 306168793Sthompsa child->next_sibling = NULL; 307224571Spluknet child->parent = parent; 308168793Sthompsa 309272170Sglebius p = &parent->children; 310272170Sglebius while (*p) 311272170Sglebius p = &((*p)->next_sibling); 312272170Sglebius 313318329Smav *p = child; 314272170Sglebius} 315272170Sglebius 316272170Sglebiusvoid delete_node_by_name(struct node *parent, char *name) 317272170Sglebius{ 318272170Sglebius struct node *node = parent->children; 319272170Sglebius 320272178Sglebius while (node) { 321272178Sglebius if (streq(node->name, name)) { 322272170Sglebius delete_node(node); 323272170Sglebius return; 324272170Sglebius } 325272170Sglebius node = node->next_sibling; 326272170Sglebius } 327272170Sglebius} 328272170Sglebius 329272170Sglebiusvoid delete_node(struct node *node) 330318329Smav{ 331272170Sglebius struct property *prop; 332272170Sglebius struct node *child; 333272175Sglebius 334272170Sglebius node->deleted = 1; 335272170Sglebius for_each_child(node, child) 336272170Sglebius delete_node(child); 337272170Sglebius for_each_property(node, prop) 338272170Sglebius delete_property(prop); 339272170Sglebius delete_labels(&node->labels); 340272170Sglebius} 341272178Sglebius 342272178Sglebiusvoid append_to_property(struct node *node, 343272178Sglebius char *name, const void *data, int len) 344272178Sglebius{ 345272178Sglebius struct data d; 346272178Sglebius struct property *p; 347272178Sglebius 348272178Sglebius p = get_property(node, name); 349272178Sglebius if (p) { 350272178Sglebius d = data_append_data(p->val, data, len); 351272178Sglebius p->val = d; 352272178Sglebius } else { 353272178Sglebius d = data_append_data(empty_data, data, len); 354272178Sglebius p = build_property(name, d); 355272178Sglebius add_property(node, p); 356272178Sglebius } 357272178Sglebius} 358272178Sglebius 359272178Sglebiusstruct reserve_info *build_reserve_entry(uint64_t address, uint64_t size) 360272178Sglebius{ 361272178Sglebius struct reserve_info *new = xmalloc(sizeof(*new)); 362272178Sglebius 363272178Sglebius memset(new, 0, sizeof(*new)); 364272178Sglebius 365272178Sglebius new->address = address; 366272178Sglebius new->size = size; 367272178Sglebius 368272178Sglebius return new; 369272178Sglebius} 370272178Sglebius 371272178Sglebiusstruct reserve_info *chain_reserve_entry(struct reserve_info *first, 372272178Sglebius struct reserve_info *list) 373272178Sglebius{ 374272178Sglebius assert(first->next == NULL); 375272178Sglebius 376272178Sglebius first->next = list; 377272178Sglebius return first; 378272178Sglebius} 379272178Sglebius 380272178Sglebiusstruct reserve_info *add_reserve_entry(struct reserve_info *list, 381272178Sglebius struct reserve_info *new) 382272178Sglebius{ 383272178Sglebius struct reserve_info *last; 384272178Sglebius 385272178Sglebius new->next = NULL; 386272178Sglebius 387272178Sglebius if (! list) 388272178Sglebius return new; 389272178Sglebius 390272178Sglebius for (last = list; last->next; last = last->next) 391272178Sglebius ; 392272178Sglebius 393272178Sglebius last->next = new; 394272178Sglebius 395272178Sglebius return list; 396272178Sglebius} 397272178Sglebius 398272178Sglebiusstruct dt_info *build_dt_info(unsigned int dtsflags, 399272178Sglebius struct reserve_info *reservelist, 400272178Sglebius struct node *tree, uint32_t boot_cpuid_phys) 401272178Sglebius{ 402272178Sglebius struct dt_info *dti; 403272178Sglebius 404272178Sglebius dti = xmalloc(sizeof(*dti)); 405272178Sglebius dti->dtsflags = dtsflags; 406272178Sglebius dti->reservelist = reservelist; 407272178Sglebius dti->dt = tree; 408272178Sglebius dti->boot_cpuid_phys = boot_cpuid_phys; 409272178Sglebius 410272178Sglebius return dti; 411272178Sglebius} 412272178Sglebius 413272178Sglebius/* 414272178Sglebius * Tree accessor functions 415272178Sglebius */ 416272178Sglebius 417272178Sglebiusconst char *get_unitname(struct node *node) 418272178Sglebius{ 419272178Sglebius if (node->name[node->basenamelen] == '\0') 420272178Sglebius return ""; 421203548Seri else 422203548Seri return node->name + node->basenamelen + 1; 423203548Seri} 424203548Seri 425203548Seristruct property *get_property(struct node *node, const char *propname) 426203548Seri{ 427203548Seri struct property *prop; 428272175Sglebius 429272175Sglebius for_each_property(node, prop) 430203548Seri if (streq(prop->name, propname)) 431272175Sglebius return prop; 432272175Sglebius 433203548Seri return NULL; 434318329Smav} 435317699Smav 436317699Smavcell_t propval_cell(struct property *prop) 437318329Smav{ 438203548Seri assert(prop->val.len == sizeof(cell_t)); 439203548Seri return fdt32_to_cpu(*((fdt32_t *)prop->val.val)); 440203548Seri} 441203548Seri 442203548Sericell_t propval_cell_n(struct property *prop, int n) 443203548Seri{ 444203548Seri assert(prop->val.len / sizeof(cell_t) >= n); 445203548Seri return fdt32_to_cpu(*((fdt32_t *)prop->val.val + n)); 446203548Seri} 447272175Sglebius 448272175Sglebiusstruct property *get_property_by_label(struct node *tree, const char *label, 449203548Seri struct node **node) 450272175Sglebius{ 451272175Sglebius struct property *prop; 452203548Seri struct node *c; 453318329Smav 454317699Smav *node = tree; 455317699Smav 456318329Smav for_each_property(tree, prop) { 457203548Seri struct label *l; 458203548Seri 459168793Sthompsa for_each_label(prop->labels, l) 460168793Sthompsa if (streq(l->label, label)) 461168793Sthompsa return prop; 462168793Sthompsa } 463168793Sthompsa 464168793Sthompsa for_each_child(tree, c) { 465168793Sthompsa prop = get_property_by_label(c, label, node); 466168793Sthompsa if (prop) 467168793Sthompsa return prop; 468168793Sthompsa } 469168793Sthompsa 470168793Sthompsa *node = NULL; 471168793Sthompsa return NULL; 472318329Smav} 473318329Smav 474168793Sthompsastruct marker *get_marker_label(struct node *tree, const char *label, 475318329Smav struct node **node, struct property **prop) 476272386Shrs{ 477272386Shrs struct marker *m; 478272386Shrs struct property *p; 479272386Shrs struct node *c; 480232629Sthompsa 481279891Shselasky *node = tree; 482232008Sthompsa 483272170Sglebius for_each_property(tree, p) { 484272170Sglebius *prop = p; 485168793Sthompsa m = p->val.markers; 486168793Sthompsa for_each_marker_of_type(m, LABEL) 487168793Sthompsa if (streq(m->ref, label)) 488168793Sthompsa return m; 489168793Sthompsa } 490168793Sthompsa 491168793Sthompsa for_each_child(tree, c) { 492168793Sthompsa m = get_marker_label(c, label, node, prop); 493241610Sglebius if (m) 494168793Sthompsa return m; 495240742Sglebius } 496240742Sglebius 497168793Sthompsa *prop = NULL; 498168793Sthompsa *node = NULL; 499272211Smelifaro return NULL; 500168793Sthompsa} 501256218Sglebius 502168793Sthompsastruct node *get_subnode(struct node *node, const char *nodename) 503168793Sthompsa{ 504227459Sbrooks struct node *child; 505168793Sthompsa 506168793Sthompsa for_each_child(node, child) 507168793Sthompsa if (streq(child->name, nodename)) 508168793Sthompsa return child; 509203548Seri 510203548Seri return NULL; 511203548Seri} 512203548Seri 513203548Seristruct node *get_node_by_path(struct node *tree, const char *path) 514168793Sthompsa{ 515272386Shrs const char *p; 516272386Shrs struct node *child; 517272386Shrs 518318329Smav if (!path || ! (*path)) { 519168793Sthompsa if (tree->deleted) 520168793Sthompsa return NULL; 521168793Sthompsa return tree; 522168793Sthompsa } 523168793Sthompsa 524168793Sthompsa while (path[0] == '/') 525168793Sthompsa path++; 526168793Sthompsa 527168793Sthompsa p = strchr(path, '/'); 528168793Sthompsa 529318329Smav for_each_child(tree, child) { 530318329Smav if (p && (strlen(child->name) == p-path) && 531168793Sthompsa strprefixeq(path, p - path, child->name)) 532168793Sthompsa return get_node_by_path(child, p+1); 533168793Sthompsa else if (!p && streq(path, child->name)) 534203548Seri return child; 535203548Seri } 536203548Seri 537168793Sthompsa return NULL; 538318329Smav} 539168793Sthompsa 540318329Smavstruct node *get_node_by_label(struct node *tree, const char *label) 541168793Sthompsa{ 542318329Smav struct node *child, *node; 543272170Sglebius struct label *l; 544290239Smelifaro 545318329Smav assert(label && (strlen(label) > 0)); 546168793Sthompsa 547168793Sthompsa for_each_label(tree->labels, l) 548168793Sthompsa if (streq(l->label, label)) 549227459Sbrooks return tree; 550168793Sthompsa 551272386Shrs for_each_child(tree, child) { 552272386Shrs node = get_node_by_label(child, label); 553272386Shrs if (node) 554168793Sthompsa return node; 555318329Smav } 556168793Sthompsa 557168793Sthompsa return NULL; 558168793Sthompsa} 559168793Sthompsa 560171661Sthompsastruct node *get_node_by_phandle(struct node *tree, cell_t phandle) 561168793Sthompsa{ 562168793Sthompsa struct node *child, *node; 563168793Sthompsa 564319696Smav if ((phandle == 0) || (phandle == -1)) { 565319696Smav assert(generate_fixups); 566271946Shselasky return NULL; 567168793Sthompsa } 568318329Smav 569168793Sthompsa if (tree->phandle == phandle) { 570319696Smav if (tree->deleted) 571319696Smav return NULL; 572319696Smav return tree; 573319696Smav } 574319696Smav 575319696Smav for_each_child(tree, child) { 576319696Smav node = get_node_by_phandle(child, phandle); 577319696Smav if (node) 578319696Smav return node; 579319696Smav } 580319696Smav 581319696Smav return NULL; 582319696Smav} 583319696Smav 584319696Smavstruct node *get_node_by_ref(struct node *tree, const char *ref) 585319696Smav{ 586319696Smav if (streq(ref, "/")) 587319696Smav return tree; 588319696Smav else if (ref[0] == '/') 589319696Smav return get_node_by_path(tree, ref); 590319696Smav else 591271946Shselasky return get_node_by_label(tree, ref); 592171661Sthompsa} 593171661Sthompsa 594186195Sthompsacell_t get_node_phandle(struct node *root, struct node *node) 595271946Shselasky{ 596171661Sthompsa static cell_t phandle = 1; /* FIXME: ick, static local */ 597171661Sthompsa 598319696Smav if ((node->phandle != 0) && (node->phandle != -1)) 599168793Sthompsa return node->phandle; 600171661Sthompsa 601186195Sthompsa while (get_node_by_phandle(root, phandle)) 602264469Srmacklem phandle++; 603271946Shselasky 604171661Sthompsa node->phandle = phandle; 605171661Sthompsa 606186195Sthompsa if (!get_property(node, "linux,phandle") 607171661Sthompsa && (phandle_format & PHANDLE_LEGACY)) 608171661Sthompsa add_property(node, 609171661Sthompsa build_property("linux,phandle", 610171661Sthompsa data_append_cell(empty_data, phandle))); 611171661Sthompsa 612168793Sthompsa if (!get_property(node, "phandle") 613168793Sthompsa && (phandle_format & PHANDLE_EPAPR)) 614168793Sthompsa add_property(node, 615168793Sthompsa build_property("phandle", 616168793Sthompsa data_append_cell(empty_data, phandle))); 617168793Sthompsa 618168793Sthompsa /* If the node *does* have a phandle property, we must 619272176Sae * be dealing with a self-referencing phandle, which will be 620342206Smav * fixed up momentarily in the caller */ 621342206Smav 622272211Smelifaro return node->phandle; 623168793Sthompsa} 624318329Smav 625168793Sthompsauint32_t guess_boot_cpuid(struct node *tree) 626342206Smav{ 627342206Smav struct node *cpus, *bootcpu; 628342206Smav struct property *reg; 629342206Smav 630342206Smav cpus = get_node_by_path(tree, "/cpus"); 631342206Smav if (!cpus) 632168793Sthompsa return 0; 633168793Sthompsa 634168793Sthompsa 635168793Sthompsa bootcpu = cpus->children; 636168793Sthompsa if (!bootcpu) 637236178Srea return 0; 638236178Srea 639236178Srea reg = get_property(bootcpu, "reg"); 640236178Srea if (!reg || (reg->val.len != sizeof(uint32_t))) 641236178Srea return 0; 642168793Sthompsa 643236178Srea /* FIXME: Sanity check node? */ 644168793Sthompsa 645168793Sthompsa return propval_cell(reg); 646290239Smelifaro} 647168793Sthompsa 648168793Sthompsastatic int cmp_reserve_info(const void *ax, const void *bx) 649171661Sthompsa{ 650342206Smav const struct reserve_info *a, *b; 651342206Smav 652171661Sthompsa a = *((const struct reserve_info * const *)ax); 653342206Smav b = *((const struct reserve_info * const *)bx); 654342206Smav 655342206Smav if (a->address < b->address) 656342206Smav return -1; 657342206Smav else if (a->address > b->address) 658342206Smav return 1; 659342206Smav else if (a->size < b->size) 660342206Smav return -1; 661342206Smav else if (a->size > b->size) 662342206Smav return 1; 663342206Smav else 664342206Smav return 0; 665342206Smav} 666342206Smav 667342206Smavstatic void sort_reserve_entries(struct dt_info *dti) 668342206Smav{ 669171661Sthompsa struct reserve_info *ri, **tbl; 670171661Sthompsa int n = 0, i = 0; 671318329Smav 672318329Smav for (ri = dti->reservelist; 673168793Sthompsa ri; 674168793Sthompsa ri = ri->next) 675272386Shrs n++; 676272386Shrs 677168793Sthompsa if (n == 0) 678272386Shrs return; 679168793Sthompsa 680342206Smav tbl = xmalloc(n * sizeof(*tbl)); 681342206Smav 682342206Smav for (ri = dti->reservelist; 683168793Sthompsa ri; 684201803Strasz ri = ri->next) 685201803Strasz tbl[i++] = ri; 686168793Sthompsa 687168793Sthompsa qsort(tbl, n, sizeof(*tbl), cmp_reserve_info); 688168793Sthompsa 689272386Shrs dti->reservelist = tbl[0]; 690168793Sthompsa for (i = 0; i < (n-1); i++) 691342206Smav tbl[i]->next = tbl[i+1]; 692342206Smav tbl[n-1]->next = NULL; 693342206Smav 694168793Sthompsa free(tbl); 695168793Sthompsa} 696201803Strasz 697168793Sthompsastatic int cmp_prop(const void *ax, const void *bx) 698168793Sthompsa{ 699272386Shrs const struct property *a, *b; 700168793Sthompsa 701318329Smav a = *((const struct property * const *)ax); 702318329Smav b = *((const struct property * const *)bx); 703318329Smav 704318329Smav return strcmp(a->name, b->name); 705318329Smav} 706318329Smav 707318329Smavstatic void sort_properties(struct node *node) 708318329Smav{ 709318329Smav int n = 0, i = 0; 710318329Smav struct property *prop, **tbl; 711318329Smav 712318329Smav for_each_property_withdel(node, prop) 713318329Smav n++; 714318329Smav 715318329Smav if (n == 0) 716318329Smav return; 717318329Smav 718318329Smav tbl = xmalloc(n * sizeof(*tbl)); 719318329Smav 720318329Smav for_each_property_withdel(node, prop) 721168793Sthompsa tbl[i++] = prop; 722168793Sthompsa 723168793Sthompsa qsort(tbl, n, sizeof(*tbl), cmp_prop); 724168793Sthompsa 725168793Sthompsa node->proplist = tbl[0]; 726168793Sthompsa for (i = 0; i < (n-1); i++) 727168793Sthompsa tbl[i]->next = tbl[i+1]; 728168793Sthompsa tbl[n-1]->next = NULL; 729168793Sthompsa 730318329Smav free(tbl); 731318329Smav} 732318329Smav 733318329Smavstatic int cmp_subnode(const void *ax, const void *bx) 734168793Sthompsa{ 735277295Sae const struct node *a, *b; 736277295Sae 737277295Sae a = *((const struct node * const *)ax); 738277295Sae b = *((const struct node * const *)bx); 739277295Sae 740277295Sae return strcmp(a->name, b->name); 741272176Sae} 742272176Sae 743272176Saestatic void sort_subnodes(struct node *node) 744277295Sae{ 745272176Sae int n = 0, i = 0; 746272176Sae struct node *subnode, **tbl; 747272176Sae 748272176Sae for_each_child_withdel(node, subnode) 749272176Sae n++; 750272176Sae 751272176Sae if (n == 0) 752168793Sthompsa return; 753168793Sthompsa 754318329Smav tbl = xmalloc(n * sizeof(*tbl)); 755168793Sthompsa 756272178Sglebius for_each_child_withdel(node, subnode) 757272178Sglebius tbl[i++] = subnode; 758168793Sthompsa 759342206Smav qsort(tbl, n, sizeof(*tbl), cmp_subnode); 760342206Smav 761318329Smav node->children = tbl[0]; 762168793Sthompsa for (i = 0; i < (n-1); i++) 763168793Sthompsa tbl[i]->next_sibling = tbl[i+1]; 764168793Sthompsa tbl[n-1]->next_sibling = NULL; 765318329Smav 766318329Smav free(tbl); 767318329Smav} 768318329Smav 769318329Smavstatic void sort_node(struct node *node) 770318329Smav{ 771272178Sglebius struct node *c; 772168793Sthompsa 773168793Sthompsa sort_properties(node); 774201803Strasz sort_subnodes(node); 775168793Sthompsa for_each_child_withdel(node, c) 776168793Sthompsa sort_node(c); 777168793Sthompsa} 778168793Sthompsa 779168793Sthompsavoid sort_tree(struct dt_info *dti) 780168793Sthompsa{ 781168793Sthompsa sort_reserve_entries(dti); 782318329Smav sort_node(dti->dt); 783168793Sthompsa} 784168793Sthompsa 785168793Sthompsa/* utility helper to avoid code duplication */ 786168793Sthompsastatic struct node *build_and_name_child_node(struct node *parent, char *name) 787168793Sthompsa{ 788168793Sthompsa struct node *node; 789168793Sthompsa 790168793Sthompsa node = build_node(NULL, NULL); 791168793Sthompsa name_node(node, xstrdup(name)); 792201803Strasz add_child(parent, node); 793168793Sthompsa 794168793Sthompsa return node; 795272178Sglebius} 796168793Sthompsa 797170599Sthompsastatic struct node *build_root_node(struct node *dt, char *name) 798288980Shrs{ 799168793Sthompsa struct node *an; 800272211Smelifaro 801272211Smelifaro an = get_subnode(dt, name); 802168793Sthompsa if (!an) 803318329Smav an = build_and_name_child_node(dt, name); 804168793Sthompsa 805318329Smav if (!an) 806318329Smav die("Could not build root node /%s\n", name); 807272178Sglebius 808318329Smav return an; 809318329Smav} 810168793Sthompsa 811318329Smavstatic bool any_label_tree(struct dt_info *dti, struct node *node) 812318329Smav{ 813168793Sthompsa struct node *c; 814168793Sthompsa 815168793Sthompsa if (node->labels) 816168793Sthompsa return true; 817168793Sthompsa 818168793Sthompsa for_each_child(node, c) 819168793Sthompsa if (any_label_tree(dti, c)) 820272211Smelifaro return true; 821272211Smelifaro 822272354Sglebius return false; 823272211Smelifaro} 824272244Sglebius 825272211Smelifarostatic void generate_label_tree_internal(struct dt_info *dti, 826272211Smelifaro struct node *an, struct node *node, 827168793Sthompsa bool allocph) 828168793Sthompsa{ 829168793Sthompsa struct node *dt = dti->dt; 830168793Sthompsa struct node *c; 831168793Sthompsa struct property *p; 832168793Sthompsa struct label *l; 833168793Sthompsa 834168793Sthompsa /* if there are labels */ 835318329Smav if (node->labels) { 836168793Sthompsa 837318329Smav /* now add the label in the node */ 838318329Smav for_each_label(node->labels, l) { 839290239Smelifaro 840318329Smav /* check whether the label already exists */ 841318329Smav p = get_property(an, l->label); 842318329Smav if (p) { 843318329Smav fprintf(stderr, "WARNING: label %s already" 844318329Smav " exists in /%s", l->label, 845318329Smav an->name); 846318329Smav continue; 847290239Smelifaro } 848288980Shrs 849318329Smav /* insert it */ 850318329Smav p = build_property(l->label, 851288980Shrs data_copy_mem(node->fullpath, 852168793Sthompsa strlen(node->fullpath) + 1)); 853318329Smav add_property(an, p); 854318329Smav } 855318329Smav 856168793Sthompsa /* force allocation of a phandle for this node */ 857168793Sthompsa if (allocph) 858168793Sthompsa (void)get_node_phandle(dt, node); 859168793Sthompsa } 860318329Smav 861318329Smav for_each_child(node, c) 862318329Smav generate_label_tree_internal(dti, an, c, allocph); 863318329Smav} 864318329Smav 865318329Smavstatic bool any_fixup_tree(struct dt_info *dti, struct node *node) 866317698Smav{ 867168793Sthompsa struct node *c; 868168793Sthompsa struct property *prop; 869168793Sthompsa struct marker *m; 870171661Sthompsa 871173895Sthompsa for_each_property(node, prop) { 872168793Sthompsa m = prop->val.markers; 873168793Sthompsa for_each_marker_of_type(m, REF_PHANDLE) { 874168793Sthompsa if (!get_node_by_ref(dti->dt, m->ref)) 875168793Sthompsa return true; 876168793Sthompsa } 877168793Sthompsa } 878168793Sthompsa 879168793Sthompsa for_each_child(node, c) { 880168793Sthompsa if (any_fixup_tree(dti, c)) 881168793Sthompsa return true; 882168793Sthompsa } 883168793Sthompsa 884168793Sthompsa return false; 885168793Sthompsa} 886170599Sthompsa 887168793Sthompsastatic void add_fixup_entry(struct dt_info *dti, struct node *fn, 888168793Sthompsa struct node *node, struct property *prop, 889168793Sthompsa struct marker *m) 890168793Sthompsa{ 891168793Sthompsa char *entry; 892168793Sthompsa 893168793Sthompsa /* m->ref can only be a REF_PHANDLE, but check anyway */ 894168793Sthompsa assert(m->type == REF_PHANDLE); 895168793Sthompsa 896168793Sthompsa /* there shouldn't be any ':' in the arguments */ 897318329Smav if (strchr(node->fullpath, ':') || strchr(prop->name, ':')) 898171603Sthompsa die("arguments should not contain ':'\n"); 899168793Sthompsa 900318329Smav xasprintf(&entry, "%s:%s:%u", 901168793Sthompsa node->fullpath, prop->name, m->offset); 902168793Sthompsa append_to_property(fn, m->ref, entry, strlen(entry) + 1); 903168793Sthompsa 904168793Sthompsa free(entry); 905318329Smav} 906168793Sthompsa 907171661Sthompsastatic void generate_fixups_tree_internal(struct dt_info *dti, 908171661Sthompsa struct node *fn, 909171661Sthompsa struct node *node) 910171661Sthompsa{ 911171661Sthompsa struct node *dt = dti->dt; 912171661Sthompsa struct node *c; 913171661Sthompsa struct property *prop; 914171661Sthompsa struct marker *m; 915171661Sthompsa struct node *refnode; 916171661Sthompsa 917171661Sthompsa for_each_property(node, prop) { 918318329Smav m = prop->val.markers; 919171661Sthompsa for_each_marker_of_type(m, REF_PHANDLE) { 920318329Smav refnode = get_node_by_ref(dt, m->ref); 921319697Smav if (!refnode) 922171661Sthompsa add_fixup_entry(dti, fn, node, prop, m); 923171661Sthompsa } 924171661Sthompsa } 925171661Sthompsa 926171661Sthompsa for_each_child(node, c) 927171661Sthompsa generate_fixups_tree_internal(dti, fn, c); 928171661Sthompsa} 929168793Sthompsa 930168793Sthompsastatic bool any_local_fixup_tree(struct dt_info *dti, struct node *node) 931168793Sthompsa{ 932168793Sthompsa struct node *c; 933168793Sthompsa struct property *prop; 934168793Sthompsa struct marker *m; 935168793Sthompsa 936313108Sasomers for_each_property(node, prop) { 937168793Sthompsa m = prop->val.markers; 938168793Sthompsa for_each_marker_of_type(m, REF_PHANDLE) { 939168793Sthompsa if (get_node_by_ref(dti->dt, m->ref)) 940168793Sthompsa return true; 941168793Sthompsa } 942234936Semaste } 943272211Smelifaro 944272211Smelifaro for_each_child(node, c) { 945272211Smelifaro if (any_local_fixup_tree(dti, c)) 946272211Smelifaro return true; 947272211Smelifaro } 948272211Smelifaro 949272211Smelifaro return false; 950272211Smelifaro} 951272211Smelifaro 952272211Smelifarostatic void add_local_fixup_entry(struct dt_info *dti, 953272211Smelifaro struct node *lfn, struct node *node, 954272211Smelifaro struct property *prop, struct marker *m, 955272211Smelifaro struct node *refnode) 956272211Smelifaro{ 957272211Smelifaro struct node *wn, *nwn; /* local fixup node, walk node, new */ 958272211Smelifaro fdt32_t value_32; 959272211Smelifaro char **compp; 960272211Smelifaro int i, depth; 961272211Smelifaro 962272211Smelifaro /* walk back retreiving depth */ 963272211Smelifaro depth = 0; 964272244Sglebius for (wn = node; wn; wn = wn->parent) 965272244Sglebius depth++; 966272211Smelifaro 967272211Smelifaro /* allocate name array */ 968272211Smelifaro compp = xmalloc(sizeof(*compp) * depth); 969272211Smelifaro 970272211Smelifaro /* store names in the array */ 971272211Smelifaro for (wn = node, i = depth - 1; wn; wn = wn->parent, i--) 972272211Smelifaro compp[i] = wn->name; 973272244Sglebius 974272211Smelifaro /* walk the path components creating nodes if they don't exist */ 975272211Smelifaro for (wn = lfn, i = 1; i < depth; i++, wn = nwn) { 976272211Smelifaro /* if no node exists, create it */ 977272211Smelifaro nwn = get_subnode(wn, compp[i]); 978272211Smelifaro if (!nwn) 979272211Smelifaro nwn = build_and_name_child_node(wn, compp[i]); 980272211Smelifaro } 981272211Smelifaro 982272211Smelifaro free(compp); 983272211Smelifaro 984272211Smelifaro value_32 = cpu_to_fdt32(m->offset); 985272211Smelifaro append_to_property(wn, prop->name, &value_32, sizeof(value_32)); 986272211Smelifaro} 987272211Smelifaro 988272211Smelifarostatic void generate_local_fixups_tree_internal(struct dt_info *dti, 989272211Smelifaro struct node *lfn, 990272244Sglebius struct node *node) 991272211Smelifaro{ 992272211Smelifaro struct node *dt = dti->dt; 993272211Smelifaro struct node *c; 994272211Smelifaro struct property *prop; 995272211Smelifaro struct marker *m; 996272211Smelifaro struct node *refnode; 997272211Smelifaro 998234936Semaste for_each_property(node, prop) { 999234936Semaste m = prop->val.markers; 1000168793Sthompsa for_each_marker_of_type(m, REF_PHANDLE) { 1001168793Sthompsa refnode = get_node_by_ref(dt, m->ref); 1002249925Sglebius if (refnode) 1003168793Sthompsa add_local_fixup_entry(dti, lfn, node, prop, m, refnode); 1004168793Sthompsa } 1005168793Sthompsa } 1006168793Sthompsa 1007168793Sthompsa for_each_child(node, c) 1008168793Sthompsa generate_local_fixups_tree_internal(dti, lfn, c); 1009191148Skmacy} 1010168793Sthompsa 1011168793Sthompsavoid generate_label_tree(struct dt_info *dti, char *name, bool allocph) 1012168793Sthompsa{ 1013168793Sthompsa if (!any_label_tree(dti, dti->dt)) 1014245741Sglebius return; 1015168793Sthompsa generate_label_tree_internal(dti, build_root_node(dti->dt, name), 1016168793Sthompsa dti->dt, allocph); 1017168793Sthompsa} 1018168793Sthompsa 1019168793Sthompsavoid generate_fixups_tree(struct dt_info *dti, char *name) 1020168793Sthompsa{ 1021168793Sthompsa if (!any_fixup_tree(dti, dti->dt)) 1022168793Sthompsa return; 1023168793Sthompsa generate_fixups_tree_internal(dti, build_root_node(dti->dt, name), 1024168793Sthompsa dti->dt); 1025237852Sthompsa} 1026237852Sthompsa 1027237852Sthompsavoid generate_local_fixups_tree(struct dt_info *dti, char *name) 1028168793Sthompsa{ 1029170599Sthompsa if (!any_local_fixup_tree(dti, dti->dt)) 1030168793Sthompsa return; 1031318329Smav generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name), 1032318329Smav dti->dt); 1033168793Sthompsa} 1034318329Smav