ofw.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  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 <rtthread.h>
  11. #include <rtdevice.h>
  12. #include <drivers/platform.h>
  13. #include <drivers/core/bus.h>
  14. #include "../serial/serial_dm.h"
  15. #define DBG_TAG "rtdm.ofw"
  16. #define DBG_LVL DBG_INFO
  17. #include <rtdbg.h>
  18. #include "ofw_internal.h"
  19. struct rt_ofw_stub *rt_ofw_stub_probe_range(struct rt_ofw_node *np,
  20. const struct rt_ofw_stub *stub_start, const struct rt_ofw_stub *stub_end)
  21. {
  22. const struct rt_ofw_stub *stub = RT_NULL;
  23. if (np && stub_start && stub_end &&
  24. !rt_ofw_node_test_flag(np, RT_OFW_F_READLY) &&
  25. !rt_ofw_node_test_flag(np, RT_OFW_F_SYSTEM))
  26. {
  27. struct rt_ofw_prop *compat_prop = rt_ofw_get_prop(np, "compatible", RT_NULL);
  28. if (compat_prop)
  29. {
  30. rt_ofw_foreach_stub(stub, stub_start, stub_end)
  31. {
  32. struct rt_ofw_node_id *id;
  33. if (!stub->ids)
  34. {
  35. continue;
  36. }
  37. id = rt_ofw_prop_match(compat_prop, stub->ids);
  38. if (id)
  39. {
  40. if (!stub->handler(np, id))
  41. {
  42. rt_ofw_node_set_flag(np, RT_OFW_F_READLY);
  43. }
  44. break;
  45. }
  46. }
  47. }
  48. }
  49. return (struct rt_ofw_stub *)stub;
  50. }
  51. static const char *ofw_console_serial_find(char *dst_con, struct rt_ofw_node *np)
  52. {
  53. rt_object_t rt_obj = RT_NULL;
  54. const char *ofw_name = RT_NULL;
  55. struct rt_serial_device *rt_serial = rt_ofw_data(np);
  56. if (rt_serial)
  57. {
  58. rt_obj = &rt_serial->parent.parent;
  59. }
  60. /*
  61. * This is a dangerous behavior because rt_data can be modified by other
  62. * user. But fortunately, we can check if the rt_data is a rt_device or
  63. * rt_serial_device.
  64. */
  65. if (rt_obj && rt_object_get_type(rt_obj) == RT_Object_Class_Device &&
  66. rt_serial->parent.type == RT_Device_Class_Char)
  67. {
  68. ofw_name = np->full_name;
  69. rt_strncpy(dst_con, rt_obj->name, RT_NAME_MAX);
  70. }
  71. return ofw_name;
  72. }
  73. static int tty_device_compare(rt_device_t dev, void *data)
  74. {
  75. rt_ubase_t *args_list;
  76. char *dst_con;
  77. const char *console, **ofw_name;
  78. const struct rt_ofw_node_id *id;
  79. struct rt_platform_device *pdev;
  80. int *tty_idx, tty_id, tty_name_len;
  81. pdev = rt_container_of(dev, struct rt_platform_device, parent);
  82. id = pdev->id;
  83. args_list = data;
  84. tty_idx = (int *)args_list[0];
  85. tty_id = args_list[1];
  86. console = (const char *)args_list[2];
  87. tty_name_len = args_list[3];
  88. dst_con = (char *)args_list[4];
  89. ofw_name = (const char **)args_list[5];
  90. if (id && id->type[0] && !strncmp(id->type, console, tty_name_len))
  91. {
  92. if (*tty_idx == tty_id)
  93. {
  94. *ofw_name = ofw_console_serial_find(dst_con, pdev->parent.ofw_node);
  95. return RT_EOK;
  96. }
  97. ++*tty_idx;
  98. }
  99. return -RT_EEMPTY;
  100. }
  101. static const char *ofw_console_tty_find(char *dst_con, const char *con)
  102. {
  103. const char *ofw_name = RT_NULL;
  104. static rt_bus_t platform_bus = RT_NULL;
  105. if (!platform_bus)
  106. {
  107. platform_bus = rt_bus_find_by_name("platform");
  108. }
  109. if (platform_bus)
  110. {
  111. rt_ubase_t args_list[6];
  112. const char *console = con;
  113. int tty_idx = 0, tty_id = 0, tty_name_len;
  114. con += sizeof("tty") - 1;
  115. while (*con && !(*con >= '0' && *con <= '9'))
  116. {
  117. ++con;
  118. }
  119. tty_name_len = con - console;
  120. while (*con && *con >= '0' && *con <= '9')
  121. {
  122. tty_id *= 10;
  123. tty_id += *con - '0';
  124. ++con;
  125. }
  126. args_list[0] = (rt_ubase_t)&tty_idx;
  127. args_list[1] = tty_id;
  128. args_list[2] = (rt_ubase_t)console;
  129. args_list[3] = tty_name_len;
  130. args_list[4] = (rt_ubase_t)dst_con;
  131. args_list[5] = (rt_ubase_t)&ofw_name;
  132. rt_bus_for_each_dev(platform_bus, &args_list, tty_device_compare);
  133. }
  134. return ofw_name;
  135. }
  136. rt_err_t rt_ofw_console_setup(void)
  137. {
  138. rt_err_t err = -RT_ENOSYS;
  139. char con_name[RT_NAME_MAX], *options = RT_NULL;
  140. const char *ofw_name = RT_NULL, *stdout_path, *con;
  141. /* chosen.console > chosen.stdout-path > RT_CONSOLE_DEVICE_NAME */
  142. con = rt_ofw_bootargs_select("console=", 0);
  143. for (int i = 1; con; ++i)
  144. {
  145. if (!rt_strncmp(con, "uart", sizeof("uart") - 1))
  146. {
  147. rt_strncpy(con_name, con, RT_NAME_MAX);
  148. err = RT_EOK;
  149. break;
  150. }
  151. else if (!rt_strncmp(con, "tty", sizeof("tty") - 1))
  152. {
  153. ofw_name = ofw_console_tty_find(con_name, con);
  154. if (ofw_name)
  155. {
  156. const char *ch = con;
  157. while (*ch && *ch != ' ')
  158. {
  159. if (*ch++ == ',')
  160. {
  161. options = (char *)ch;
  162. break;
  163. }
  164. }
  165. err = RT_EOK;
  166. break;
  167. }
  168. }
  169. con = rt_ofw_bootargs_select("console=", i);
  170. }
  171. if (err == -RT_ENOSYS && !rt_ofw_prop_read_string(ofw_node_chosen, "stdout-path", &stdout_path))
  172. {
  173. struct rt_ofw_node *stdout_np = rt_ofw_find_node_by_path(stdout_path);
  174. if (stdout_np && (ofw_name = ofw_console_serial_find(con_name, stdout_np)))
  175. {
  176. err = RT_EOK;
  177. }
  178. }
  179. if (err == -RT_ENOSYS)
  180. {
  181. rt_device_t serial = rt_device_find(RT_CONSOLE_DEVICE_NAME);
  182. if (serial)
  183. {
  184. ofw_name = rt_ofw_node_full_name(serial->ofw_node);
  185. con = RT_CONSOLE_DEVICE_NAME;
  186. }
  187. else
  188. {
  189. LOG_W("Console will probably fail to setup");
  190. }
  191. }
  192. else
  193. {
  194. con = con_name;
  195. }
  196. rt_console_set_device(con);
  197. if (options)
  198. {
  199. rt_device_t con_dev = rt_console_get_device();
  200. if (con_dev)
  201. {
  202. struct serial_configure con_conf = serial_cfg_from_args(options);
  203. rt_device_control(con_dev, RT_DEVICE_CTRL_CONFIG, &con_conf);
  204. }
  205. }
  206. rt_fdt_earlycon_kick(FDT_EARLYCON_KICK_COMPLETED);
  207. LOG_I("Console: %s (%s)", con, ofw_name ? ofw_name : "<unknown>");
  208. return err;
  209. }
  210. const char *rt_ofw_bootargs_select(const char *key, int index)
  211. {
  212. const char *value = RT_NULL;
  213. if (key && index >= 0)
  214. {
  215. static char **values = RT_NULL;
  216. static rt_size_t bootargs_nr = 1;
  217. const char *bootargs = RT_NULL, *ch;
  218. if (bootargs_nr && !values &&
  219. (bootargs_nr = 0, !rt_ofw_prop_read_string(ofw_node_chosen, "bootargs", &bootargs)) &&
  220. bootargs && (bootargs = rt_strdup(bootargs)))
  221. {
  222. rt_bool_t quotes = RT_TRUE;
  223. rt_size_t length = rt_strlen(bootargs);
  224. const char *bootargs_end = bootargs + length;
  225. for (ch = bootargs; ch < bootargs_end; ++ch)
  226. {
  227. if (*ch == '"')
  228. {
  229. quotes = !quotes;
  230. continue;
  231. }
  232. if (*ch != ' ' || !quotes)
  233. {
  234. continue;
  235. }
  236. ++bootargs_nr;
  237. while (*ch == ' ' && ch < bootargs_end)
  238. {
  239. *(char *)ch++ = '\0';
  240. }
  241. --ch;
  242. }
  243. if (bootargs_nr)
  244. {
  245. /* last arg */
  246. ++bootargs_nr;
  247. values = rt_malloc(sizeof(char *) * bootargs_nr);
  248. }
  249. if (values)
  250. {
  251. int idx = 0;
  252. for (int i = 0; i < length; ++i)
  253. {
  254. for (; i < length && !bootargs[i]; ++i)
  255. {
  256. }
  257. if (i < length)
  258. {
  259. values[idx++] = (char *)&bootargs[i];
  260. }
  261. for (; i < length && bootargs[i]; ++i)
  262. {
  263. }
  264. }
  265. }
  266. else
  267. {
  268. rt_free((char *)bootargs);
  269. }
  270. }
  271. if (values)
  272. {
  273. int keylen = rt_strlen(key);
  274. for (int idx = 0, count = 0; idx < bootargs_nr; ++idx)
  275. {
  276. if (!rt_strncmp(values[idx], key, keylen))
  277. {
  278. if (count == index)
  279. {
  280. value = values[idx] + keylen;
  281. break;
  282. }
  283. ++count;
  284. }
  285. }
  286. }
  287. }
  288. return value;
  289. }
  290. #ifdef RT_USING_CONSOLE
  291. static void dts_put_depth(int depth)
  292. {
  293. while (depth --> 0)
  294. {
  295. rt_kputs(" ");
  296. }
  297. }
  298. static rt_bool_t dts_test_string_list(const void *value, int size)
  299. {
  300. const char *str, *str_start, *str_end;
  301. if (!size)
  302. {
  303. return RT_FALSE;
  304. }
  305. str = value;
  306. /* String end with '\0' */
  307. if (str[size - 1] != '\0')
  308. {
  309. return RT_FALSE;
  310. }
  311. /* Get string list end */
  312. str_end = str + size;
  313. while (str < str_end)
  314. {
  315. str_start = str;
  316. /* Before string list end, not '\0' and a printable characters */
  317. while (str < str_end && *str && ((unsigned char)*str >= ' ' && (unsigned char)*str <= '~'))
  318. {
  319. ++str;
  320. }
  321. /* Not zero, or not increased */
  322. if (*str != '\0' || str == str_start)
  323. {
  324. return RT_FALSE;
  325. }
  326. /* Next string */
  327. ++str;
  328. }
  329. return RT_TRUE;
  330. }
  331. static void ofw_node_dump_dts(struct rt_ofw_node *np, rt_bool_t sibling_too)
  332. {
  333. int depth = 0;
  334. struct rt_ofw_prop *prop;
  335. struct rt_ofw_node *org_np = np;
  336. while (np)
  337. {
  338. dts_put_depth(depth);
  339. rt_kputs(np->full_name);
  340. rt_kputs(" {\n");
  341. prop = np->props;
  342. /* Print prop start */
  343. ++depth;
  344. while (prop)
  345. {
  346. dts_put_depth(depth);
  347. rt_kputs(prop->name);
  348. /* Have value? */
  349. if (prop->length > 0)
  350. {
  351. int length = prop->length;
  352. void *value = prop->value;
  353. rt_kputs(" = ");
  354. if (dts_test_string_list(value, length))
  355. {
  356. /* String list */
  357. char *str = value;
  358. do {
  359. rt_kputs("\"");
  360. rt_kputs(str);
  361. rt_kputs("\", ");
  362. str += rt_strlen(str) + 1;
  363. } while (str < (char *)value + length);
  364. rt_kputs("\b\b");
  365. }
  366. else if ((length % 4) == 0)
  367. {
  368. /* u32 data in <?> */
  369. fdt32_t *cell = value;
  370. rt_kputs("<");
  371. length /= 4;
  372. for (int i = 0; i < length; ++i)
  373. {
  374. rt_kprintf("0x%02x ", fdt32_to_cpu(cell[i]));
  375. }
  376. rt_kputs("\b>");
  377. }
  378. else
  379. {
  380. /* Byte data in [?] */
  381. rt_uint8_t *byte = value;
  382. rt_kputs("[");
  383. for (int i = 0; i < length; ++i)
  384. {
  385. rt_kprintf("%02x ", *byte++);
  386. }
  387. rt_kputs("\b]");
  388. }
  389. }
  390. rt_kputs(";\n");
  391. prop = prop->next;
  392. }
  393. --depth;
  394. /* Print prop end */
  395. if (np->child)
  396. {
  397. rt_kputs("\n");
  398. np = np->child;
  399. ++depth;
  400. }
  401. else
  402. {
  403. dts_put_depth(depth);
  404. rt_kputs("};\n");
  405. if (!sibling_too && org_np == np)
  406. {
  407. break;
  408. }
  409. while (np->parent && !np->sibling)
  410. {
  411. np = np->parent;
  412. --depth;
  413. if (depth >= 0)
  414. {
  415. dts_put_depth(depth);
  416. rt_kputs("};\n");
  417. }
  418. }
  419. if (!sibling_too && org_np == np)
  420. {
  421. break;
  422. }
  423. np = np->sibling;
  424. if (np)
  425. {
  426. rt_kputs("\n");
  427. }
  428. }
  429. }
  430. }
  431. void rt_ofw_node_dump_dts(struct rt_ofw_node *np, rt_bool_t sibling_too)
  432. {
  433. if (np)
  434. {
  435. if (!rt_strcmp(np->name, "/"))
  436. {
  437. struct fdt_info *header = (struct fdt_info *)np->name;
  438. struct fdt_reserve_entry *rsvmap = header->rsvmap;
  439. rt_kprintf("/dts-v%x/;\n\n", fdt_version(header->fdt));
  440. for (int i = header->rsvmap_nr - 1; i >= 0; --i)
  441. {
  442. rt_kprintf("/memreserve/\t%p %p;\n",
  443. ofw_static_cast(rt_size_t, fdt64_to_cpu(rsvmap->address)),
  444. ofw_static_cast(rt_size_t, fdt64_to_cpu(rsvmap->size)));
  445. ++rsvmap;
  446. }
  447. rt_kputs(np->name);
  448. }
  449. ofw_node_dump_dts(np, sibling_too);
  450. }
  451. }
  452. #ifdef RT_USING_MSH
  453. static void ofw_dts(int argc, char**argv)
  454. {
  455. if (ofw_node_root)
  456. {
  457. if (argc == 1)
  458. {
  459. rt_ofw_node_dump_dts(ofw_node_root, RT_TRUE);
  460. }
  461. else if (argv[1][0] == '/')
  462. {
  463. struct rt_ofw_node *np = rt_ofw_find_node_by_path(argv[1]);
  464. if (np)
  465. {
  466. rt_ofw_node_dump_dts(np, RT_FALSE);
  467. }
  468. else
  469. {
  470. rt_kprintf("%s not found.\n", argv[1]);
  471. }
  472. }
  473. else if (argc >= 2 && !rt_strcmp(argv[1], "list") && argv[2][0] == '/')
  474. {
  475. struct rt_ofw_node *np = rt_ofw_find_node_by_path(argv[2]);
  476. if (np)
  477. {
  478. const char *split = np == ofw_node_root ? "" : "/";
  479. np = np->child;
  480. while (np)
  481. {
  482. rt_kprintf("%s%s%s\n", argv[2], split, np->full_name);
  483. np = np->sibling;
  484. }
  485. }
  486. else
  487. {
  488. rt_kprintf("%s not found.\n", argv[2]);
  489. }
  490. }
  491. else
  492. {
  493. rt_kprintf("Usage: %s {list} {path}\n", __func__);
  494. }
  495. }
  496. else
  497. {
  498. rt_kprintf("\"/\" path not found.");
  499. }
  500. }
  501. MSH_CMD_EXPORT(ofw_dts, dump the dts or node for this platform);
  502. #endif /* RT_USING_MSH */
  503. #endif /* RT_USING_CONSOLE */