mailbox-rockchip.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  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 <rtthread.h>
  11. #include <rtdevice.h>
  12. #define DBG_TAG "mailbox.rockchip"
  13. #define DBG_LVL DBG_INFO
  14. #include <rtdbg.h>
  15. #define MAILBOX_A2B_INTEN 0x00
  16. #define MAILBOX_A2B_STATUS 0x04
  17. #define MAILBOX_A2B_CMD(x) (0x08 + (x) * 8)
  18. #define MAILBOX_A2B_DAT(x) (0x0c + (x) * 8)
  19. #define MAILBOX_B2A_INTEN 0x28
  20. #define MAILBOX_B2A_STATUS 0x2C
  21. #define MAILBOX_B2A_CMD(x) (0x30 + (x) * 8)
  22. #define MAILBOX_B2A_DAT(x) (0x34 + (x) * 8)
  23. #define MAILBOX_V2_A2B_INTEN MAILBOX_A2B_INTEN
  24. #define MAILBOX_V2_A2B_STATUS MAILBOX_A2B_STATUS
  25. #define MAILBOX_V2_A2B_CMD 0x08
  26. #define MAILBOX_V2_A2B_DAT 0x0c
  27. #define MAILBOX_V2_B2A_INTEN 0x10
  28. #define MAILBOX_V2_B2A_STATUS 0x14
  29. #define MAILBOX_V2_B2A_CMD 0x18
  30. #define MAILBOX_V2_B2A_DAT 0x1c
  31. #define MAILBOX_V2_TRIGGER_SHIFT 8
  32. #define MAILBOX_V2_TRIGGER_MASK RT_BIT(8)
  33. #define MAILBOX_V2_INTEN_TX_DONE RT_BIT(0)
  34. #define MAILBOX_V2_INTEN_RX_DONE RT_BIT(1)
  35. #define MAILBOX_V2_INTEN_RX_DONE_SHIFT 1
  36. #define MAILBOX_V2_STATUS_TX_DONE RT_BIT(0)
  37. #define MAILBOX_V2_STATUS_RX_DONE RT_BIT(1)
  38. #define MAILBOX_V2_STATUS_MASK RT_GENMASK(1, 0)
  39. #define MAILBOX_POLLING_MS 5 /* default polling interval 5ms */
  40. #define BIT_WRITEABLE_SHIFT 16
  41. struct rockchip_mbox;
  42. struct rockchip_mbox_reg
  43. {
  44. rt_uint32_t tx_int;
  45. rt_uint32_t tx_sts;
  46. rt_uint32_t tx_cmd;
  47. rt_uint32_t tx_dat;
  48. rt_uint32_t rx_int;
  49. rt_uint32_t rx_sts;
  50. rt_uint32_t rx_cmd;
  51. rt_uint32_t rx_dat;
  52. };
  53. struct rockchip_mbox_msg
  54. {
  55. rt_uint32_t cmd;
  56. rt_uint32_t data;
  57. };
  58. struct rockchip_mbox_soc_data
  59. {
  60. int num_chans;
  61. struct rockchip_mbox_reg reg_a2b;
  62. struct rockchip_mbox_reg reg_b2a;
  63. const struct rt_mbox_controller_ops *ops;
  64. void (*isr)(int irqno, void *param);
  65. void (*thread_isr)(void *param);
  66. };
  67. struct rockchip_mbox_chan
  68. {
  69. int idx;
  70. int irq;
  71. struct rockchip_mbox_msg *msg;
  72. struct rockchip_mbox *rk_mbox;
  73. };
  74. struct rockchip_mbox
  75. {
  76. struct rt_mbox_controller parent;
  77. void *regs;
  78. struct rt_clk *pclk;
  79. struct rt_thread *irq_thread;
  80. const struct rockchip_mbox_reg *reg;
  81. rt_uint32_t buf_size;
  82. rt_bool_t txdone_irq;
  83. rt_bool_t trigger_method;
  84. struct rockchip_mbox_chan chans[];
  85. };
  86. #define raw_to_rockchip_mbox(raw) rt_container_of(raw, struct rockchip_mbox, parent)
  87. rt_inline rt_uint32_t rockchip_mbox_readl(struct rockchip_mbox *rk_mbox, int offset)
  88. {
  89. return HWREG32(rk_mbox->regs + offset);
  90. }
  91. rt_inline void rockchip_mbox_writel(struct rockchip_mbox *rk_mbox, int offset,
  92. rt_uint32_t value)
  93. {
  94. HWREG32(rk_mbox->regs + offset) = value;
  95. }
  96. static rt_err_t rockchip_mbox_request(struct rt_mbox_chan *chan)
  97. {
  98. int idx;
  99. rt_uint32_t value;
  100. struct rockchip_mbox *rk_mbox = raw_to_rockchip_mbox(chan->ctrl);
  101. idx = chan - rk_mbox->parent.chans;
  102. /* Enable the corresponding B2A interrupts */
  103. value = rockchip_mbox_readl(rk_mbox, MAILBOX_B2A_INTEN);
  104. value |= RT_BIT(idx);
  105. rockchip_mbox_writel(rk_mbox, MAILBOX_B2A_INTEN, value);
  106. return RT_EOK;
  107. }
  108. static void rockchip_mbox_release(struct rt_mbox_chan *chan)
  109. {
  110. int idx;
  111. rt_uint32_t value;
  112. struct rockchip_mbox *rk_mbox = raw_to_rockchip_mbox(chan->ctrl);
  113. idx = chan - rk_mbox->parent.chans;
  114. /* Disable the corresponding B2A interrupts */
  115. value = rockchip_mbox_readl(rk_mbox, MAILBOX_B2A_INTEN);
  116. value &= ~RT_BIT(idx);
  117. rockchip_mbox_writel(rk_mbox, MAILBOX_B2A_INTEN, value);
  118. rk_mbox->chans[idx].msg = RT_NULL;
  119. }
  120. static rt_err_t rockchip_mbox_send(struct rt_mbox_chan *chan, const void *data)
  121. {
  122. int idx;
  123. struct rockchip_mbox_msg *msg = (void *)data;
  124. struct rockchip_mbox *rk_mbox = raw_to_rockchip_mbox(chan->ctrl);
  125. idx = chan - rk_mbox->parent.chans;
  126. if (rockchip_mbox_readl(rk_mbox, MAILBOX_A2B_STATUS) & RT_BIT(idx))
  127. {
  128. LOG_E("The mailbox channel(%d) is busy", idx);
  129. return -RT_EBUSY;
  130. }
  131. rk_mbox->chans[idx].msg = msg;
  132. rockchip_mbox_writel(rk_mbox, MAILBOX_A2B_CMD(idx), msg->cmd);
  133. rockchip_mbox_writel(rk_mbox, MAILBOX_A2B_DAT(idx), msg->data);
  134. return RT_EOK;
  135. }
  136. static const struct rt_mbox_controller_ops rockchip_mbox_ops =
  137. {
  138. .request = rockchip_mbox_request,
  139. .release = rockchip_mbox_release,
  140. .send = rockchip_mbox_send,
  141. };
  142. static void rockchip_mbox_thread_isr(void *param)
  143. {
  144. struct rockchip_mbox_msg *msg;
  145. struct rockchip_mbox *rk_mbox = param;
  146. while (RT_TRUE)
  147. {
  148. rt_thread_suspend(rk_mbox->irq_thread);
  149. rt_schedule();
  150. for (int idx = 0; idx < rk_mbox->parent.num_chans; ++idx)
  151. {
  152. msg = rk_mbox->chans[idx].msg;
  153. if (!msg)
  154. {
  155. LOG_E("Chan[%d]: B2A message is NULL", idx);
  156. break;
  157. }
  158. rt_mbox_recv(&rk_mbox->parent.chans[idx], msg);
  159. rk_mbox->chans[idx].msg = RT_NULL;
  160. }
  161. }
  162. }
  163. static void rockchip_mbox_isr(int irqno, void *param)
  164. {
  165. rt_uint32_t status;
  166. struct rockchip_mbox_msg *msg;
  167. struct rockchip_mbox *rk_mbox = param;
  168. status = rockchip_mbox_readl(rk_mbox, MAILBOX_B2A_STATUS);
  169. for (int idx = 0; idx < rk_mbox->parent.num_chans; ++idx)
  170. {
  171. if ((status & RT_BIT(idx)) && (irqno == rk_mbox->chans[idx].irq))
  172. {
  173. msg = rk_mbox->chans[idx].msg;
  174. msg->cmd = rockchip_mbox_readl(rk_mbox, MAILBOX_B2A_CMD(idx));
  175. msg->data = rockchip_mbox_readl(rk_mbox, MAILBOX_B2A_DAT(idx));
  176. /* Clear mbox interrupt */
  177. rockchip_mbox_writel(rk_mbox, MAILBOX_B2A_STATUS, RT_BIT(idx));
  178. rt_thread_resume(rk_mbox->irq_thread);
  179. break;
  180. }
  181. }
  182. }
  183. static rt_err_t rockchip_mbox_v2_request(struct rt_mbox_chan *chan)
  184. {
  185. struct rockchip_mbox *rk_mbox = raw_to_rockchip_mbox(chan->ctrl);
  186. /* Set the TX interrupt trigger method */
  187. rockchip_mbox_writel(rk_mbox, rk_mbox->reg->tx_int,
  188. (1U << (BIT_WRITEABLE_SHIFT + MAILBOX_V2_TRIGGER_SHIFT) |
  189. rk_mbox->trigger_method << MAILBOX_V2_TRIGGER_SHIFT));
  190. /* Enable the tx_done interrupt */
  191. rockchip_mbox_writel(rk_mbox, rk_mbox->reg->rx_int,
  192. (1U << BIT_WRITEABLE_SHIFT | MAILBOX_V2_INTEN_TX_DONE));
  193. /* Enable the rx_done interrupt */
  194. if (rk_mbox->txdone_irq)
  195. {
  196. rockchip_mbox_writel(rk_mbox, rk_mbox->reg->rx_int,
  197. (1U << (BIT_WRITEABLE_SHIFT + MAILBOX_V2_INTEN_RX_DONE_SHIFT) |
  198. MAILBOX_V2_INTEN_RX_DONE));
  199. }
  200. return RT_EOK;
  201. }
  202. static void rockchip_mbox_v2_release(struct rt_mbox_chan *chan)
  203. {
  204. struct rockchip_mbox *rk_mbox = raw_to_rockchip_mbox(chan->ctrl);
  205. /* Disable the tx_done interrupt */
  206. rockchip_mbox_writel(rk_mbox, rk_mbox->reg->rx_int, 1U << BIT_WRITEABLE_SHIFT);
  207. /* Disable the rx_done interrupt */
  208. if (rk_mbox->txdone_irq)
  209. {
  210. rockchip_mbox_writel(rk_mbox, rk_mbox->reg->rx_int,
  211. 1U << (BIT_WRITEABLE_SHIFT + MAILBOX_V2_INTEN_RX_DONE_SHIFT));
  212. }
  213. }
  214. static rt_err_t rockchip_mbox_v2_send(struct rt_mbox_chan *chan, const void *data)
  215. {
  216. struct rockchip_mbox_msg *msg = (void *)data;
  217. struct rockchip_mbox *rk_mbox = raw_to_rockchip_mbox(chan->ctrl);
  218. if (rockchip_mbox_readl(rk_mbox, rk_mbox->reg->tx_sts) & MAILBOX_V2_STATUS_TX_DONE)
  219. {
  220. LOG_E("The mailbox channel(%d) is busy", 0);
  221. return -RT_EBUSY;
  222. }
  223. rk_mbox->chans[0].msg = msg;
  224. if (rk_mbox->trigger_method)
  225. {
  226. rockchip_mbox_writel(rk_mbox, rk_mbox->reg->tx_cmd, msg->cmd);
  227. rockchip_mbox_writel(rk_mbox, rk_mbox->reg->tx_dat, msg->data);
  228. }
  229. else
  230. {
  231. rockchip_mbox_writel(rk_mbox, rk_mbox->reg->tx_cmd, msg->cmd);
  232. }
  233. return RT_EOK;
  234. }
  235. static const struct rt_mbox_controller_ops rockchip_mbox_v2_ops =
  236. {
  237. .request = rockchip_mbox_v2_request,
  238. .release = rockchip_mbox_v2_release,
  239. .send = rockchip_mbox_v2_send,
  240. };
  241. static void rockchip_mbox_v2_thread_isr(void *param)
  242. {
  243. struct rockchip_mbox_msg *msg;
  244. struct rockchip_mbox *rk_mbox = param;
  245. while (RT_TRUE)
  246. {
  247. rt_thread_suspend(rk_mbox->irq_thread);
  248. rt_schedule();
  249. msg = rk_mbox->chans[0].msg;
  250. if (!msg)
  251. {
  252. LOG_E("Chan[%d]: B2A message is NULL", 0);
  253. continue;
  254. }
  255. rt_mbox_recv(&rk_mbox->parent.chans[0], msg);
  256. rk_mbox->chans[0].msg = RT_NULL;
  257. }
  258. }
  259. static void rockchip_mbox_v2_isr(int irqno, void *param)
  260. {
  261. rt_uint32_t status;
  262. struct rockchip_mbox_msg *msg;
  263. struct rockchip_mbox *rk_mbox = param;
  264. status = rockchip_mbox_readl(rk_mbox, rk_mbox->reg->rx_sts);
  265. if (!(status & MAILBOX_V2_STATUS_MASK))
  266. {
  267. return;
  268. }
  269. if (status & MAILBOX_V2_STATUS_TX_DONE)
  270. {
  271. msg = rk_mbox->chans[0].msg;
  272. /* Get cmd/data from the channel */
  273. msg->cmd = rockchip_mbox_readl(rk_mbox, rk_mbox->reg->rx_cmd);
  274. msg->data = rockchip_mbox_readl(rk_mbox, rk_mbox->reg->rx_dat);
  275. /* Clear the tx_done interrupt */
  276. rockchip_mbox_writel(rk_mbox, rk_mbox->reg->rx_sts, MAILBOX_V2_STATUS_TX_DONE);
  277. rt_thread_resume(rk_mbox->irq_thread);
  278. }
  279. if (status & MAILBOX_V2_STATUS_RX_DONE)
  280. {
  281. if (rk_mbox->txdone_irq)
  282. {
  283. rt_mbox_send_done(&rk_mbox->parent.chans[0], 0);
  284. }
  285. /* Clear the rx_done interrupt */
  286. rockchip_mbox_writel(rk_mbox, rk_mbox->reg->rx_sts, MAILBOX_V2_STATUS_RX_DONE);
  287. }
  288. }
  289. static void rockchip_mbox_free_resource(struct rockchip_mbox *rk_mbox)
  290. {
  291. if (rk_mbox->regs)
  292. {
  293. rt_iounmap(rk_mbox->regs);
  294. }
  295. if (!rt_is_err_or_null(rk_mbox->pclk))
  296. {
  297. rt_clk_disable_unprepare(rk_mbox->pclk);
  298. rt_clk_put(rk_mbox->pclk);
  299. }
  300. if (rk_mbox->irq_thread)
  301. {
  302. rt_thread_delete(rk_mbox->irq_thread);
  303. }
  304. rt_free(rk_mbox);
  305. }
  306. static rt_err_t rockchip_mbox_probe(struct rt_platform_device *pdev)
  307. {
  308. rt_err_t err;
  309. char chan_name[RT_NAME_MAX];
  310. rt_uint64_t io_addr, io_size;
  311. struct rockchip_mbox *rk_mbox;
  312. struct rockchip_mbox_chan *chan;
  313. struct rt_device *dev = &pdev->parent;
  314. const struct rockchip_mbox_soc_data *soc_data = pdev->id->data;
  315. rk_mbox = rt_calloc(1, sizeof(*rk_mbox) +
  316. soc_data->num_chans * sizeof(struct rockchip_mbox_chan));
  317. if (!rk_mbox)
  318. {
  319. return -RT_ENOMEM;
  320. }
  321. if (rt_dm_dev_prop_read_bool(dev, "rockchip,tx-direction-b2a"))
  322. {
  323. rk_mbox->reg = &soc_data->reg_b2a;
  324. }
  325. else
  326. {
  327. rk_mbox->reg = &soc_data->reg_a2b;
  328. }
  329. if (rt_dm_dev_prop_read_bool(dev, "rockchip,txdone-ack"))
  330. {
  331. rk_mbox->txdone_irq = RT_FALSE;
  332. }
  333. else if (rt_dm_dev_prop_read_bool(dev, "rockchip,txdone-irq"))
  334. {
  335. rk_mbox->txdone_irq = RT_TRUE;
  336. }
  337. rk_mbox->trigger_method = !rt_dm_dev_prop_read_bool(dev, "rockchip,enable-cmd-trigger");
  338. if ((err = rt_dm_dev_get_address(dev, 0, &io_addr, &io_size)))
  339. {
  340. goto _fail;
  341. }
  342. rk_mbox->regs = rt_ioremap((void *)io_addr, (size_t)io_size);
  343. if (!rk_mbox->regs)
  344. {
  345. err = -RT_EIO;
  346. goto _fail;
  347. }
  348. rk_mbox->pclk = rt_clk_get_by_name(dev, "pclk_mailbox");
  349. if (rt_is_err(rk_mbox->pclk))
  350. {
  351. err = rt_ptr_err(rk_mbox->pclk);
  352. goto _fail;
  353. }
  354. if ((err = rt_clk_prepare_enable(rk_mbox->pclk)))
  355. {
  356. goto _fail;
  357. }
  358. rk_mbox->irq_thread = rt_thread_create("rk_mbox", soc_data->thread_isr,
  359. rk_mbox, DM_THREAD_STACK_SIZE, RT_THREAD_PRIORITY_MAX / 2, 10);
  360. if (!rk_mbox->irq_thread)
  361. {
  362. LOG_E("Create Mailbox IRQ thread fail");
  363. goto _fail;
  364. }
  365. rt_thread_startup(rk_mbox->irq_thread);
  366. chan = &rk_mbox->chans[0];
  367. for (int i = 0; i < soc_data->num_chans; ++i, ++chan)
  368. {
  369. int irq = rt_dm_dev_get_irq(dev, i);
  370. if (irq < 0)
  371. {
  372. err = irq;
  373. goto _fail;
  374. }
  375. rt_snprintf(chan_name, sizeof(chan_name), "rk_mbox-%d", i);
  376. rt_hw_interrupt_install(irq, soc_data->isr, rk_mbox, chan_name);
  377. rt_hw_interrupt_umask(irq);
  378. chan->idx = i;
  379. chan->irq = irq;
  380. chan->rk_mbox = rk_mbox;
  381. }
  382. rk_mbox->buf_size = io_size / (soc_data->num_chans * 2);
  383. dev->user_data = rk_mbox;
  384. rk_mbox->parent.dev = dev;
  385. rk_mbox->parent.num_chans = soc_data->num_chans;
  386. rk_mbox->parent.ops = soc_data->ops;
  387. if ((err = rt_mbox_controller_register(&rk_mbox->parent)))
  388. {
  389. goto _fail;
  390. }
  391. return RT_EOK;
  392. _fail:
  393. rockchip_mbox_free_resource(rk_mbox);
  394. return err;
  395. }
  396. static rt_err_t rockchip_mbox_remove(struct rt_platform_device *pdev)
  397. {
  398. struct rockchip_mbox_chan *chan;
  399. struct rockchip_mbox *rk_mbox = pdev->parent.user_data;
  400. chan = &rk_mbox->chans[0];
  401. for (int i = 0; i < rk_mbox->parent.num_chans; ++i, ++chan)
  402. {
  403. rt_hw_interrupt_mask(chan->irq);
  404. rt_pic_detach_irq(chan->irq, rk_mbox);
  405. }
  406. rt_mbox_controller_unregister(&rk_mbox->parent);
  407. rockchip_mbox_free_resource(rk_mbox);
  408. return RT_EOK;
  409. }
  410. static const struct rockchip_mbox_soc_data rk3368_data =
  411. {
  412. .num_chans = 4,
  413. .ops = &rockchip_mbox_ops,
  414. .isr = rockchip_mbox_isr,
  415. .thread_isr = rockchip_mbox_thread_isr,
  416. };
  417. static const struct rockchip_mbox_soc_data rk3576_data =
  418. {
  419. .num_chans = 1,
  420. .reg_a2b =
  421. {
  422. MAILBOX_V2_A2B_INTEN, MAILBOX_V2_A2B_STATUS,
  423. MAILBOX_V2_A2B_CMD, MAILBOX_V2_A2B_DAT,
  424. MAILBOX_V2_B2A_INTEN, MAILBOX_V2_B2A_STATUS,
  425. MAILBOX_V2_B2A_CMD, MAILBOX_V2_B2A_DAT
  426. },
  427. .reg_b2a =
  428. {
  429. MAILBOX_V2_B2A_INTEN, MAILBOX_V2_B2A_STATUS,
  430. MAILBOX_V2_B2A_CMD, MAILBOX_V2_B2A_DAT,
  431. MAILBOX_V2_A2B_INTEN, MAILBOX_V2_A2B_STATUS,
  432. MAILBOX_V2_A2B_CMD, MAILBOX_V2_A2B_DAT
  433. },
  434. .ops = &rockchip_mbox_v2_ops,
  435. .isr = rockchip_mbox_v2_isr,
  436. .thread_isr = rockchip_mbox_v2_thread_isr,
  437. };
  438. static const struct rt_ofw_node_id rockchip_mbox_ofw_ids[] =
  439. {
  440. { .compatible = "rockchip,rk3368-mailbox", .data = &rk3368_data },
  441. { .compatible = "rockchip,rk3576-mailbox", .data = &rk3576_data },
  442. { /* sentinel */ }
  443. };
  444. static struct rt_platform_driver rockchip_mbox_driver =
  445. {
  446. .name = "mailbox-rockchip",
  447. .ids = rockchip_mbox_ofw_ids,
  448. .probe = rockchip_mbox_probe,
  449. .remove = rockchip_mbox_remove,
  450. };
  451. RT_PLATFORM_DRIVER_EXPORT(rockchip_mbox_driver);