platform_ofw.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  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-06-04 GuEe-GUI the first version
  9. */
  10. #include <rtthread.h>
  11. #define DBG_TAG "drv.platform"
  12. #define DBG_LVL DBG_INFO
  13. #include <rtdbg.h>
  14. #include <drivers/ofw_io.h>
  15. #include <drivers/ofw_fdt.h>
  16. #include <drivers/platform.h>
  17. #include <drivers/core/dm.h>
  18. #include "../ofw/ofw_internal.h"
  19. static const struct rt_ofw_node_id platform_ofw_ids[] =
  20. {
  21. { .compatible = "simple-bus", },
  22. #ifdef RT_USING_MFD
  23. { .compatible = "simple-mfd", },
  24. #endif
  25. #ifdef RT_USING_ISA
  26. { .compatible = "isa", },
  27. #endif
  28. #ifdef RT_USING_AMBA_BUS
  29. /*
  30. * Maybe ARM has replaced it with compatible: "arm,primecell" and will not
  31. * used anymore in the future.
  32. */
  33. { .compatible = "arm,amba-bus", },
  34. #endif
  35. { /* sentinel */ }
  36. };
  37. static void ofw_device_rename(struct rt_device *dev)
  38. {
  39. rt_uint32_t mask;
  40. rt_uint64_t addr;
  41. const char *dev_name = dev->parent.name;
  42. struct rt_ofw_node *np = dev->ofw_node;
  43. #if RT_NAME_MAX > 0
  44. if (dev_name[0] == '\0')
  45. {
  46. dev_name = RT_NULL;
  47. }
  48. #endif
  49. while (np->parent)
  50. {
  51. if (!rt_ofw_get_address(np, 0, &addr, RT_NULL))
  52. {
  53. const char *node_name = rt_fdt_node_name(np->full_name);
  54. rt_size_t tag_len = strchrnul(node_name, '@') - node_name;
  55. if (!rt_ofw_prop_read_u32(np, "mask", &mask))
  56. {
  57. rt_dm_dev_set_name(dev, dev_name ? "%lx.%x.%.*s:%s" : "%lx.%x.%.*s",
  58. addr, __rt_ffs(mask) - 1, tag_len, node_name, dev_name);
  59. }
  60. else
  61. {
  62. rt_dm_dev_set_name(dev, dev_name ? "%lx.%.*s:%s" : "%lx.%.*s",
  63. addr, tag_len, node_name, dev_name);
  64. }
  65. return;
  66. }
  67. rt_dm_dev_set_name(dev, dev_name ? "%s:%s" : "%s",
  68. rt_fdt_node_name(np->full_name), dev_name);
  69. np = np->parent;
  70. }
  71. }
  72. static struct rt_platform_device *alloc_ofw_platform_device(struct rt_ofw_node *np)
  73. {
  74. struct rt_platform_device *pdev = rt_platform_device_alloc("");
  75. if (pdev)
  76. {
  77. /* inc reference of dt-node */
  78. rt_ofw_node_get(np);
  79. rt_ofw_node_set_flag(np, RT_OFW_F_PLATFORM);
  80. pdev->parent.ofw_node = np;
  81. ofw_device_rename(&pdev->parent);
  82. }
  83. else
  84. {
  85. LOG_E("Alloc device fail for %s", rt_ofw_node_full_name(np));
  86. }
  87. return pdev;
  88. }
  89. static rt_err_t platform_ofw_device_probe_once(struct rt_ofw_node *parent_np)
  90. {
  91. rt_err_t err = RT_EOK;
  92. struct rt_ofw_node *np;
  93. struct rt_platform_device *pdev;
  94. rt_ofw_foreach_available_child_node(parent_np, np)
  95. {
  96. const char *name;
  97. struct rt_ofw_node_id *id;
  98. struct rt_ofw_prop *compat_prop = RT_NULL;
  99. LOG_D("%s found in %s", np->full_name, parent_np->full_name);
  100. /* Is system node or have driver */
  101. if (rt_ofw_node_test_flag(np, RT_OFW_F_SYSTEM) ||
  102. rt_ofw_node_test_flag(np, RT_OFW_F_READLY))
  103. {
  104. continue;
  105. }
  106. compat_prop = rt_ofw_get_prop(np, "compatible", RT_NULL);
  107. name = rt_ofw_node_name(np);
  108. /* Not have name and compatible */
  109. if (!compat_prop && (name == (const char *)"<NULL>" || !rt_strcmp(name, "<NULL>")))
  110. {
  111. continue;
  112. }
  113. id = rt_ofw_prop_match(compat_prop, platform_ofw_ids);
  114. if (id && np->child)
  115. {
  116. /* scan next level */
  117. err = platform_ofw_device_probe_once(np);
  118. if (err)
  119. {
  120. rt_ofw_node_put(np);
  121. LOG_E("%s bus probe fail", np->full_name);
  122. break;
  123. }
  124. }
  125. pdev = alloc_ofw_platform_device(np);
  126. if (!pdev)
  127. {
  128. rt_ofw_node_put(np);
  129. err = -RT_ENOMEM;
  130. break;
  131. }
  132. pdev->dev_id = ofw_alias_node_id(np);
  133. LOG_D("%s register to bus", np->full_name);
  134. rt_platform_device_register(pdev);
  135. }
  136. return err;
  137. }
  138. rt_err_t rt_platform_ofw_device_probe_child(struct rt_ofw_node *np)
  139. {
  140. rt_err_t err;
  141. struct rt_ofw_node *parent = rt_ofw_get_parent(np);
  142. if (parent && rt_strcmp(parent->name, "/") &&
  143. rt_ofw_get_prop(np, "compatible", RT_NULL) &&
  144. !rt_ofw_node_test_flag(np, RT_OFW_F_PLATFORM))
  145. {
  146. struct rt_platform_device *pdev = alloc_ofw_platform_device(np);
  147. if (pdev)
  148. {
  149. err = rt_platform_device_register(pdev);
  150. }
  151. else
  152. {
  153. err = -RT_ENOMEM;
  154. }
  155. }
  156. else
  157. {
  158. err = -RT_EINVAL;
  159. }
  160. rt_ofw_node_put(parent);
  161. return err;
  162. }
  163. static int platform_ofw_device_probe(void)
  164. {
  165. rt_err_t err = RT_EOK;
  166. struct rt_ofw_node *node;
  167. if (ofw_node_root)
  168. {
  169. rt_ofw_node_get(ofw_node_root);
  170. err = platform_ofw_device_probe_once(ofw_node_root);
  171. rt_ofw_node_put(ofw_node_root);
  172. if ((node = rt_ofw_find_node_by_path("/firmware")))
  173. {
  174. platform_ofw_device_probe_once(node);
  175. rt_ofw_node_put(node);
  176. }
  177. rt_ofw_node_get(ofw_node_chosen);
  178. if ((node = rt_ofw_get_child_by_compatible(ofw_node_chosen, "simple-framebuffer")))
  179. {
  180. platform_ofw_device_probe_once(node);
  181. rt_ofw_node_put(node);
  182. }
  183. rt_ofw_node_get(ofw_node_chosen);
  184. }
  185. else
  186. {
  187. err = -RT_ENOSYS;
  188. }
  189. return (int)err;
  190. }
  191. INIT_PLATFORM_EXPORT(platform_ofw_device_probe);
  192. rt_err_t rt_platform_ofw_free(struct rt_platform_device *pdev)
  193. {
  194. rt_err_t err = RT_EOK;
  195. if (pdev)
  196. {
  197. struct rt_ofw_node *np = pdev->parent.ofw_node;
  198. if (np)
  199. {
  200. rt_ofw_node_clear_flag(np, RT_OFW_F_PLATFORM);
  201. rt_ofw_node_put(np);
  202. pdev->parent.ofw_node = RT_NULL;
  203. }
  204. }
  205. else
  206. {
  207. err = -RT_EINVAL;
  208. }
  209. return err;
  210. }