fdt.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065
  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, parent, "ranges", &length);
  68. }
  69. if (ranges && length > 0)
  70. {
  71. local.addr_cells = fdt_address_cells(fdt, parent);
  72. local.size_cells = fdt_size_cells(fdt, parent);
  73. cpu.addr_cells = fdt_io_addr_cells(fdt, parent);
  74. cpu.size_cells = fdt_io_size_cells(fdt, parent);
  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 - local.addr + 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(fdt_get_name(_fdt, nodeoffset, RT_NULL),
  199. base, base + size, is_nomap);
  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. rt_err_t rt_fdt_bootargs_select(const char *key, int index, const char **out_result)
  638. {
  639. rt_err_t err;
  640. if (key && index >= 0 && out_result)
  641. {
  642. int offset = fdt_path_offset(_fdt, "/chosen");
  643. if (offset >= 0)
  644. {
  645. int len, key_len = rt_strlen(key);
  646. const char *bootargs = fdt_getprop(_fdt, offset, "bootargs", &len), *end;
  647. end = bootargs + len;
  648. err = -RT_EEMPTY;
  649. for (int i = 0; bootargs < end; ++i)
  650. {
  651. bootargs = rt_strstr(bootargs, key);
  652. if (!bootargs)
  653. {
  654. break;
  655. }
  656. bootargs += key_len;
  657. if (i == index)
  658. {
  659. *out_result = bootargs;
  660. err = -RT_EOK;
  661. break;
  662. }
  663. }
  664. }
  665. else
  666. {
  667. err = -RT_ERROR;
  668. }
  669. }
  670. else
  671. {
  672. err = -RT_EINVAL;
  673. }
  674. return err;
  675. }
  676. static void system_node_init_flag(struct rt_ofw_node *np)
  677. {
  678. if (np)
  679. {
  680. rt_ofw_node_set_flag(np, RT_OFW_F_READLY);
  681. rt_ofw_node_set_flag(np, RT_OFW_F_SYSTEM);
  682. }
  683. }
  684. rt_err_t rt_fdt_unflatten(void)
  685. {
  686. rt_err_t err = RT_EOK;
  687. if (_fdt)
  688. {
  689. _phandle_min = OFW_PHANDLE_MAX;
  690. _phandle_max = OFW_PHANDLE_MIN;
  691. ofw_node_root = rt_fdt_unflatten_single(_fdt);
  692. if (ofw_node_root)
  693. {
  694. ofw_node_cpus = rt_ofw_find_node_by_path("/cpus");
  695. ofw_node_chosen = rt_ofw_find_node_by_path("/chosen");
  696. ofw_node_aliases = rt_ofw_find_node_by_path("/aliases");
  697. ofw_node_reserved_memory = rt_ofw_find_node_by_path("/reserved-memory");
  698. RT_ASSERT(ofw_node_cpus != RT_NULL);
  699. system_node_init_flag(ofw_node_root);
  700. system_node_init_flag(ofw_node_cpus);
  701. system_node_init_flag(ofw_node_chosen);
  702. system_node_init_flag(ofw_node_aliases);
  703. system_node_init_flag(ofw_node_reserved_memory);
  704. if (ofw_node_aliases)
  705. {
  706. err = ofw_alias_scan();
  707. }
  708. err = err ? : ofw_phandle_hash_reset(_phandle_min, _phandle_max);
  709. }
  710. }
  711. else
  712. {
  713. err = -RT_ERROR;
  714. }
  715. return err;
  716. }
  717. static rt_err_t fdt_unflatten_props(struct rt_ofw_node *np, int node_off)
  718. {
  719. rt_err_t err = RT_EOK;
  720. struct rt_ofw_prop *prop;
  721. int prop_off = fdt_first_property_offset(_fdt, node_off);
  722. if (prop_off >= 0)
  723. {
  724. np->props = rt_malloc(sizeof(struct rt_ofw_prop));
  725. }
  726. prop = np->props;
  727. while (prop_off >= 0)
  728. {
  729. if (!prop)
  730. {
  731. err = -RT_ENOMEM;
  732. break;
  733. }
  734. prop->value = (void *)fdt_getprop_by_offset(_fdt, prop_off, &prop->name, &prop->length);
  735. if (prop->name && !rt_strcmp(prop->name, "name"))
  736. {
  737. np->name = prop->value;
  738. }
  739. prop_off = fdt_next_property_offset(_fdt, prop_off);
  740. if (prop_off < 0)
  741. {
  742. prop->next = RT_NULL;
  743. break;
  744. }
  745. prop->next = rt_malloc(sizeof(struct rt_ofw_prop));
  746. prop = prop->next;
  747. }
  748. return err;
  749. }
  750. static rt_err_t fdt_unflatten_single(struct rt_ofw_node *np, int node_off)
  751. {
  752. int depth = 0;
  753. rt_err_t err = RT_EOK;
  754. struct rt_ofw_node *np_stack[OFW_NODE_MAX_DEPTH], *parent = RT_NULL;
  755. do {
  756. if (!np)
  757. {
  758. err = -RT_ENOMEM;
  759. break;
  760. }
  761. np->name = "<NULL>";
  762. np->full_name = fdt_get_name(_fdt, node_off, RT_NULL);
  763. np->phandle = fdt_get_phandle(_fdt, node_off);
  764. if (np->phandle >= OFW_PHANDLE_MIN)
  765. {
  766. if (np->phandle < _phandle_min)
  767. {
  768. _phandle_min = np->phandle;
  769. }
  770. if (np->phandle > _phandle_max)
  771. {
  772. _phandle_max = np->phandle;
  773. }
  774. }
  775. if ((err = fdt_unflatten_props(np, node_off)))
  776. {
  777. break;
  778. }
  779. np->parent = parent;
  780. rt_ref_init(&np->ref);
  781. np->flags = 0;
  782. if (!np->child)
  783. {
  784. /* Save node offset temp */
  785. rt_ofw_data(np) = (void *)(rt_ubase_t)node_off;
  786. /* Check children */
  787. node_off = fdt_first_subnode(_fdt, node_off);
  788. if (node_off >= 0)
  789. {
  790. parent = np;
  791. np_stack[depth++] = np;
  792. np->child = rt_calloc(1, sizeof(struct rt_ofw_node));
  793. np = np->child;
  794. continue;
  795. }
  796. }
  797. while (depth >= 0)
  798. {
  799. /* Restore node offset temp */
  800. node_off = (long)rt_ofw_data(np);
  801. rt_ofw_data(np) = RT_NULL;
  802. /* Next step */
  803. node_off = fdt_next_subnode(_fdt, node_off);
  804. if (node_off < 0)
  805. {
  806. np->sibling = RT_NULL;
  807. np = np_stack[--depth];
  808. }
  809. else
  810. {
  811. parent = np->parent;
  812. np->sibling = rt_calloc(1, sizeof(struct rt_ofw_node));
  813. np = np->sibling;
  814. break;
  815. }
  816. }
  817. } while (depth >= 0);
  818. return err;
  819. }
  820. struct rt_ofw_node *rt_fdt_unflatten_single(void *fdt)
  821. {
  822. int root_off;
  823. struct fdt_info *header;
  824. struct rt_ofw_node *root = RT_NULL;
  825. if (fdt && (root_off = fdt_path_offset(fdt, "/")) >= 0)
  826. {
  827. root = rt_calloc(1, sizeof(struct fdt_info) + sizeof(struct rt_ofw_node));
  828. }
  829. if (root)
  830. {
  831. header = (void *)root + sizeof(struct rt_ofw_node);
  832. rt_strncpy(header->name, "/", sizeof("/"));
  833. header->fdt = fdt;
  834. header->rsvmap = (struct fdt_reserve_entry *)((void *)fdt + fdt_off_mem_rsvmap(fdt));
  835. header->rsvmap_nr = fdt_num_mem_rsv(fdt);
  836. if (!fdt_unflatten_single(root, root_off))
  837. {
  838. root->name = (const char *)header;
  839. }
  840. else
  841. {
  842. rt_ofw_node_destroy(root);
  843. root = RT_NULL;
  844. }
  845. }
  846. return root;
  847. }