1
0

mailbox.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-09-23 GuEe-GUI first version
  9. */
  10. #include <rthw.h>
  11. #include <rtthread.h>
  12. #define DBG_TAG "rtdm.mailbox"
  13. #define DBG_LVL DBG_INFO
  14. #include <rtdbg.h>
  15. #include <drivers/ofw.h>
  16. #include <drivers/mailbox.h>
  17. #include <drivers/platform.h>
  18. #include <drivers/core/dm.h>
  19. static RT_DEFINE_SPINLOCK(mbox_ops_lock);
  20. static rt_list_t mbox_nodes = RT_LIST_OBJECT_INIT(mbox_nodes);
  21. static void mbox_chan_timeout(void *param);
  22. rt_err_t rt_mbox_controller_register(struct rt_mbox_controller *ctrl)
  23. {
  24. int len;
  25. struct rt_mbox_chan *chan;
  26. char timer_name[RT_NAME_MAX];
  27. if (!ctrl || !ctrl->dev || !ctrl->ops || !ctrl->num_chans)
  28. {
  29. return -RT_EINVAL;
  30. }
  31. ctrl->chans = rt_calloc(ctrl->num_chans, sizeof(struct rt_mbox_chan));
  32. if (!ctrl->chans)
  33. {
  34. return -RT_ENOMEM;
  35. }
  36. len = rt_snprintf(timer_name, sizeof(timer_name), "%s-",
  37. rt_dm_dev_get_name(ctrl->dev));
  38. RT_ASSERT(len < sizeof(timer_name));
  39. chan = &ctrl->chans[0];
  40. for (int i = 0; i < ctrl->num_chans; ++i, ++chan)
  41. {
  42. chan->ctrl = ctrl;
  43. rt_spin_lock_init(&chan->lock);
  44. rt_snprintf(&timer_name[len], sizeof(timer_name) - len, "%d", i);
  45. rt_timer_init(&chan->timer, timer_name, mbox_chan_timeout, chan,
  46. 0, RT_TIMER_FLAG_ONE_SHOT);
  47. }
  48. rt_list_init(&ctrl->list);
  49. rt_dm_dev_bind_fwdata(ctrl->dev, RT_NULL, ctrl);
  50. rt_spin_lock(&mbox_ops_lock);
  51. rt_list_insert_after(&mbox_nodes, &ctrl->list);
  52. rt_spin_unlock(&mbox_ops_lock);
  53. return RT_EOK;
  54. }
  55. rt_err_t rt_mbox_controller_unregister(struct rt_mbox_controller *ctrl)
  56. {
  57. struct rt_mbox_chan *chan;
  58. if (!ctrl)
  59. {
  60. return -RT_EINVAL;
  61. }
  62. rt_spin_lock(&mbox_ops_lock);
  63. rt_dm_dev_unbind_fwdata(ctrl->dev, RT_NULL);
  64. rt_list_remove(&ctrl->list);
  65. rt_spin_unlock(&mbox_ops_lock);
  66. chan = &ctrl->chans[0];
  67. for (int i = ctrl->num_chans - 1; i >= 0; --i, ++chan)
  68. {
  69. rt_mbox_release(&ctrl->chans[i]);
  70. }
  71. rt_free(ctrl->chans);
  72. return RT_EOK;
  73. }
  74. rt_err_t rt_mbox_send(struct rt_mbox_chan *chan, const void *data,
  75. rt_uint32_t timeout_ms)
  76. {
  77. rt_err_t err;
  78. rt_ubase_t level;
  79. rt_bool_t timer_go = RT_FALSE;
  80. struct rt_mbox_client *client;
  81. struct rt_mbox_controller *ctrl;
  82. if (!chan || !data)
  83. {
  84. return -RT_EINVAL;
  85. }
  86. ctrl = chan->ctrl;
  87. client = chan->client;
  88. level = rt_spin_lock_irqsave(&chan->lock);
  89. if (client->tx_prepare)
  90. {
  91. client->tx_prepare(client, data);
  92. }
  93. chan->complete = RT_FALSE;
  94. err = ctrl->ops->send(chan, data);
  95. if (!err)
  96. {
  97. chan->data = (void *)data;
  98. if (timeout_ms != RT_WAITING_FOREVER)
  99. {
  100. rt_tick_t tick = rt_tick_from_millisecond(timeout_ms);
  101. rt_timer_control(&chan->timer, RT_TIMER_CTRL_SET_TIME, &tick);
  102. timer_go = RT_TRUE;
  103. }
  104. }
  105. else
  106. {
  107. chan->complete = RT_TRUE;
  108. }
  109. rt_spin_unlock_irqrestore(&chan->lock, level);
  110. if (timer_go)
  111. {
  112. rt_timer_start(&chan->timer);
  113. }
  114. return err;
  115. }
  116. void rt_mbox_send_done(struct rt_mbox_chan *chan, rt_err_t err)
  117. {
  118. void *data;
  119. rt_ubase_t level;
  120. level = rt_spin_lock_irqsave(&chan->lock);
  121. data = chan->data;
  122. chan->data = RT_NULL;
  123. rt_spin_unlock_irqrestore(&chan->lock, level);
  124. if (chan->client->tx_done)
  125. {
  126. chan->client->tx_done(chan->client, data, err);
  127. }
  128. chan->complete = RT_TRUE;
  129. }
  130. static void mbox_chan_timeout(void *param)
  131. {
  132. rt_err_t err = RT_EOK;
  133. struct rt_mbox_chan *chan = param;
  134. if (!chan->complete)
  135. {
  136. err = -RT_ETIMEOUT;
  137. }
  138. rt_mbox_send_done(chan, err);
  139. }
  140. rt_bool_t rt_mbox_peek(struct rt_mbox_chan *chan)
  141. {
  142. if (chan && chan->ctrl->ops->peek)
  143. {
  144. return chan->ctrl->ops->peek(chan);
  145. }
  146. return RT_FALSE;
  147. }
  148. rt_err_t rt_mbox_recv(struct rt_mbox_chan *chan, void *data)
  149. {
  150. if (!chan || !data)
  151. {
  152. return -RT_EINVAL;
  153. }
  154. if (chan->client->rx_callback)
  155. {
  156. chan->client->rx_callback(chan->client, data);
  157. }
  158. return RT_EOK;
  159. }
  160. static int mbox_controller_ofw_parse_default(struct rt_mbox_controller *ctrl,
  161. struct rt_ofw_cell_args *args)
  162. {
  163. if (args->args_count != 1)
  164. {
  165. return -RT_EINVAL;
  166. }
  167. return args->args[0];
  168. }
  169. struct rt_mbox_chan *rt_mbox_request_by_index(struct rt_mbox_client *client, int index)
  170. {
  171. rt_err_t err;
  172. struct rt_ofw_cell_args args;
  173. struct rt_ofw_node *np, *ctrl_np;
  174. struct rt_mbox_controller *ctrl;
  175. struct rt_mbox_chan *chan = RT_NULL;
  176. if (!client && index < 0)
  177. {
  178. return rt_err_ptr(-RT_EINVAL);
  179. }
  180. np = client->dev->ofw_node;
  181. rt_spin_lock(&mbox_ops_lock);
  182. err = rt_ofw_parse_phandle_cells(np, "mboxes", "#mbox-cells", index, &args);
  183. if (err)
  184. {
  185. chan = rt_err_ptr(err);
  186. goto _out_lock;
  187. }
  188. ctrl_np = args.data;
  189. if (!rt_ofw_data(ctrl_np))
  190. {
  191. rt_spin_unlock(&mbox_ops_lock);
  192. rt_platform_ofw_request(ctrl_np);
  193. rt_spin_lock(&mbox_ops_lock);
  194. }
  195. ctrl = rt_ofw_data(ctrl_np);
  196. rt_ofw_node_put(ctrl_np);
  197. if (ctrl)
  198. {
  199. int index;
  200. if (ctrl->ops->ofw_parse)
  201. {
  202. index = ctrl->ops->ofw_parse(ctrl, &args);
  203. }
  204. else
  205. {
  206. index = mbox_controller_ofw_parse_default(ctrl, &args);
  207. }
  208. if (index >= 0)
  209. {
  210. chan = &ctrl->chans[index];
  211. }
  212. else
  213. {
  214. LOG_E("Parse chan from %s error = %s",
  215. rt_dm_dev_get_name(ctrl->dev), rt_strerror(index));
  216. chan = rt_err_ptr(index);
  217. goto _out_lock;
  218. }
  219. if (ctrl->ops->request)
  220. {
  221. rt_err_t err = ctrl->ops->request(chan);
  222. if (err)
  223. {
  224. LOG_E("Request chan[%d] from %s error = %s",
  225. index, rt_dm_dev_get_name(ctrl->dev), rt_strerror(err));
  226. rt_mbox_release(chan);
  227. chan = rt_err_ptr(err);
  228. }
  229. }
  230. chan->client = client;
  231. }
  232. else
  233. {
  234. chan = rt_err_ptr(-RT_ENOSYS);
  235. }
  236. _out_lock:
  237. rt_spin_unlock(&mbox_ops_lock);
  238. return chan;
  239. }
  240. struct rt_mbox_chan *rt_mbox_request_by_name(struct rt_mbox_client *client, char *name)
  241. {
  242. int index;
  243. struct rt_ofw_node *np;
  244. if (!client || !name)
  245. {
  246. return rt_err_ptr(-RT_EINVAL);
  247. }
  248. np = client->dev->ofw_node;
  249. index = rt_ofw_prop_index_of_string(np, "mbox-names", name);
  250. if (index < 0)
  251. {
  252. return RT_NULL;
  253. }
  254. return rt_mbox_request_by_index(client, index);
  255. }
  256. rt_err_t rt_mbox_release(struct rt_mbox_chan *chan)
  257. {
  258. if (chan)
  259. {
  260. chan->ctrl->ops->release(chan);
  261. }
  262. else
  263. {
  264. return -RT_EINVAL;
  265. }
  266. return RT_EOK;
  267. }