dm.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  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. * 2023-04-20 ErikChan the first version
  9. */
  10. #include <rtthread.h>
  11. #define DBG_TAG "rtdm"
  12. #define DBG_LVL DBG_INFO
  13. #include <rtdbg.h>
  14. #ifdef RT_USING_OFW
  15. #include <drivers/ofw_io.h>
  16. #include <drivers/ofw_irq.h>
  17. #endif
  18. #include <drivers/core/dm.h>
  19. #ifdef RT_USING_SMP
  20. static int rti_secondary_cpu_start(void)
  21. {
  22. return 0;
  23. }
  24. INIT_EXPORT(rti_secondary_cpu_start, "6.end");
  25. static int rti_secondary_cpu_end(void)
  26. {
  27. return 0;
  28. }
  29. INIT_EXPORT(rti_secondary_cpu_end, "7.end");
  30. void rt_dm_secondary_cpu_init(void)
  31. {
  32. #ifdef RT_DEBUGING_AUTO_INIT
  33. int result;
  34. const struct rt_init_desc *desc;
  35. rt_kprintf("do secondary cpu initialization.\n");
  36. for (desc = &__rt_init_desc_rti_secondary_cpu_start; desc < &__rt_init_desc_rti_secondary_cpu_end; ++desc)
  37. {
  38. rt_kprintf("initialize %s", desc->fn_name);
  39. result = desc->fn();
  40. rt_kprintf(":%d done\n", result);
  41. }
  42. #else
  43. volatile const init_fn_t *fn_ptr;
  44. for (fn_ptr = &__rt_init_rti_secondary_cpu_start; fn_ptr < &__rt_init_rti_secondary_cpu_end; ++fn_ptr)
  45. {
  46. (*fn_ptr)();
  47. }
  48. #endif /* RT_DEBUGING_AUTO_INIT */
  49. }
  50. #endif /* RT_USING_SMP */
  51. /**
  52. * @brief This function will alloc an id in an IDA object
  53. *
  54. * @param ida is the IDA object
  55. *
  56. * @return the id or -RT_EEMPTY
  57. */
  58. int rt_dm_ida_alloc(struct rt_dm_ida *ida)
  59. {
  60. int id;
  61. RT_ASSERT(ida != RT_NULL);
  62. rt_spin_lock(&ida->lock);
  63. id = rt_bitmap_next_clear_bit(ida->map, 0, RT_DM_IDA_NUM);
  64. if (id != RT_DM_IDA_NUM)
  65. {
  66. rt_bitmap_set_bit(ida->map, id);
  67. }
  68. rt_spin_unlock(&ida->lock);
  69. if (id != RT_DM_IDA_NUM)
  70. {
  71. return id;
  72. }
  73. return -RT_EEMPTY;
  74. }
  75. /**
  76. * @brief This function will take (force) an id in an IDA object
  77. *
  78. * @param ida is the IDA object
  79. *
  80. * @param id is the id that want to take
  81. *
  82. * @return the result of taking
  83. */
  84. rt_bool_t rt_dm_ida_take(struct rt_dm_ida *ida, int id)
  85. {
  86. RT_ASSERT(ida != RT_NULL);
  87. RT_ASSERT(id >= 0);
  88. rt_spin_lock(&ida->lock);
  89. if (!rt_bitmap_test_bit(ida->map, id))
  90. {
  91. rt_bitmap_set_bit(ida->map, id);
  92. }
  93. else
  94. {
  95. id = RT_DM_IDA_NUM;
  96. }
  97. rt_spin_unlock(&ida->lock);
  98. return id != RT_DM_IDA_NUM;
  99. }
  100. /**
  101. * @brief This function will release an id in an IDA object
  102. *
  103. * @param ida is the IDA object
  104. *
  105. * @param id is the id of IDA object
  106. */
  107. void rt_dm_ida_free(struct rt_dm_ida *ida, int id)
  108. {
  109. RT_ASSERT(ida != RT_NULL);
  110. RT_ASSERT(id >= 0);
  111. rt_spin_lock(&ida->lock);
  112. rt_bitmap_clear_bit(ida->map, id);
  113. rt_spin_unlock(&ida->lock);
  114. }
  115. /**
  116. * @brief This function will return the specified master id and device id of device.
  117. *
  118. * @param master_id is the master id (0, 255] of device
  119. *
  120. * @param device_id is the device id [-1, 255] of device, when device_id is -1,
  121. * the function will end when find the first device.
  122. *
  123. * @return the device object or RT_NULL
  124. */
  125. rt_device_t rt_dm_device_find(int master_id, int device_id)
  126. {
  127. struct rt_device *dev, *ret_dev = RT_NULL;
  128. struct rt_object_information *information = RT_NULL;
  129. if (master_id <= 0 || device_id > 255)
  130. {
  131. return RT_NULL;
  132. }
  133. information = rt_object_get_information(RT_Object_Class_Device);
  134. /* parameter check */
  135. if (!information)
  136. {
  137. return RT_NULL;
  138. }
  139. /* which is invoke in interrupt status */
  140. RT_DEBUG_NOT_IN_INTERRUPT;
  141. /* enter critical */
  142. rt_enter_critical();
  143. /* try to find object */
  144. rt_list_for_each_entry(dev, &information->object_list, parent.list)
  145. {
  146. if (master_id == dev->master_id &&
  147. (device_id == -1 || device_id == dev->device_id))
  148. {
  149. ret_dev = dev;
  150. break;
  151. }
  152. }
  153. /* leave critical */
  154. rt_exit_critical();
  155. return ret_dev;
  156. }
  157. struct prefix_track
  158. {
  159. rt_list_t list;
  160. int uid;
  161. const char *prefix;
  162. };
  163. static RT_DEFINE_SPINLOCK(_prefix_nodes_lock);
  164. static rt_list_t _prefix_nodes = RT_LIST_OBJECT_INIT(_prefix_nodes);
  165. int rt_dm_dev_set_name_auto(rt_device_t dev, const char *prefix)
  166. {
  167. int uid = -1;
  168. struct prefix_track *pt = RT_NULL;
  169. RT_ASSERT(dev != RT_NULL);
  170. RT_ASSERT(prefix != RT_NULL);
  171. RT_DEBUG_NOT_IN_INTERRUPT;
  172. rt_spin_lock(&_prefix_nodes_lock);
  173. rt_list_for_each_entry(pt, &_prefix_nodes, list)
  174. {
  175. /* caller always input constants string, check ptr is faster */
  176. if (pt->prefix == prefix || !rt_strcmp(pt->prefix, prefix))
  177. {
  178. uid = ++pt->uid;
  179. break;
  180. }
  181. }
  182. rt_spin_unlock(&_prefix_nodes_lock);
  183. if (uid < 0)
  184. {
  185. pt = rt_malloc(sizeof(*pt));
  186. if (!pt)
  187. {
  188. return -RT_ENOMEM;
  189. }
  190. rt_list_init(&pt->list);
  191. pt->uid = uid = 0;
  192. pt->prefix = prefix;
  193. rt_spin_lock(&_prefix_nodes_lock);
  194. rt_list_insert_before(&_prefix_nodes, &pt->list);
  195. rt_spin_unlock(&_prefix_nodes_lock);
  196. }
  197. return rt_dm_dev_set_name(dev, "%s%u", prefix, uid);
  198. }
  199. int rt_dm_dev_get_name_id(rt_device_t dev)
  200. {
  201. int id = 0, len;
  202. const char *name;
  203. RT_ASSERT(dev != RT_NULL);
  204. name = rt_dm_dev_get_name(dev);
  205. len = rt_strlen(name) - 1;
  206. name += len;
  207. while (len --> 0)
  208. {
  209. if (*name < '0' || *name > '9')
  210. {
  211. while (*(++name))
  212. {
  213. id *= 10;
  214. id += *name - '0';
  215. }
  216. break;
  217. }
  218. --name;
  219. }
  220. return id;
  221. }
  222. int rt_dm_dev_set_name(rt_device_t dev, const char *format, ...)
  223. {
  224. int n;
  225. va_list arg_ptr;
  226. RT_ASSERT(dev != RT_NULL);
  227. RT_ASSERT(format != RT_NULL);
  228. va_start(arg_ptr, format);
  229. n = rt_vsnprintf(dev->parent.name, RT_NAME_MAX, format, arg_ptr);
  230. va_end(arg_ptr);
  231. return n;
  232. }
  233. const char *rt_dm_dev_get_name(rt_device_t dev)
  234. {
  235. RT_ASSERT(dev != RT_NULL);
  236. return dev->parent.name;
  237. }
  238. #ifdef RT_USING_OFW
  239. #define ofw_api_call(name, ...) rt_ofw_##name(__VA_ARGS__)
  240. #define ofw_api_call_ptr(name, ...) ofw_api_call(name, __VA_ARGS__)
  241. #else
  242. #define ofw_api_call(name, ...) (-RT_ENOSYS)
  243. #define ofw_api_call_ptr(name, ...) RT_NULL
  244. #endif
  245. rt_bool_t rt_dm_dev_is_big_endian(rt_device_t dev)
  246. {
  247. if (rt_dm_dev_prop_read_bool(dev, "big-endian"))
  248. {
  249. return RT_TRUE;
  250. }
  251. #ifdef ARCH_CPU_BIG_ENDIAN
  252. if (rt_dm_dev_prop_read_bool(dev, "native-endian"))
  253. {
  254. return RT_TRUE;
  255. }
  256. #endif /* ARCH_CPU_BIG_ENDIAN */
  257. return RT_FALSE;
  258. }
  259. int rt_dm_dev_get_address_count(rt_device_t dev)
  260. {
  261. RT_ASSERT(dev != RT_NULL);
  262. #ifdef RT_USING_OFW
  263. if (dev->ofw_node)
  264. {
  265. return ofw_api_call(get_address_count, dev->ofw_node);
  266. }
  267. #endif
  268. return -RT_ENOSYS;
  269. }
  270. rt_err_t rt_dm_dev_get_address(rt_device_t dev, int index,
  271. rt_uint64_t *out_address, rt_uint64_t *out_size)
  272. {
  273. RT_ASSERT(dev != RT_NULL);
  274. #ifdef RT_USING_OFW
  275. if (dev->ofw_node)
  276. {
  277. return ofw_api_call(get_address, dev->ofw_node, index,
  278. out_address, out_size);
  279. }
  280. #endif
  281. return -RT_ENOSYS;
  282. }
  283. rt_err_t rt_dm_dev_get_address_by_name(rt_device_t dev, const char *name,
  284. rt_uint64_t *out_address, rt_uint64_t *out_size)
  285. {
  286. RT_ASSERT(dev != RT_NULL);
  287. #ifdef RT_USING_OFW
  288. if (dev->ofw_node)
  289. {
  290. return ofw_api_call(get_address_by_name, dev->ofw_node, name,
  291. out_address, out_size);
  292. }
  293. #endif
  294. return -RT_ENOSYS;
  295. }
  296. int rt_dm_dev_get_address_array(rt_device_t dev, int nr, rt_uint64_t *out_regs)
  297. {
  298. RT_ASSERT(dev != RT_NULL);
  299. #ifdef RT_USING_OFW
  300. if (dev->ofw_node)
  301. {
  302. return ofw_api_call(get_address_array, dev->ofw_node, nr, out_regs);
  303. }
  304. #endif
  305. return -RT_ENOSYS;
  306. }
  307. void *rt_dm_dev_iomap(rt_device_t dev, int index)
  308. {
  309. RT_ASSERT(dev != RT_NULL);
  310. #ifdef RT_USING_OFW
  311. if (dev->ofw_node)
  312. {
  313. return ofw_api_call_ptr(iomap, dev->ofw_node, index);
  314. }
  315. #endif
  316. return RT_NULL;
  317. }
  318. void *rt_dm_dev_iomap_by_name(rt_device_t dev, const char *name)
  319. {
  320. RT_ASSERT(dev != RT_NULL);
  321. #ifdef RT_USING_OFW
  322. if (dev->ofw_node)
  323. {
  324. return ofw_api_call_ptr(iomap_by_name, dev->ofw_node, name);
  325. }
  326. #endif
  327. return RT_NULL;
  328. }
  329. int rt_dm_dev_get_irq_count(rt_device_t dev)
  330. {
  331. RT_ASSERT(dev != RT_NULL);
  332. #if defined(RT_USING_OFW) && defined(RT_USING_PIC)
  333. if (dev->ofw_node)
  334. {
  335. return ofw_api_call(get_irq_count, dev->ofw_node);
  336. }
  337. #endif
  338. return -RT_ENOSYS;
  339. }
  340. int rt_dm_dev_get_irq(rt_device_t dev, int index)
  341. {
  342. RT_ASSERT(dev != RT_NULL);
  343. #if defined(RT_USING_OFW) && defined(RT_USING_PIC)
  344. if (dev->ofw_node)
  345. {
  346. return ofw_api_call(get_irq, dev->ofw_node, index);
  347. }
  348. #endif
  349. return -RT_ENOSYS;
  350. }
  351. int rt_dm_dev_get_irq_by_name(rt_device_t dev, const char *name)
  352. {
  353. RT_ASSERT(dev != RT_NULL);
  354. #if defined(RT_USING_OFW) && defined(RT_USING_PIC)
  355. if (dev->ofw_node)
  356. {
  357. return ofw_api_call(get_irq_by_name, dev->ofw_node, name);
  358. }
  359. #endif
  360. return -RT_ENOSYS;
  361. }
  362. void rt_dm_dev_bind_fwdata(rt_device_t dev, void *fw_np, void *data)
  363. {
  364. RT_ASSERT(dev != RT_NULL);
  365. #ifdef RT_USING_OFW
  366. if (!dev->ofw_node && fw_np)
  367. {
  368. dev->ofw_node = fw_np;
  369. rt_ofw_data(fw_np) = data;
  370. }
  371. if (dev->ofw_node == RT_NULL)
  372. {
  373. LOG_D("[%s:%s] line=%d ofw_node is NULL", __FILE__, __func__, __LINE__);
  374. return;
  375. }
  376. rt_ofw_data(dev->ofw_node) = data;
  377. #endif
  378. }
  379. void rt_dm_dev_unbind_fwdata(rt_device_t dev, void *fw_np)
  380. {
  381. RT_ASSERT(dev!= RT_NULL);
  382. #ifdef RT_USING_OFW
  383. void *dev_fw_np = RT_NULL;
  384. if (!dev->ofw_node && fw_np)
  385. {
  386. dev_fw_np = fw_np;
  387. rt_ofw_data(fw_np) = RT_NULL;
  388. }
  389. if (dev_fw_np == RT_NULL)
  390. {
  391. LOG_D("[%s:%s] line=%d dev_fw_np is NULL", __FILE__, __func__, __LINE__);
  392. return;
  393. }
  394. rt_ofw_data(dev_fw_np) = RT_NULL;
  395. #endif
  396. }
  397. const char *rt_dm_dev_get_prop_fuzzy_name(rt_device_t dev, const char *name)
  398. {
  399. RT_ASSERT(dev != RT_NULL);
  400. #ifdef RT_USING_OFW
  401. if (dev->ofw_node)
  402. {
  403. return ofw_api_call_ptr(get_prop_fuzzy_name, dev->ofw_node, name);
  404. }
  405. #endif
  406. return RT_NULL;
  407. }
  408. int rt_dm_dev_prop_read_u8_array_index(rt_device_t dev, const char *propname,
  409. int index, int nr, rt_uint8_t *out_values)
  410. {
  411. RT_ASSERT(dev != RT_NULL);
  412. #ifdef RT_USING_OFW
  413. if (dev->ofw_node)
  414. {
  415. return ofw_api_call(prop_read_u8_array_index, dev->ofw_node, propname,
  416. index, nr, out_values);
  417. }
  418. #endif
  419. return -RT_ENOSYS;
  420. }
  421. int rt_dm_dev_prop_read_u16_array_index(rt_device_t dev, const char *propname,
  422. int index, int nr, rt_uint16_t *out_values)
  423. {
  424. RT_ASSERT(dev != RT_NULL);
  425. #ifdef RT_USING_OFW
  426. if (dev->ofw_node)
  427. {
  428. return ofw_api_call(prop_read_u16_array_index, dev->ofw_node, propname,
  429. index, nr, out_values);
  430. }
  431. #endif
  432. return -RT_ENOSYS;
  433. }
  434. int rt_dm_dev_prop_read_u32_array_index(rt_device_t dev, const char *propname,
  435. int index, int nr, rt_uint32_t *out_values)
  436. {
  437. RT_ASSERT(dev != RT_NULL);
  438. #ifdef RT_USING_OFW
  439. if (dev->ofw_node)
  440. {
  441. return ofw_api_call(prop_read_u32_array_index, dev->ofw_node, propname,
  442. index, nr, out_values);
  443. }
  444. #endif
  445. return -RT_ENOSYS;
  446. }
  447. int rt_dm_dev_prop_read_u64_array_index(rt_device_t dev, const char *propname,
  448. int index, int nr, rt_uint64_t *out_values)
  449. {
  450. RT_ASSERT(dev != RT_NULL);
  451. #ifdef RT_USING_OFW
  452. if (dev->ofw_node)
  453. {
  454. return ofw_api_call(prop_read_u64_array_index, dev->ofw_node, propname,
  455. index, nr, out_values);
  456. }
  457. #endif
  458. return -RT_ENOSYS;
  459. }
  460. int rt_dm_dev_prop_read_string_array_index(rt_device_t dev, const char *propname,
  461. int index, int nr, const char **out_strings)
  462. {
  463. RT_ASSERT(dev != RT_NULL);
  464. #ifdef RT_USING_OFW
  465. if (dev->ofw_node)
  466. {
  467. return ofw_api_call(prop_read_string_array_index, dev->ofw_node, propname,
  468. index, nr, out_strings);
  469. }
  470. #endif
  471. return -RT_ENOSYS;
  472. }
  473. int rt_dm_dev_prop_count_of_size(rt_device_t dev, const char *propname, int size)
  474. {
  475. RT_ASSERT(dev != RT_NULL);
  476. #ifdef RT_USING_OFW
  477. if (dev->ofw_node)
  478. {
  479. return ofw_api_call(prop_count_of_size, dev->ofw_node, propname, size);
  480. }
  481. #endif
  482. return -RT_ENOSYS;
  483. }
  484. int rt_dm_dev_prop_index_of_string(rt_device_t dev, const char *propname, const char *string)
  485. {
  486. RT_ASSERT(dev != RT_NULL);
  487. #ifdef RT_USING_OFW
  488. if (dev->ofw_node)
  489. {
  490. return ofw_api_call(prop_index_of_string, dev->ofw_node, propname, string);
  491. }
  492. #endif
  493. return -RT_ENOSYS;
  494. }
  495. rt_bool_t rt_dm_dev_prop_read_bool(rt_device_t dev, const char *propname)
  496. {
  497. RT_ASSERT(dev != RT_NULL);
  498. #ifdef RT_USING_OFW
  499. if (dev->ofw_node)
  500. {
  501. return ofw_api_call(prop_read_bool, dev->ofw_node, propname);
  502. }
  503. #endif
  504. return RT_FALSE;
  505. }