mailbox-xgene-slimpro.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * APM X-Gene SLIMpro MailBox Driver
  4. *
  5. * Copyright (c) 2015, Applied Micro Circuits Corporation
  6. * Author: Feng Kan [email protected]
  7. */
  8. #include <linux/acpi.h>
  9. #include <linux/delay.h>
  10. #include <linux/interrupt.h>
  11. #include <linux/io.h>
  12. #include <linux/mailbox_controller.h>
  13. #include <linux/module.h>
  14. #include <linux/of.h>
  15. #include <linux/platform_device.h>
  16. #include <linux/spinlock.h>
  17. #define MBOX_CON_NAME "slimpro-mbox"
  18. #define MBOX_REG_SET_OFFSET 0x1000
  19. #define MBOX_CNT 8
  20. #define MBOX_STATUS_AVAIL_MASK BIT(16)
  21. #define MBOX_STATUS_ACK_MASK BIT(0)
  22. /* Configuration and Status Registers */
  23. #define REG_DB_IN 0x00
  24. #define REG_DB_DIN0 0x04
  25. #define REG_DB_DIN1 0x08
  26. #define REG_DB_OUT 0x10
  27. #define REG_DB_DOUT0 0x14
  28. #define REG_DB_DOUT1 0x18
  29. #define REG_DB_STAT 0x20
  30. #define REG_DB_STATMASK 0x24
  31. /**
  32. * X-Gene SlimPRO mailbox channel information
  33. *
  34. * @dev: Device to which it is attached
  35. * @chan: Pointer to mailbox communication channel
  36. * @reg: Base address to access channel registers
  37. * @irq: Interrupt number of the channel
  38. * @rx_msg: Received message storage
  39. */
  40. struct slimpro_mbox_chan {
  41. struct device *dev;
  42. struct mbox_chan *chan;
  43. void __iomem *reg;
  44. int irq;
  45. u32 rx_msg[3];
  46. };
  47. /**
  48. * X-Gene SlimPRO Mailbox controller data
  49. *
  50. * X-Gene SlimPRO Mailbox controller has 8 communication channels.
  51. * Each channel has a separate IRQ number assigned to it.
  52. *
  53. * @mb_ctrl: Representation of the communication channel controller
  54. * @mc: Array of SlimPRO mailbox channels of the controller
  55. * @chans: Array of mailbox communication channels
  56. *
  57. */
  58. struct slimpro_mbox {
  59. struct mbox_controller mb_ctrl;
  60. struct slimpro_mbox_chan mc[MBOX_CNT];
  61. struct mbox_chan chans[MBOX_CNT];
  62. };
  63. static void mb_chan_send_msg(struct slimpro_mbox_chan *mb_chan, u32 *msg)
  64. {
  65. writel(msg[1], mb_chan->reg + REG_DB_DOUT0);
  66. writel(msg[2], mb_chan->reg + REG_DB_DOUT1);
  67. writel(msg[0], mb_chan->reg + REG_DB_OUT);
  68. }
  69. static void mb_chan_recv_msg(struct slimpro_mbox_chan *mb_chan)
  70. {
  71. mb_chan->rx_msg[1] = readl(mb_chan->reg + REG_DB_DIN0);
  72. mb_chan->rx_msg[2] = readl(mb_chan->reg + REG_DB_DIN1);
  73. mb_chan->rx_msg[0] = readl(mb_chan->reg + REG_DB_IN);
  74. }
  75. static int mb_chan_status_ack(struct slimpro_mbox_chan *mb_chan)
  76. {
  77. u32 val = readl(mb_chan->reg + REG_DB_STAT);
  78. if (val & MBOX_STATUS_ACK_MASK) {
  79. writel(MBOX_STATUS_ACK_MASK, mb_chan->reg + REG_DB_STAT);
  80. return 1;
  81. }
  82. return 0;
  83. }
  84. static int mb_chan_status_avail(struct slimpro_mbox_chan *mb_chan)
  85. {
  86. u32 val = readl(mb_chan->reg + REG_DB_STAT);
  87. if (val & MBOX_STATUS_AVAIL_MASK) {
  88. mb_chan_recv_msg(mb_chan);
  89. writel(MBOX_STATUS_AVAIL_MASK, mb_chan->reg + REG_DB_STAT);
  90. return 1;
  91. }
  92. return 0;
  93. }
  94. static irqreturn_t slimpro_mbox_irq(int irq, void *id)
  95. {
  96. struct slimpro_mbox_chan *mb_chan = id;
  97. if (mb_chan_status_ack(mb_chan))
  98. mbox_chan_txdone(mb_chan->chan, 0);
  99. if (mb_chan_status_avail(mb_chan))
  100. mbox_chan_received_data(mb_chan->chan, mb_chan->rx_msg);
  101. return IRQ_HANDLED;
  102. }
  103. static int slimpro_mbox_send_data(struct mbox_chan *chan, void *msg)
  104. {
  105. struct slimpro_mbox_chan *mb_chan = chan->con_priv;
  106. mb_chan_send_msg(mb_chan, msg);
  107. return 0;
  108. }
  109. static int slimpro_mbox_startup(struct mbox_chan *chan)
  110. {
  111. struct slimpro_mbox_chan *mb_chan = chan->con_priv;
  112. int rc;
  113. u32 val;
  114. rc = devm_request_irq(mb_chan->dev, mb_chan->irq, slimpro_mbox_irq, 0,
  115. MBOX_CON_NAME, mb_chan);
  116. if (unlikely(rc)) {
  117. dev_err(mb_chan->dev, "failed to register mailbox interrupt %d\n",
  118. mb_chan->irq);
  119. return rc;
  120. }
  121. /* Enable HW interrupt */
  122. writel(MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK,
  123. mb_chan->reg + REG_DB_STAT);
  124. /* Unmask doorbell status interrupt */
  125. val = readl(mb_chan->reg + REG_DB_STATMASK);
  126. val &= ~(MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK);
  127. writel(val, mb_chan->reg + REG_DB_STATMASK);
  128. return 0;
  129. }
  130. static void slimpro_mbox_shutdown(struct mbox_chan *chan)
  131. {
  132. struct slimpro_mbox_chan *mb_chan = chan->con_priv;
  133. u32 val;
  134. /* Mask doorbell status interrupt */
  135. val = readl(mb_chan->reg + REG_DB_STATMASK);
  136. val |= (MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK);
  137. writel(val, mb_chan->reg + REG_DB_STATMASK);
  138. devm_free_irq(mb_chan->dev, mb_chan->irq, mb_chan);
  139. }
  140. static const struct mbox_chan_ops slimpro_mbox_ops = {
  141. .send_data = slimpro_mbox_send_data,
  142. .startup = slimpro_mbox_startup,
  143. .shutdown = slimpro_mbox_shutdown,
  144. };
  145. static int slimpro_mbox_probe(struct platform_device *pdev)
  146. {
  147. struct slimpro_mbox *ctx;
  148. void __iomem *mb_base;
  149. int rc;
  150. int i;
  151. ctx = devm_kzalloc(&pdev->dev, sizeof(struct slimpro_mbox), GFP_KERNEL);
  152. if (!ctx)
  153. return -ENOMEM;
  154. platform_set_drvdata(pdev, ctx);
  155. mb_base = devm_platform_ioremap_resource(pdev, 0);
  156. if (IS_ERR(mb_base))
  157. return PTR_ERR(mb_base);
  158. /* Setup mailbox links */
  159. for (i = 0; i < MBOX_CNT; i++) {
  160. ctx->mc[i].irq = platform_get_irq(pdev, i);
  161. if (ctx->mc[i].irq < 0) {
  162. if (i == 0) {
  163. dev_err(&pdev->dev, "no available IRQ\n");
  164. return -EINVAL;
  165. }
  166. dev_info(&pdev->dev, "no IRQ for channel %d\n", i);
  167. break;
  168. }
  169. ctx->mc[i].dev = &pdev->dev;
  170. ctx->mc[i].reg = mb_base + i * MBOX_REG_SET_OFFSET;
  171. ctx->mc[i].chan = &ctx->chans[i];
  172. ctx->chans[i].con_priv = &ctx->mc[i];
  173. }
  174. /* Setup mailbox controller */
  175. ctx->mb_ctrl.dev = &pdev->dev;
  176. ctx->mb_ctrl.chans = ctx->chans;
  177. ctx->mb_ctrl.txdone_irq = true;
  178. ctx->mb_ctrl.ops = &slimpro_mbox_ops;
  179. ctx->mb_ctrl.num_chans = i;
  180. rc = devm_mbox_controller_register(&pdev->dev, &ctx->mb_ctrl);
  181. if (rc) {
  182. dev_err(&pdev->dev,
  183. "APM X-Gene SLIMpro MailBox register failed:%d\n", rc);
  184. return rc;
  185. }
  186. dev_info(&pdev->dev, "APM X-Gene SLIMpro MailBox registered\n");
  187. return 0;
  188. }
  189. static const struct of_device_id slimpro_of_match[] = {
  190. {.compatible = "apm,xgene-slimpro-mbox" },
  191. { },
  192. };
  193. MODULE_DEVICE_TABLE(of, slimpro_of_match);
  194. #ifdef CONFIG_ACPI
  195. static const struct acpi_device_id slimpro_acpi_ids[] = {
  196. {"APMC0D01", 0},
  197. {}
  198. };
  199. MODULE_DEVICE_TABLE(acpi, slimpro_acpi_ids);
  200. #endif
  201. static struct platform_driver slimpro_mbox_driver = {
  202. .probe = slimpro_mbox_probe,
  203. .driver = {
  204. .name = "xgene-slimpro-mbox",
  205. .of_match_table = of_match_ptr(slimpro_of_match),
  206. .acpi_match_table = ACPI_PTR(slimpro_acpi_ids)
  207. },
  208. };
  209. static int __init slimpro_mbox_init(void)
  210. {
  211. return platform_driver_register(&slimpro_mbox_driver);
  212. }
  213. static void __exit slimpro_mbox_exit(void)
  214. {
  215. platform_driver_unregister(&slimpro_mbox_driver);
  216. }
  217. subsys_initcall(slimpro_mbox_init);
  218. module_exit(slimpro_mbox_exit);
  219. MODULE_DESCRIPTION("APM X-Gene SLIMpro Mailbox Driver");
  220. MODULE_LICENSE("GPL");