fdt.c 27 KB

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