fdt.c 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016
  1. /*
  2. * Copyright (c) 2006-2024, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-08-25 GuEe-GUI first version
  9. */
  10. #include <rthw.h>
  11. #include <rtthread.h>
  12. #include <drivers/ofw_fdt.h>
  13. #include <drivers/ofw_raw.h>
  14. #include <drivers/core/dm.h>
  15. #include <mm_memblock.h>
  16. #define DBG_TAG "rtdm.ofw"
  17. #define DBG_LVL DBG_INFO
  18. #include <rtdbg.h>
  19. #include "ofw_internal.h"
  20. struct rt_fdt_earlycon fdt_earlycon rt_section(".bss.noclean.earlycon");
  21. RT_OFW_SYMBOL_TYPE_RANGE(earlycon, struct rt_fdt_earlycon_id, _earlycon_start = {}, _earlycon_end = {});
  22. #ifndef ARCH_INIT_MEMREGION_NR
  23. #define ARCH_INIT_MEMREGION_NR 128
  24. #endif
  25. static void *_fdt = RT_NULL;
  26. static rt_phandle _phandle_min;
  27. static rt_phandle _phandle_max;
  28. static rt_size_t _root_size_cells;
  29. static rt_size_t _root_addr_cells;
  30. const char *rt_fdt_node_name(const char *full_name)
  31. {
  32. const char *node_name = strrchr(full_name, '/');
  33. return node_name ? node_name + 1 : full_name;
  34. }
  35. rt_uint64_t rt_fdt_read_number(const fdt32_t *cell, int size)
  36. {
  37. rt_uint64_t val = 0;
  38. for (; size--; ++cell)
  39. {
  40. val = (val << 32) | fdt32_to_cpu(*cell);
  41. }
  42. return val;
  43. }
  44. rt_uint64_t rt_fdt_next_cell(const fdt32_t **cellptr, int size)
  45. {
  46. const fdt32_t *ptr = *cellptr;
  47. *cellptr = ptr + size;
  48. return rt_fdt_read_number(ptr, size);
  49. }
  50. rt_uint64_t rt_fdt_translate_address(void *fdt, int nodeoffset, rt_uint64_t address)
  51. {
  52. rt_uint64_t ret = address;
  53. if (fdt && nodeoffset >= 0)
  54. {
  55. struct
  56. {
  57. rt_uint64_t addr;
  58. rt_size_t size;
  59. int addr_cells;
  60. int size_cells;
  61. } local, cpu;
  62. int parent, length = 0, group_len;
  63. const fdt32_t *ranges = RT_NULL;
  64. parent = fdt_parent_offset(fdt, nodeoffset);
  65. if (parent >= 0)
  66. {
  67. ranges = fdt_getprop(fdt, nodeoffset, "ranges", &length);
  68. }
  69. if (ranges && length > 0)
  70. {
  71. local.addr_cells = fdt_address_cells(fdt, nodeoffset);
  72. local.size_cells = fdt_size_cells(fdt, nodeoffset);
  73. cpu.addr_cells = fdt_io_addr_cells(fdt, nodeoffset);
  74. cpu.size_cells = fdt_io_size_cells(fdt, nodeoffset);
  75. group_len = local.addr_cells + cpu.addr_cells + local.size_cells;
  76. while (length > 0)
  77. {
  78. local.addr = rt_fdt_next_cell(&ranges, local.addr_cells);
  79. cpu.addr = rt_fdt_next_cell(&ranges, cpu.addr_cells);
  80. local.size = rt_fdt_next_cell(&ranges, local.size_cells);
  81. if (local.addr <= address && local.addr + local.size > address)
  82. {
  83. ret += address - cpu.addr;
  84. break;
  85. }
  86. length -= group_len;
  87. }
  88. }
  89. }
  90. return ret;
  91. }
  92. rt_bool_t rt_fdt_device_is_available(void *fdt, int nodeoffset)
  93. {
  94. rt_bool_t ret;
  95. const char *status = fdt_getprop(fdt, nodeoffset, "status", RT_NULL);
  96. if (!status)
  97. {
  98. ret = RT_TRUE;
  99. }
  100. else if (!rt_strcmp(status, "ok") || !rt_strcmp(status, "okay"))
  101. {
  102. ret = RT_TRUE;
  103. }
  104. else
  105. {
  106. ret = RT_FALSE;
  107. }
  108. return ret;
  109. }
  110. rt_err_t rt_fdt_prefetch(void *fdt)
  111. {
  112. rt_err_t err = -RT_ERROR;
  113. if (fdt)
  114. {
  115. _fdt = fdt;
  116. if (!fdt_check_header(_fdt))
  117. {
  118. err = rt_fdt_scan_root();
  119. }
  120. else
  121. {
  122. err = -RT_EINVAL;
  123. }
  124. }
  125. return err;
  126. }
  127. rt_err_t rt_fdt_scan_root(void)
  128. {
  129. rt_err_t err = RT_EOK;
  130. int root = fdt_path_offset(_fdt, "/");
  131. if (root >= 0)
  132. {
  133. const fdt32_t *prop;
  134. _root_addr_cells = OFW_ROOT_NODE_ADDR_CELLS_DEFAULT;
  135. _root_size_cells = OFW_ROOT_NODE_SIZE_CELLS_DEFAULT;
  136. if ((prop = fdt_getprop(_fdt, root, "#address-cells", RT_NULL)))
  137. {
  138. _root_addr_cells = fdt32_to_cpu(*prop);
  139. }
  140. if ((prop = fdt_getprop(_fdt, root, "#size-cells", RT_NULL)))
  141. {
  142. _root_size_cells = fdt32_to_cpu(*prop);
  143. }
  144. }
  145. else
  146. {
  147. err = -RT_EEMPTY;
  148. }
  149. return err;
  150. }
  151. static rt_err_t fdt_reserved_mem_check_root(int nodeoffset)
  152. {
  153. rt_err_t err = RT_EOK;
  154. const fdt32_t *prop = fdt_getprop(_fdt, nodeoffset, "#size-cells", RT_NULL);
  155. if (!prop || fdt32_to_cpu(*prop) != _root_size_cells)
  156. {
  157. err = -RT_EINVAL;
  158. }
  159. if (!err)
  160. {
  161. prop = fdt_getprop(_fdt, nodeoffset, "#address-cells", RT_NULL);
  162. if (!prop || fdt32_to_cpu(*prop) != _root_addr_cells)
  163. {
  164. err = -RT_EINVAL;
  165. }
  166. }
  167. if (!err && !(prop = fdt_getprop(_fdt, nodeoffset, "ranges", RT_NULL)))
  168. {
  169. err = -RT_EINVAL;
  170. }
  171. return err;
  172. }
  173. static rt_err_t fdt_reserved_memory_reg(int nodeoffset, const char *uname)
  174. {
  175. rt_err_t err = RT_EOK;
  176. rt_ubase_t base, size;
  177. const fdt32_t *prop;
  178. int len, t_len = (_root_addr_cells + _root_size_cells) * sizeof(fdt32_t);
  179. if ((prop = fdt_getprop(_fdt, nodeoffset, "reg", &len)))
  180. {
  181. if (len && len % t_len != 0)
  182. {
  183. LOG_E("Reserved memory: invalid reg property in '%s', skipping node", uname);
  184. err = -RT_EINVAL;
  185. }
  186. else
  187. {
  188. for (; len >= t_len; len -= t_len)
  189. {
  190. base = rt_fdt_next_cell(&prop, _root_addr_cells);
  191. size = rt_fdt_next_cell(&prop, _root_size_cells);
  192. if (!size)
  193. {
  194. continue;
  195. }
  196. rt_bool_t is_nomap = fdt_getprop(_fdt, nodeoffset, "no-map", RT_NULL) ? RT_TRUE : RT_FALSE;
  197. base = rt_fdt_translate_address(_fdt, nodeoffset, base);
  198. rt_memblock_reserve_memory(uname, base, base + size, is_nomap);
  199. len -= t_len;
  200. }
  201. }
  202. }
  203. else
  204. {
  205. err = -RT_EEMPTY;
  206. }
  207. return err;
  208. }
  209. static void fdt_scan_reserved_memory(void)
  210. {
  211. int nodeoffset, child;
  212. nodeoffset = fdt_path_offset(_fdt, "/reserved-memory");
  213. if (nodeoffset >= 0)
  214. {
  215. if (!fdt_reserved_mem_check_root(nodeoffset))
  216. {
  217. fdt_for_each_subnode(child, _fdt, nodeoffset)
  218. {
  219. rt_err_t err;
  220. const char *uname;
  221. if (!rt_fdt_device_is_available(_fdt, child))
  222. {
  223. continue;
  224. }
  225. uname = fdt_get_name(_fdt, child, RT_NULL);
  226. err = fdt_reserved_memory_reg(child, uname);
  227. if (err == -RT_EEMPTY && fdt_getprop(_fdt, child, "size", RT_NULL))
  228. {
  229. LOG_E("Allocating reserved memory in setup is not yet supported");
  230. }
  231. }
  232. }
  233. else
  234. {
  235. LOG_E("Reserved memory: unsupported node format, ignoring");
  236. }
  237. }
  238. }
  239. static rt_err_t fdt_scan_memory(void)
  240. {
  241. int nodeoffset, no;
  242. rt_uint64_t base, size;
  243. rt_err_t err = -RT_EEMPTY;
  244. /* Process header /memreserve/ fields */
  245. for (no = 0; ; ++no)
  246. {
  247. fdt_get_mem_rsv(_fdt, no, &base, &size);
  248. if (!size)
  249. {
  250. break;
  251. }
  252. rt_memblock_reserve_memory("memreserve", base, base + size, MEMBLOCK_NONE);
  253. }
  254. fdt_for_each_subnode(nodeoffset, _fdt, 0)
  255. {
  256. int len;
  257. const fdt32_t *reg, *endptr;
  258. const char *name = fdt_get_name(_fdt, nodeoffset, RT_NULL);
  259. const char *type = fdt_getprop(_fdt, nodeoffset, "device_type", RT_NULL);
  260. if (!type || rt_strcmp(type, "memory"))
  261. {
  262. continue;
  263. }
  264. if (!rt_fdt_device_is_available(_fdt, nodeoffset))
  265. {
  266. continue;
  267. }
  268. reg = fdt_getprop(_fdt, nodeoffset, "reg", &len);
  269. if (!reg)
  270. {
  271. continue;
  272. }
  273. endptr = reg + (len / sizeof(fdt32_t));
  274. name = name ? name : "memory";
  275. while ((endptr - reg) >= (_root_addr_cells + _root_size_cells))
  276. {
  277. base = rt_fdt_next_cell(&reg, _root_addr_cells);
  278. size = rt_fdt_next_cell(&reg, _root_size_cells);
  279. if (!size)
  280. {
  281. continue;
  282. }
  283. bool is_hotpluggable = fdt_getprop(_fdt, nodeoffset, "hotpluggable", RT_NULL) ? RT_TRUE : RT_FALSE;
  284. err = rt_memblock_add_memory(name, base, base + size, is_hotpluggable);
  285. if (!err)
  286. {
  287. LOG_I("Memory node(%d) ranges: %p - %p%s", no, base, base + size, "");
  288. }
  289. else
  290. {
  291. LOG_W("Memory node(%d) ranges: %p - %p%s", no, base, base + size, " unable to record");
  292. }
  293. }
  294. }
  295. if (!err)
  296. {
  297. fdt_scan_reserved_memory();
  298. }
  299. return err;
  300. }
  301. rt_err_t rt_fdt_scan_memory(void)
  302. {
  303. rt_err_t err = -RT_EEMPTY;
  304. if (_fdt)
  305. {
  306. err = fdt_scan_memory();
  307. }
  308. return err;
  309. }
  310. static rt_err_t fdt_scan_initrd(rt_uint64_t *ranges, const char *name, const char *oem)
  311. {
  312. char tmp_name[32];
  313. rt_err_t err = -RT_EEMPTY;
  314. if (_fdt && ranges)
  315. {
  316. int offset = fdt_path_offset(_fdt, "/chosen");
  317. if (offset >= 0)
  318. {
  319. int s_len, e_len;
  320. const fdt32_t *start = RT_NULL, *end = RT_NULL;
  321. rt_snprintf(tmp_name, sizeof(tmp_name), "%s,%s-start", oem, name);
  322. start = fdt_getprop(_fdt, offset, tmp_name, &s_len);
  323. rt_snprintf(tmp_name, sizeof(tmp_name), "%s,%s-end", oem, name);
  324. end = fdt_getprop(_fdt, offset, tmp_name, &e_len);
  325. if (start && end)
  326. {
  327. s_len /= sizeof(*start);
  328. e_len /= sizeof(*end);
  329. ranges[0] = rt_fdt_read_number(start, s_len);
  330. ranges[1] = rt_fdt_read_number(end, e_len);
  331. err = RT_EOK;
  332. }
  333. }
  334. if (err)
  335. {
  336. int len;
  337. const char *options, *bootargs = fdt_getprop(_fdt, offset, "bootargs", &len);
  338. rt_snprintf(tmp_name, sizeof(tmp_name), "%s=", name);
  339. if (bootargs && (options = rt_strstr(bootargs, tmp_name)))
  340. {
  341. rt_uint64_t value;
  342. options += rt_strlen(tmp_name) + sizeof("0x") - 1;
  343. err = RT_EOK;
  344. for (int i = 0; i < 2 && !err; ++i)
  345. {
  346. value = 0;
  347. while (*options && *options != ',' && *options != ' ')
  348. {
  349. /* To lowercase or keep number */
  350. char ch = *options | ' ';
  351. value *= 16;
  352. if (ch >= '0' && ch <= '9')
  353. {
  354. value += ch - '0';
  355. }
  356. else if (ch >= 'a' && ch <= 'f')
  357. {
  358. value += ch - 'a' + 10;
  359. }
  360. else
  361. {
  362. err = -RT_EINVAL;
  363. break;
  364. }
  365. ++options;
  366. }
  367. ranges[i] = value;
  368. options += sizeof(",0x") - 1;
  369. }
  370. /* This is initrd's size, convert to initrd's end */
  371. ranges[1] += ranges[0];
  372. }
  373. }
  374. if (!err)
  375. {
  376. rt_memblock_reserve_memory("initrd", ranges[0], ranges[1], MEMBLOCK_NONE);
  377. }
  378. }
  379. else if (!ranges)
  380. {
  381. err = -RT_EINVAL;
  382. }
  383. return err;
  384. }
  385. rt_err_t rt_fdt_scan_initrd(rt_uint64_t *ranges)
  386. {
  387. rt_err_t err;
  388. err = fdt_scan_initrd(ranges, "cromfs", "rt-thread");
  389. if (err && err == -RT_EEMPTY)
  390. {
  391. err = fdt_scan_initrd(ranges, "initrd", "linux");
  392. }
  393. return err;
  394. }
  395. rt_err_t rt_fdt_model_dump(void)
  396. {
  397. rt_err_t err = RT_EOK;
  398. int root = fdt_path_offset(_fdt, "/");
  399. if (root >= 0)
  400. {
  401. const char *mach_model = fdt_getprop(_fdt, root, "model", RT_NULL);
  402. if (!mach_model)
  403. {
  404. mach_model = fdt_getprop(_fdt, root, "compatible", RT_NULL);
  405. }
  406. LOG_I("Machine model: %s", mach_model ? mach_model : "<undefined>");
  407. }
  408. else
  409. {
  410. err = -RT_EEMPTY;
  411. }
  412. return err;
  413. }
  414. rt_weak rt_err_t rt_fdt_boot_dump(void)
  415. {
  416. LOG_I("Booting RT-Thread on physical CPU 0x%x", rt_hw_cpu_id());
  417. return RT_EOK;
  418. }
  419. void rt_fdt_earlycon_output(const char *str)
  420. {
  421. if (fdt_earlycon.console_putc)
  422. {
  423. while (*str)
  424. {
  425. fdt_earlycon.console_putc(fdt_earlycon.data, *str);
  426. if (*str == '\n')
  427. {
  428. /* Make sure return */
  429. fdt_earlycon.console_putc(fdt_earlycon.data, '\r');
  430. }
  431. ++str;
  432. }
  433. }
  434. else
  435. {
  436. /* We need a byte to save '\0' */
  437. while (*str && fdt_earlycon.msg_idx < sizeof(fdt_earlycon.msg) - 1)
  438. {
  439. fdt_earlycon.msg[fdt_earlycon.msg_idx++] = *str;
  440. ++str;
  441. }
  442. fdt_earlycon.msg[fdt_earlycon.msg_idx] = '\0';
  443. }
  444. }
  445. void rt_fdt_earlycon_kick(int why)
  446. {
  447. if (fdt_earlycon.console_kick)
  448. {
  449. fdt_earlycon.console_kick(&fdt_earlycon, why);
  450. }
  451. if (why == FDT_EARLYCON_KICK_COMPLETED)
  452. {
  453. fdt_earlycon.console_putc = RT_NULL;
  454. if (fdt_earlycon.msg_idx)
  455. {
  456. fdt_earlycon.msg_idx = 0;
  457. /* Dump old messages */
  458. rt_kputs(fdt_earlycon.msg);
  459. }
  460. }
  461. }
  462. rt_err_t rt_fdt_scan_chosen_stdout(void)
  463. {
  464. rt_err_t err = RT_EOK;
  465. int offset;
  466. int len, options_len = 0;
  467. const char *options = RT_NULL, *con_type = RT_NULL;
  468. rt_memset(&fdt_earlycon, 0, sizeof(fdt_earlycon) - sizeof(fdt_earlycon.msg));
  469. fdt_earlycon.nodeoffset = -1;
  470. offset = fdt_path_offset(_fdt, "/chosen");
  471. if (offset >= 0)
  472. {
  473. const char *stdout_path = RT_NULL;
  474. const char *bootargs = fdt_getprop(_fdt, offset, "bootargs", &len);
  475. if (bootargs && (options = rt_strstr(bootargs, "earlycon")))
  476. {
  477. options += sizeof("earlycon") - 1;
  478. if (*options == '\0' || *options == ' ')
  479. {
  480. stdout_path = fdt_getprop(_fdt, offset, "stdout-path", &len);
  481. if (stdout_path && len)
  482. {
  483. const char *path_split = strchrnul(stdout_path, ':');
  484. if (*path_split != '\0')
  485. {
  486. options = path_split + 1;
  487. }
  488. len = path_split - stdout_path;
  489. /*
  490. * Will try 2 styles:
  491. * 1: stdout-path = "serialN:bbbbpnf";
  492. * 2: stdout-path = "/serial-path";
  493. */
  494. offset = fdt_path_offset_namelen(_fdt, stdout_path, len);
  495. if (offset < 0)
  496. {
  497. stdout_path = RT_NULL;
  498. }
  499. }
  500. else if (*options == '=')
  501. {
  502. ++options;
  503. }
  504. else
  505. {
  506. /* Maybe is error in bootargs or it is a new arg */
  507. options = RT_NULL;
  508. }
  509. if (!stdout_path)
  510. {
  511. /* We couldn't know how to setup the earlycon */
  512. options = RT_NULL;
  513. }
  514. }
  515. else
  516. {
  517. offset = -1;
  518. }
  519. if (options)
  520. {
  521. int type_len = 0;
  522. struct rt_fdt_earlycon_id *earlycon_id, *earlycon_id_end, *best_earlycon_id = RT_NULL;
  523. earlycon_id = (struct rt_fdt_earlycon_id *)&_earlycon_start;
  524. earlycon_id_end = (struct rt_fdt_earlycon_id *)&_earlycon_end;
  525. err = -RT_ENOSYS;
  526. /* Only "earlycon" in bootargs */
  527. if (stdout_path)
  528. {
  529. const fdt32_t *reg;
  530. options = RT_NULL;
  531. if ((reg = fdt_getprop(_fdt, offset, "reg", RT_NULL)))
  532. {
  533. rt_uint64_t address;
  534. int addr_cells = fdt_io_addr_cells(_fdt, offset);
  535. int size_cells = fdt_io_size_cells(_fdt, offset);
  536. address = rt_fdt_read_number(reg, addr_cells);
  537. fdt_earlycon.mmio = rt_fdt_translate_address(_fdt, offset, address);
  538. fdt_earlycon.size = rt_fdt_read_number(reg + addr_cells, size_cells);
  539. }
  540. }
  541. else
  542. {
  543. /* Pass split */
  544. while (*options && (*options == '=' || *options == ' '))
  545. {
  546. ++options;
  547. }
  548. if (*options)
  549. {
  550. type_len = strchrnul(options, ',') - options;
  551. }
  552. }
  553. if (options && *options && *options != ' ')
  554. {
  555. options_len = strchrnul(options, ' ') - options;
  556. rt_strncpy(fdt_earlycon.options, options, options_len);
  557. }
  558. /* console > stdout-path */
  559. for (int max_score = 0; earlycon_id < earlycon_id_end; ++earlycon_id)
  560. {
  561. int score = 0;
  562. if (type_len && earlycon_id->type)
  563. {
  564. if (!rt_strncmp(earlycon_id->type, options, type_len))
  565. {
  566. score += 1;
  567. }
  568. }
  569. if (stdout_path && earlycon_id->compatible)
  570. {
  571. if (!fdt_node_check_compatible(_fdt, offset, earlycon_id->compatible))
  572. {
  573. score += 2;
  574. }
  575. }
  576. if (score > max_score)
  577. {
  578. max_score = score;
  579. best_earlycon_id = earlycon_id;
  580. if (score == 3)
  581. {
  582. break;
  583. }
  584. }
  585. }
  586. if (best_earlycon_id && best_earlycon_id->setup)
  587. {
  588. const char earlycon_magic[] = { 'O', 'F', 'W', '\0' };
  589. if (!con_type)
  590. {
  591. con_type = best_earlycon_id->type;
  592. }
  593. fdt_earlycon.fdt = _fdt;
  594. fdt_earlycon.nodeoffset = offset;
  595. options = &fdt_earlycon.options[options_len + 1];
  596. rt_strncpy((void *)options, earlycon_magic, RT_ARRAY_SIZE(earlycon_magic));
  597. err = best_earlycon_id->setup(&fdt_earlycon, fdt_earlycon.options);
  598. if (rt_strncmp(options, earlycon_magic, RT_ARRAY_SIZE(earlycon_magic)))
  599. {
  600. const char *option_start = options - 1;
  601. while (option_start[-1] != '\0')
  602. {
  603. --option_start;
  604. }
  605. rt_memmove(fdt_earlycon.options, option_start, options - option_start);
  606. }
  607. else
  608. {
  609. fdt_earlycon.options[0] = '\0';
  610. }
  611. }
  612. }
  613. }
  614. else
  615. {
  616. err = -RT_EEMPTY;
  617. }
  618. }
  619. else
  620. {
  621. err = -RT_EEMPTY;
  622. }
  623. if (fdt_earlycon.msg_idx)
  624. {
  625. fdt_earlycon.msg_idx = 0;
  626. rt_kputs(fdt_earlycon.msg);
  627. }
  628. rt_fdt_boot_dump();
  629. rt_fdt_model_dump();
  630. if (fdt_earlycon.mmio)
  631. {
  632. LOG_I("Earlycon: %s at MMIO/PIO %p (options '%s')",
  633. con_type, fdt_earlycon.mmio, fdt_earlycon.options);
  634. }
  635. return err;
  636. }
  637. static void system_node_init_flag(struct rt_ofw_node *np)
  638. {
  639. if (np)
  640. {
  641. rt_ofw_node_set_flag(np, RT_OFW_F_READLY);
  642. rt_ofw_node_set_flag(np, RT_OFW_F_SYSTEM);
  643. }
  644. }
  645. rt_err_t rt_fdt_unflatten(void)
  646. {
  647. rt_err_t err = RT_EOK;
  648. if (_fdt)
  649. {
  650. _phandle_min = OFW_PHANDLE_MAX;
  651. _phandle_max = OFW_PHANDLE_MIN;
  652. ofw_node_root = rt_fdt_unflatten_single(_fdt);
  653. if (ofw_node_root)
  654. {
  655. ofw_node_cpus = rt_ofw_find_node_by_path("/cpus");
  656. ofw_node_chosen = rt_ofw_find_node_by_path("/chosen");
  657. ofw_node_aliases = rt_ofw_find_node_by_path("/aliases");
  658. ofw_node_reserved_memory = rt_ofw_find_node_by_path("/reserved-memory");
  659. RT_ASSERT(ofw_node_cpus != RT_NULL);
  660. system_node_init_flag(ofw_node_root);
  661. system_node_init_flag(ofw_node_cpus);
  662. system_node_init_flag(ofw_node_chosen);
  663. system_node_init_flag(ofw_node_aliases);
  664. system_node_init_flag(ofw_node_reserved_memory);
  665. if (ofw_node_aliases)
  666. {
  667. err = ofw_alias_scan();
  668. }
  669. err = err ? : ofw_phandle_hash_reset(_phandle_min, _phandle_max);
  670. }
  671. }
  672. else
  673. {
  674. err = -RT_ERROR;
  675. }
  676. return err;
  677. }
  678. static rt_err_t fdt_unflatten_props(struct rt_ofw_node *np, int node_off)
  679. {
  680. rt_err_t err = RT_EOK;
  681. struct rt_ofw_prop *prop;
  682. int prop_off = fdt_first_property_offset(_fdt, node_off);
  683. if (prop_off >= 0)
  684. {
  685. np->props = rt_malloc(sizeof(struct rt_ofw_prop));
  686. }
  687. prop = np->props;
  688. while (prop_off >= 0)
  689. {
  690. if (!prop)
  691. {
  692. err = -RT_ENOMEM;
  693. break;
  694. }
  695. prop->value = (void *)fdt_getprop_by_offset(_fdt, prop_off, &prop->name, &prop->length);
  696. if (prop->name && !rt_strcmp(prop->name, "name"))
  697. {
  698. np->name = prop->value;
  699. }
  700. prop_off = fdt_next_property_offset(_fdt, prop_off);
  701. if (prop_off < 0)
  702. {
  703. prop->next = RT_NULL;
  704. break;
  705. }
  706. prop->next = rt_malloc(sizeof(struct rt_ofw_prop));
  707. prop = prop->next;
  708. }
  709. return err;
  710. }
  711. static rt_err_t fdt_unflatten_single(struct rt_ofw_node *np, int node_off)
  712. {
  713. int depth = 0;
  714. rt_err_t err = RT_EOK;
  715. struct rt_ofw_node *np_stack[OFW_NODE_MAX_DEPTH], *parent = RT_NULL;
  716. do {
  717. if (!np)
  718. {
  719. err = -RT_ENOMEM;
  720. break;
  721. }
  722. np->name = "<NULL>";
  723. np->full_name = fdt_get_name(_fdt, node_off, RT_NULL);
  724. np->phandle = fdt_get_phandle(_fdt, node_off);
  725. if (np->phandle >= OFW_PHANDLE_MIN)
  726. {
  727. if (np->phandle < _phandle_min)
  728. {
  729. _phandle_min = np->phandle;
  730. }
  731. if (np->phandle > _phandle_max)
  732. {
  733. _phandle_max = np->phandle;
  734. }
  735. }
  736. if ((err = fdt_unflatten_props(np, node_off)))
  737. {
  738. break;
  739. }
  740. np->parent = parent;
  741. rt_ref_init(&np->ref);
  742. np->flags = 0;
  743. if (!np->child)
  744. {
  745. /* Save node offset temp */
  746. rt_ofw_data(np) = (void *)(rt_ubase_t)node_off;
  747. /* Check children */
  748. node_off = fdt_first_subnode(_fdt, node_off);
  749. if (node_off >= 0)
  750. {
  751. parent = np;
  752. np_stack[depth++] = np;
  753. np->child = rt_calloc(1, sizeof(struct rt_ofw_node));
  754. np = np->child;
  755. continue;
  756. }
  757. }
  758. while (depth >= 0)
  759. {
  760. /* Restore node offset temp */
  761. node_off = (long)rt_ofw_data(np);
  762. rt_ofw_data(np) = RT_NULL;
  763. /* Next step */
  764. node_off = fdt_next_subnode(_fdt, node_off);
  765. if (node_off < 0)
  766. {
  767. np->sibling = RT_NULL;
  768. np = np_stack[--depth];
  769. }
  770. else
  771. {
  772. parent = np->parent;
  773. np->sibling = rt_calloc(1, sizeof(struct rt_ofw_node));
  774. np = np->sibling;
  775. break;
  776. }
  777. }
  778. } while (depth >= 0);
  779. return err;
  780. }
  781. struct rt_ofw_node *rt_fdt_unflatten_single(void *fdt)
  782. {
  783. int root_off;
  784. struct fdt_info *header;
  785. struct rt_ofw_node *root = RT_NULL;
  786. if (fdt && (root_off = fdt_path_offset(fdt, "/")) >= 0)
  787. {
  788. root = rt_calloc(1, sizeof(struct fdt_info) + sizeof(struct rt_ofw_node));
  789. }
  790. if (root)
  791. {
  792. header = (void *)root + sizeof(struct rt_ofw_node);
  793. rt_strncpy(header->name, "/", sizeof("/"));
  794. header->fdt = fdt;
  795. header->rsvmap = (struct fdt_reserve_entry *)((void *)fdt + fdt_off_mem_rsvmap(fdt));
  796. header->rsvmap_nr = fdt_num_mem_rsv(fdt);
  797. if (!fdt_unflatten_single(root, root_off))
  798. {
  799. root->name = (const char *)header;
  800. }
  801. else
  802. {
  803. rt_ofw_node_destroy(root);
  804. root = RT_NULL;
  805. }
  806. }
  807. return root;
  808. }