hi6220-mailbox.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. /*
  2. * Hisilicon's Hi6220 mailbox driver
  3. *
  4. * Copyright (c) 2015 Hisilicon Limited.
  5. * Copyright (c) 2015 Linaro Limited.
  6. *
  7. * Author: Leo Yan <leo.yan@linaro.org>
  8. *
  9. * This program is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation, version 2 of the License.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. */
  19. #include <linux/device.h>
  20. #include <linux/err.h>
  21. #include <linux/interrupt.h>
  22. #include <linux/io.h>
  23. #include <linux/kfifo.h>
  24. #include <linux/mailbox_controller.h>
  25. #include <linux/module.h>
  26. #include <linux/platform_device.h>
  27. #include <linux/slab.h>
  28. #define MBOX_CHAN_MAX 32
  29. #define MBOX_TX 0x1
  30. /* Mailbox message length: 8 words */
  31. #define MBOX_MSG_LEN 8
  32. /* Mailbox Registers */
  33. #define MBOX_OFF(m) (0x40 * (m))
  34. #define MBOX_MODE_REG(m) (MBOX_OFF(m) + 0x0)
  35. #define MBOX_DATA_REG(m) (MBOX_OFF(m) + 0x4)
  36. #define MBOX_STATE_MASK (0xF << 4)
  37. #define MBOX_STATE_IDLE (0x1 << 4)
  38. #define MBOX_STATE_TX (0x2 << 4)
  39. #define MBOX_STATE_RX (0x4 << 4)
  40. #define MBOX_STATE_ACK (0x8 << 4)
  41. #define MBOX_ACK_CONFIG_MASK (0x1 << 0)
  42. #define MBOX_ACK_AUTOMATIC (0x1 << 0)
  43. #define MBOX_ACK_IRQ (0x0 << 0)
  44. /* IPC registers */
  45. #define ACK_INT_RAW_REG(i) ((i) + 0x400)
  46. #define ACK_INT_MSK_REG(i) ((i) + 0x404)
  47. #define ACK_INT_STAT_REG(i) ((i) + 0x408)
  48. #define ACK_INT_CLR_REG(i) ((i) + 0x40c)
  49. #define ACK_INT_ENA_REG(i) ((i) + 0x500)
  50. #define ACK_INT_DIS_REG(i) ((i) + 0x504)
  51. #define DST_INT_RAW_REG(i) ((i) + 0x420)
  52. struct hi6220_mbox_chan {
  53. /*
  54. * Description for channel's hardware info:
  55. * - direction: tx or rx
  56. * - dst irq: peer core's irq number
  57. * - ack irq: local irq number
  58. * - slot number
  59. */
  60. unsigned int dir, dst_irq, ack_irq;
  61. unsigned int slot;
  62. struct hi6220_mbox *parent;
  63. };
  64. struct hi6220_mbox {
  65. struct device *dev;
  66. int irq;
  67. /* flag of enabling tx's irq mode */
  68. bool tx_irq_mode;
  69. /* region for ipc event */
  70. void __iomem *ipc;
  71. /* region for mailbox */
  72. void __iomem *base;
  73. unsigned int chan_num;
  74. struct hi6220_mbox_chan *mchan;
  75. void *irq_map_chan[MBOX_CHAN_MAX];
  76. struct mbox_chan *chan;
  77. struct mbox_controller controller;
  78. };
  79. static void mbox_set_state(struct hi6220_mbox *mbox,
  80. unsigned int slot, u32 val)
  81. {
  82. u32 status;
  83. status = readl(mbox->base + MBOX_MODE_REG(slot));
  84. status = (status & ~MBOX_STATE_MASK) | val;
  85. writel(status, mbox->base + MBOX_MODE_REG(slot));
  86. }
  87. static void mbox_set_mode(struct hi6220_mbox *mbox,
  88. unsigned int slot, u32 val)
  89. {
  90. u32 mode;
  91. mode = readl(mbox->base + MBOX_MODE_REG(slot));
  92. mode = (mode & ~MBOX_ACK_CONFIG_MASK) | val;
  93. writel(mode, mbox->base + MBOX_MODE_REG(slot));
  94. }
  95. static bool hi6220_mbox_last_tx_done(struct mbox_chan *chan)
  96. {
  97. struct hi6220_mbox_chan *mchan = chan->con_priv;
  98. struct hi6220_mbox *mbox = mchan->parent;
  99. u32 state;
  100. /* Only set idle state for polling mode */
  101. BUG_ON(mbox->tx_irq_mode);
  102. state = readl(mbox->base + MBOX_MODE_REG(mchan->slot));
  103. return ((state & MBOX_STATE_MASK) == MBOX_STATE_IDLE);
  104. }
  105. static int hi6220_mbox_send_data(struct mbox_chan *chan, void *msg)
  106. {
  107. struct hi6220_mbox_chan *mchan = chan->con_priv;
  108. struct hi6220_mbox *mbox = mchan->parent;
  109. unsigned int slot = mchan->slot;
  110. u32 *buf = msg;
  111. int i;
  112. /* indicate as a TX channel */
  113. mchan->dir = MBOX_TX;
  114. mbox_set_state(mbox, slot, MBOX_STATE_TX);
  115. if (mbox->tx_irq_mode)
  116. mbox_set_mode(mbox, slot, MBOX_ACK_IRQ);
  117. else
  118. mbox_set_mode(mbox, slot, MBOX_ACK_AUTOMATIC);
  119. for (i = 0; i < MBOX_MSG_LEN; i++)
  120. writel(buf[i], mbox->base + MBOX_DATA_REG(slot) + i * 4);
  121. /* trigger remote request */
  122. writel(BIT(mchan->dst_irq), DST_INT_RAW_REG(mbox->ipc));
  123. return 0;
  124. }
  125. static irqreturn_t hi6220_mbox_interrupt(int irq, void *p)
  126. {
  127. struct hi6220_mbox *mbox = p;
  128. struct hi6220_mbox_chan *mchan;
  129. struct mbox_chan *chan;
  130. unsigned int state, intr_bit, i;
  131. u32 msg[MBOX_MSG_LEN];
  132. state = readl(ACK_INT_STAT_REG(mbox->ipc));
  133. if (!state) {
  134. dev_warn(mbox->dev, "%s: spurious interrupt\n",
  135. __func__);
  136. return IRQ_HANDLED;
  137. }
  138. while (state) {
  139. intr_bit = __ffs(state);
  140. state &= (state - 1);
  141. chan = mbox->irq_map_chan[intr_bit];
  142. if (!chan) {
  143. dev_warn(mbox->dev, "%s: unexpected irq vector %d\n",
  144. __func__, intr_bit);
  145. continue;
  146. }
  147. mchan = chan->con_priv;
  148. if (mchan->dir == MBOX_TX)
  149. mbox_chan_txdone(chan, 0);
  150. else {
  151. for (i = 0; i < MBOX_MSG_LEN; i++)
  152. msg[i] = readl(mbox->base +
  153. MBOX_DATA_REG(mchan->slot) + i * 4);
  154. mbox_chan_received_data(chan, (void *)msg);
  155. }
  156. /* clear IRQ source */
  157. writel(BIT(mchan->ack_irq), ACK_INT_CLR_REG(mbox->ipc));
  158. mbox_set_state(mbox, mchan->slot, MBOX_STATE_IDLE);
  159. }
  160. return IRQ_HANDLED;
  161. }
  162. static int hi6220_mbox_startup(struct mbox_chan *chan)
  163. {
  164. struct hi6220_mbox_chan *mchan = chan->con_priv;
  165. struct hi6220_mbox *mbox = mchan->parent;
  166. mchan->dir = 0;
  167. /* enable interrupt */
  168. writel(BIT(mchan->ack_irq), ACK_INT_ENA_REG(mbox->ipc));
  169. return 0;
  170. }
  171. static void hi6220_mbox_shutdown(struct mbox_chan *chan)
  172. {
  173. struct hi6220_mbox_chan *mchan = chan->con_priv;
  174. struct hi6220_mbox *mbox = mchan->parent;
  175. /* disable interrupt */
  176. writel(BIT(mchan->ack_irq), ACK_INT_DIS_REG(mbox->ipc));
  177. mbox->irq_map_chan[mchan->ack_irq] = NULL;
  178. }
  179. static const struct mbox_chan_ops hi6220_mbox_ops = {
  180. .send_data = hi6220_mbox_send_data,
  181. .startup = hi6220_mbox_startup,
  182. .shutdown = hi6220_mbox_shutdown,
  183. .last_tx_done = hi6220_mbox_last_tx_done,
  184. };
  185. static struct mbox_chan *hi6220_mbox_xlate(struct mbox_controller *controller,
  186. const struct of_phandle_args *spec)
  187. {
  188. struct hi6220_mbox *mbox = dev_get_drvdata(controller->dev);
  189. struct hi6220_mbox_chan *mchan;
  190. struct mbox_chan *chan;
  191. unsigned int i = spec->args[0];
  192. unsigned int dst_irq = spec->args[1];
  193. unsigned int ack_irq = spec->args[2];
  194. /* Bounds checking */
  195. if (i >= mbox->chan_num || dst_irq >= mbox->chan_num ||
  196. ack_irq >= mbox->chan_num) {
  197. dev_err(mbox->dev,
  198. "Invalid channel idx %d dst_irq %d ack_irq %d\n",
  199. i, dst_irq, ack_irq);
  200. return ERR_PTR(-EINVAL);
  201. }
  202. /* Is requested channel free? */
  203. chan = &mbox->chan[i];
  204. if (mbox->irq_map_chan[ack_irq] == (void *)chan) {
  205. dev_err(mbox->dev, "Channel in use\n");
  206. return ERR_PTR(-EBUSY);
  207. }
  208. mchan = chan->con_priv;
  209. mchan->dst_irq = dst_irq;
  210. mchan->ack_irq = ack_irq;
  211. mbox->irq_map_chan[ack_irq] = (void *)chan;
  212. return chan;
  213. }
  214. static const struct of_device_id hi6220_mbox_of_match[] = {
  215. { .compatible = "hisilicon,hi6220-mbox", },
  216. {},
  217. };
  218. MODULE_DEVICE_TABLE(of, hi6220_mbox_of_match);
  219. static int hi6220_mbox_probe(struct platform_device *pdev)
  220. {
  221. struct device_node *node = pdev->dev.of_node;
  222. struct device *dev = &pdev->dev;
  223. struct hi6220_mbox *mbox;
  224. struct resource *res;
  225. int i, err;
  226. mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
  227. if (!mbox)
  228. return -ENOMEM;
  229. mbox->dev = dev;
  230. mbox->chan_num = MBOX_CHAN_MAX;
  231. mbox->mchan = devm_kcalloc(dev,
  232. mbox->chan_num, sizeof(*mbox->mchan), GFP_KERNEL);
  233. if (!mbox->mchan)
  234. return -ENOMEM;
  235. mbox->chan = devm_kcalloc(dev,
  236. mbox->chan_num, sizeof(*mbox->chan), GFP_KERNEL);
  237. if (!mbox->chan)
  238. return -ENOMEM;
  239. mbox->irq = platform_get_irq(pdev, 0);
  240. if (mbox->irq < 0)
  241. return mbox->irq;
  242. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  243. mbox->ipc = devm_ioremap_resource(dev, res);
  244. if (IS_ERR(mbox->ipc)) {
  245. dev_err(dev, "ioremap ipc failed\n");
  246. return PTR_ERR(mbox->ipc);
  247. }
  248. res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
  249. mbox->base = devm_ioremap_resource(dev, res);
  250. if (IS_ERR(mbox->base)) {
  251. dev_err(dev, "ioremap buffer failed\n");
  252. return PTR_ERR(mbox->base);
  253. }
  254. err = devm_request_irq(dev, mbox->irq, hi6220_mbox_interrupt, 0,
  255. dev_name(dev), mbox);
  256. if (err) {
  257. dev_err(dev, "Failed to register a mailbox IRQ handler: %d\n",
  258. err);
  259. return -ENODEV;
  260. }
  261. mbox->controller.dev = dev;
  262. mbox->controller.chans = &mbox->chan[0];
  263. mbox->controller.num_chans = mbox->chan_num;
  264. mbox->controller.ops = &hi6220_mbox_ops;
  265. mbox->controller.of_xlate = hi6220_mbox_xlate;
  266. for (i = 0; i < mbox->chan_num; i++) {
  267. mbox->chan[i].con_priv = &mbox->mchan[i];
  268. mbox->irq_map_chan[i] = NULL;
  269. mbox->mchan[i].parent = mbox;
  270. mbox->mchan[i].slot = i;
  271. }
  272. /* mask and clear all interrupt vectors */
  273. writel(0x0, ACK_INT_MSK_REG(mbox->ipc));
  274. writel(~0x0, ACK_INT_CLR_REG(mbox->ipc));
  275. /* use interrupt for tx's ack */
  276. if (of_find_property(node, "hi6220,mbox-tx-noirq", NULL))
  277. mbox->tx_irq_mode = false;
  278. else
  279. mbox->tx_irq_mode = true;
  280. if (mbox->tx_irq_mode)
  281. mbox->controller.txdone_irq = true;
  282. else {
  283. mbox->controller.txdone_poll = true;
  284. mbox->controller.txpoll_period = 5;
  285. }
  286. err = mbox_controller_register(&mbox->controller);
  287. if (err) {
  288. dev_err(dev, "Failed to register mailbox %d\n", err);
  289. return err;
  290. }
  291. platform_set_drvdata(pdev, mbox);
  292. dev_info(dev, "Mailbox enabled\n");
  293. return 0;
  294. }
  295. static int hi6220_mbox_remove(struct platform_device *pdev)
  296. {
  297. struct hi6220_mbox *mbox = platform_get_drvdata(pdev);
  298. mbox_controller_unregister(&mbox->controller);
  299. return 0;
  300. }
  301. static struct platform_driver hi6220_mbox_driver = {
  302. .driver = {
  303. .name = "hi6220-mbox",
  304. .owner = THIS_MODULE,
  305. .of_match_table = hi6220_mbox_of_match,
  306. },
  307. .probe = hi6220_mbox_probe,
  308. .remove = hi6220_mbox_remove,
  309. };
  310. static int __init hi6220_mbox_init(void)
  311. {
  312. return platform_driver_register(&hi6220_mbox_driver);
  313. }
  314. core_initcall(hi6220_mbox_init);
  315. static void __exit hi6220_mbox_exit(void)
  316. {
  317. platform_driver_unregister(&hi6220_mbox_driver);
  318. }
  319. module_exit(hi6220_mbox_exit);
  320. MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>");
  321. MODULE_DESCRIPTION("Hi6220 mailbox driver");
  322. MODULE_LICENSE("GPL v2");