fdt.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. /*
  2. * Functions for working with the Flattened Device Tree data format
  3. *
  4. * Copyright 2009 Benjamin Herrenschmidt, IBM Corp
  5. * benh@kernel.crashing.org
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * version 2 as published by the Free Software Foundation.
  10. */
  11. #include <linux/kernel.h>
  12. #include <linux/lmb.h>
  13. #include <linux/initrd.h>
  14. #include <linux/of.h>
  15. #include <linux/of_fdt.h>
  16. #ifdef CONFIG_PPC
  17. #include <asm/machdep.h>
  18. #endif /* CONFIG_PPC */
  19. int __initdata dt_root_addr_cells;
  20. int __initdata dt_root_size_cells;
  21. struct boot_param_header *initial_boot_params;
  22. char *find_flat_dt_string(u32 offset)
  23. {
  24. return ((char *)initial_boot_params) +
  25. initial_boot_params->off_dt_strings + offset;
  26. }
  27. /**
  28. * of_scan_flat_dt - scan flattened tree blob and call callback on each.
  29. * @it: callback function
  30. * @data: context data pointer
  31. *
  32. * This function is used to scan the flattened device-tree, it is
  33. * used to extract the memory information at boot before we can
  34. * unflatten the tree
  35. */
  36. int __init of_scan_flat_dt(int (*it)(unsigned long node,
  37. const char *uname, int depth,
  38. void *data),
  39. void *data)
  40. {
  41. unsigned long p = ((unsigned long)initial_boot_params) +
  42. initial_boot_params->off_dt_struct;
  43. int rc = 0;
  44. int depth = -1;
  45. do {
  46. u32 tag = *((u32 *)p);
  47. char *pathp;
  48. p += 4;
  49. if (tag == OF_DT_END_NODE) {
  50. depth--;
  51. continue;
  52. }
  53. if (tag == OF_DT_NOP)
  54. continue;
  55. if (tag == OF_DT_END)
  56. break;
  57. if (tag == OF_DT_PROP) {
  58. u32 sz = *((u32 *)p);
  59. p += 8;
  60. if (initial_boot_params->version < 0x10)
  61. p = _ALIGN(p, sz >= 8 ? 8 : 4);
  62. p += sz;
  63. p = _ALIGN(p, 4);
  64. continue;
  65. }
  66. if (tag != OF_DT_BEGIN_NODE) {
  67. pr_err("Invalid tag %x in flat device tree!\n", tag);
  68. return -EINVAL;
  69. }
  70. depth++;
  71. pathp = (char *)p;
  72. p = _ALIGN(p + strlen(pathp) + 1, 4);
  73. if ((*pathp) == '/') {
  74. char *lp, *np;
  75. for (lp = NULL, np = pathp; *np; np++)
  76. if ((*np) == '/')
  77. lp = np+1;
  78. if (lp != NULL)
  79. pathp = lp;
  80. }
  81. rc = it(p, pathp, depth, data);
  82. if (rc != 0)
  83. break;
  84. } while (1);
  85. return rc;
  86. }
  87. /**
  88. * of_get_flat_dt_root - find the root node in the flat blob
  89. */
  90. unsigned long __init of_get_flat_dt_root(void)
  91. {
  92. unsigned long p = ((unsigned long)initial_boot_params) +
  93. initial_boot_params->off_dt_struct;
  94. while (*((u32 *)p) == OF_DT_NOP)
  95. p += 4;
  96. BUG_ON(*((u32 *)p) != OF_DT_BEGIN_NODE);
  97. p += 4;
  98. return _ALIGN(p + strlen((char *)p) + 1, 4);
  99. }
  100. /**
  101. * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr
  102. *
  103. * This function can be used within scan_flattened_dt callback to get
  104. * access to properties
  105. */
  106. void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
  107. unsigned long *size)
  108. {
  109. unsigned long p = node;
  110. do {
  111. u32 tag = *((u32 *)p);
  112. u32 sz, noff;
  113. const char *nstr;
  114. p += 4;
  115. if (tag == OF_DT_NOP)
  116. continue;
  117. if (tag != OF_DT_PROP)
  118. return NULL;
  119. sz = *((u32 *)p);
  120. noff = *((u32 *)(p + 4));
  121. p += 8;
  122. if (initial_boot_params->version < 0x10)
  123. p = _ALIGN(p, sz >= 8 ? 8 : 4);
  124. nstr = find_flat_dt_string(noff);
  125. if (nstr == NULL) {
  126. pr_warning("Can't find property index name !\n");
  127. return NULL;
  128. }
  129. if (strcmp(name, nstr) == 0) {
  130. if (size)
  131. *size = sz;
  132. return (void *)p;
  133. }
  134. p += sz;
  135. p = _ALIGN(p, 4);
  136. } while (1);
  137. }
  138. /**
  139. * of_flat_dt_is_compatible - Return true if given node has compat in compatible list
  140. * @node: node to test
  141. * @compat: compatible string to compare with compatible list.
  142. */
  143. int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
  144. {
  145. const char *cp;
  146. unsigned long cplen, l;
  147. cp = of_get_flat_dt_prop(node, "compatible", &cplen);
  148. if (cp == NULL)
  149. return 0;
  150. while (cplen > 0) {
  151. if (strncasecmp(cp, compat, strlen(compat)) == 0)
  152. return 1;
  153. l = strlen(cp) + 1;
  154. cp += l;
  155. cplen -= l;
  156. }
  157. return 0;
  158. }
  159. static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
  160. unsigned long align)
  161. {
  162. void *res;
  163. *mem = _ALIGN(*mem, align);
  164. res = (void *)*mem;
  165. *mem += size;
  166. return res;
  167. }
  168. /**
  169. * unflatten_dt_node - Alloc and populate a device_node from the flat tree
  170. * @p: pointer to node in flat tree
  171. * @dad: Parent struct device_node
  172. * @allnextpp: pointer to ->allnext from last allocated device_node
  173. * @fpsize: Size of the node path up at the current depth.
  174. */
  175. unsigned long __init unflatten_dt_node(unsigned long mem,
  176. unsigned long *p,
  177. struct device_node *dad,
  178. struct device_node ***allnextpp,
  179. unsigned long fpsize)
  180. {
  181. struct device_node *np;
  182. struct property *pp, **prev_pp = NULL;
  183. char *pathp;
  184. u32 tag;
  185. unsigned int l, allocl;
  186. int has_name = 0;
  187. int new_format = 0;
  188. tag = *((u32 *)(*p));
  189. if (tag != OF_DT_BEGIN_NODE) {
  190. pr_err("Weird tag at start of node: %x\n", tag);
  191. return mem;
  192. }
  193. *p += 4;
  194. pathp = (char *)*p;
  195. l = allocl = strlen(pathp) + 1;
  196. *p = _ALIGN(*p + l, 4);
  197. /* version 0x10 has a more compact unit name here instead of the full
  198. * path. we accumulate the full path size using "fpsize", we'll rebuild
  199. * it later. We detect this because the first character of the name is
  200. * not '/'.
  201. */
  202. if ((*pathp) != '/') {
  203. new_format = 1;
  204. if (fpsize == 0) {
  205. /* root node: special case. fpsize accounts for path
  206. * plus terminating zero. root node only has '/', so
  207. * fpsize should be 2, but we want to avoid the first
  208. * level nodes to have two '/' so we use fpsize 1 here
  209. */
  210. fpsize = 1;
  211. allocl = 2;
  212. } else {
  213. /* account for '/' and path size minus terminal 0
  214. * already in 'l'
  215. */
  216. fpsize += l;
  217. allocl = fpsize;
  218. }
  219. }
  220. np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
  221. __alignof__(struct device_node));
  222. if (allnextpp) {
  223. memset(np, 0, sizeof(*np));
  224. np->full_name = ((char *)np) + sizeof(struct device_node);
  225. if (new_format) {
  226. char *fn = np->full_name;
  227. /* rebuild full path for new format */
  228. if (dad && dad->parent) {
  229. strcpy(fn, dad->full_name);
  230. #ifdef DEBUG
  231. if ((strlen(fn) + l + 1) != allocl) {
  232. pr_debug("%s: p: %d, l: %d, a: %d\n",
  233. pathp, (int)strlen(fn),
  234. l, allocl);
  235. }
  236. #endif
  237. fn += strlen(fn);
  238. }
  239. *(fn++) = '/';
  240. memcpy(fn, pathp, l);
  241. } else
  242. memcpy(np->full_name, pathp, l);
  243. prev_pp = &np->properties;
  244. **allnextpp = np;
  245. *allnextpp = &np->allnext;
  246. if (dad != NULL) {
  247. np->parent = dad;
  248. /* we temporarily use the next field as `last_child'*/
  249. if (dad->next == NULL)
  250. dad->child = np;
  251. else
  252. dad->next->sibling = np;
  253. dad->next = np;
  254. }
  255. kref_init(&np->kref);
  256. }
  257. while (1) {
  258. u32 sz, noff;
  259. char *pname;
  260. tag = *((u32 *)(*p));
  261. if (tag == OF_DT_NOP) {
  262. *p += 4;
  263. continue;
  264. }
  265. if (tag != OF_DT_PROP)
  266. break;
  267. *p += 4;
  268. sz = *((u32 *)(*p));
  269. noff = *((u32 *)((*p) + 4));
  270. *p += 8;
  271. if (initial_boot_params->version < 0x10)
  272. *p = _ALIGN(*p, sz >= 8 ? 8 : 4);
  273. pname = find_flat_dt_string(noff);
  274. if (pname == NULL) {
  275. pr_info("Can't find property name in list !\n");
  276. break;
  277. }
  278. if (strcmp(pname, "name") == 0)
  279. has_name = 1;
  280. l = strlen(pname) + 1;
  281. pp = unflatten_dt_alloc(&mem, sizeof(struct property),
  282. __alignof__(struct property));
  283. if (allnextpp) {
  284. if (strcmp(pname, "linux,phandle") == 0) {
  285. if (np->phandle == 0)
  286. np->phandle = *((u32 *)*p);
  287. }
  288. if (strcmp(pname, "ibm,phandle") == 0)
  289. np->phandle = *((u32 *)*p);
  290. pp->name = pname;
  291. pp->length = sz;
  292. pp->value = (void *)*p;
  293. *prev_pp = pp;
  294. prev_pp = &pp->next;
  295. }
  296. *p = _ALIGN((*p) + sz, 4);
  297. }
  298. /* with version 0x10 we may not have the name property, recreate
  299. * it here from the unit name if absent
  300. */
  301. if (!has_name) {
  302. char *p1 = pathp, *ps = pathp, *pa = NULL;
  303. int sz;
  304. while (*p1) {
  305. if ((*p1) == '@')
  306. pa = p1;
  307. if ((*p1) == '/')
  308. ps = p1 + 1;
  309. p1++;
  310. }
  311. if (pa < ps)
  312. pa = p1;
  313. sz = (pa - ps) + 1;
  314. pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
  315. __alignof__(struct property));
  316. if (allnextpp) {
  317. pp->name = "name";
  318. pp->length = sz;
  319. pp->value = pp + 1;
  320. *prev_pp = pp;
  321. prev_pp = &pp->next;
  322. memcpy(pp->value, ps, sz - 1);
  323. ((char *)pp->value)[sz - 1] = 0;
  324. pr_debug("fixed up name for %s -> %s\n", pathp,
  325. (char *)pp->value);
  326. }
  327. }
  328. if (allnextpp) {
  329. *prev_pp = NULL;
  330. np->name = of_get_property(np, "name", NULL);
  331. np->type = of_get_property(np, "device_type", NULL);
  332. if (!np->name)
  333. np->name = "<NULL>";
  334. if (!np->type)
  335. np->type = "<NULL>";
  336. }
  337. while (tag == OF_DT_BEGIN_NODE) {
  338. mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize);
  339. tag = *((u32 *)(*p));
  340. }
  341. if (tag != OF_DT_END_NODE) {
  342. pr_err("Weird tag at end of node: %x\n", tag);
  343. return mem;
  344. }
  345. *p += 4;
  346. return mem;
  347. }
  348. #ifdef CONFIG_BLK_DEV_INITRD
  349. /**
  350. * early_init_dt_check_for_initrd - Decode initrd location from flat tree
  351. * @node: reference to node containing initrd location ('chosen')
  352. */
  353. void __init early_init_dt_check_for_initrd(unsigned long node)
  354. {
  355. unsigned long start, end, len;
  356. u32 *prop;
  357. pr_debug("Looking for initrd properties... ");
  358. prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len);
  359. if (!prop)
  360. return;
  361. start = of_read_ulong(prop, len/4);
  362. prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len);
  363. if (!prop)
  364. return;
  365. end = of_read_ulong(prop, len/4);
  366. early_init_dt_setup_initrd_arch(start, end);
  367. pr_debug("initrd_start=0x%lx initrd_end=0x%lx\n", start, end);
  368. }
  369. #else
  370. inline void early_init_dt_check_for_initrd(unsigned long node)
  371. {
  372. }
  373. #endif /* CONFIG_BLK_DEV_INITRD */
  374. /**
  375. * early_init_dt_scan_root - fetch the top level address and size cells
  376. */
  377. int __init early_init_dt_scan_root(unsigned long node, const char *uname,
  378. int depth, void *data)
  379. {
  380. u32 *prop;
  381. if (depth != 0)
  382. return 0;
  383. prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
  384. dt_root_size_cells = prop ? *prop : OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
  385. pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells);
  386. prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
  387. dt_root_addr_cells = prop ? *prop : OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
  388. pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells);
  389. /* break now */
  390. return 1;
  391. }
  392. u64 __init dt_mem_next_cell(int s, __be32 **cellp)
  393. {
  394. __be32 *p = *cellp;
  395. *cellp = p + s;
  396. return of_read_number(p, s);
  397. }
  398. /**
  399. * early_init_dt_scan_memory - Look for an parse memory nodes
  400. */
  401. int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
  402. int depth, void *data)
  403. {
  404. char *type = of_get_flat_dt_prop(node, "device_type", NULL);
  405. __be32 *reg, *endp;
  406. unsigned long l;
  407. /* We are scanning "memory" nodes only */
  408. if (type == NULL) {
  409. /*
  410. * The longtrail doesn't have a device_type on the
  411. * /memory node, so look for the node called /memory@0.
  412. */
  413. if (depth != 1 || strcmp(uname, "memory@0") != 0)
  414. return 0;
  415. } else if (strcmp(type, "memory") != 0)
  416. return 0;
  417. reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
  418. if (reg == NULL)
  419. reg = of_get_flat_dt_prop(node, "reg", &l);
  420. if (reg == NULL)
  421. return 0;
  422. endp = reg + (l / sizeof(__be32));
  423. pr_debug("memory scan node %s, reg size %ld, data: %x %x %x %x,\n",
  424. uname, l, reg[0], reg[1], reg[2], reg[3]);
  425. while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
  426. u64 base, size;
  427. base = dt_mem_next_cell(dt_root_addr_cells, &reg);
  428. size = dt_mem_next_cell(dt_root_size_cells, &reg);
  429. if (size == 0)
  430. continue;
  431. pr_debug(" - %llx , %llx\n", (unsigned long long)base,
  432. (unsigned long long)size);
  433. early_init_dt_add_memory_arch(base, size);
  434. }
  435. return 0;
  436. }
  437. int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
  438. int depth, void *data)
  439. {
  440. unsigned long l;
  441. char *p;
  442. pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
  443. if (depth != 1 ||
  444. (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
  445. return 0;
  446. early_init_dt_check_for_initrd(node);
  447. /* Retreive command line */
  448. p = of_get_flat_dt_prop(node, "bootargs", &l);
  449. if (p != NULL && l > 0)
  450. strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE));
  451. #ifdef CONFIG_CMDLINE
  452. #ifndef CONFIG_CMDLINE_FORCE
  453. if (p == NULL || l == 0 || (l == 1 && (*p) == 0))
  454. #endif
  455. strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
  456. #endif /* CONFIG_CMDLINE */
  457. early_init_dt_scan_chosen_arch(node);
  458. pr_debug("Command line is: %s\n", cmd_line);
  459. /* break now */
  460. return 1;
  461. }
  462. /**
  463. * unflatten_device_tree - create tree of device_nodes from flat blob
  464. *
  465. * unflattens the device-tree passed by the firmware, creating the
  466. * tree of struct device_node. It also fills the "name" and "type"
  467. * pointers of the nodes so the normal device-tree walking functions
  468. * can be used.
  469. */
  470. void __init unflatten_device_tree(void)
  471. {
  472. unsigned long start, mem, size;
  473. struct device_node **allnextp = &allnodes;
  474. pr_debug(" -> unflatten_device_tree()\n");
  475. /* First pass, scan for size */
  476. start = ((unsigned long)initial_boot_params) +
  477. initial_boot_params->off_dt_struct;
  478. size = unflatten_dt_node(0, &start, NULL, NULL, 0);
  479. size = (size | 3) + 1;
  480. pr_debug(" size is %lx, allocating...\n", size);
  481. /* Allocate memory for the expanded device tree */
  482. mem = lmb_alloc(size + 4, __alignof__(struct device_node));
  483. mem = (unsigned long) __va(mem);
  484. ((u32 *)mem)[size / 4] = 0xdeadbeef;
  485. pr_debug(" unflattening %lx...\n", mem);
  486. /* Second pass, do actual unflattening */
  487. start = ((unsigned long)initial_boot_params) +
  488. initial_boot_params->off_dt_struct;
  489. unflatten_dt_node(mem, &start, NULL, &allnextp, 0);
  490. if (*((u32 *)start) != OF_DT_END)
  491. pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start));
  492. if (((u32 *)mem)[size / 4] != 0xdeadbeef)
  493. pr_warning("End of tree marker overwritten: %08x\n",
  494. ((u32 *)mem)[size / 4]);
  495. *allnextp = NULL;
  496. /* Get pointer to OF "/chosen" node for use everywhere */
  497. of_chosen = of_find_node_by_path("/chosen");
  498. if (of_chosen == NULL)
  499. of_chosen = of_find_node_by_path("/chosen@0");
  500. pr_debug(" <- unflatten_device_tree()\n");
  501. }