bcm74110-mailbox.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Broadcom BCM74110 Mailbox Driver
  4. *
  5. * Copyright (c) 2025 Broadcom
  6. */
  7. #include <linux/list.h>
  8. #include <linux/types.h>
  9. #include <linux/workqueue.h>
  10. #include <linux/io-64-nonatomic-hi-lo.h>
  11. #include <linux/interrupt.h>
  12. #include <linux/module.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/of.h>
  15. #include <linux/delay.h>
  16. #include <linux/mailbox_controller.h>
  17. #include <linux/bitfield.h>
  18. #include <linux/slab.h>
  19. #define BCM_MBOX_BASE(sel) ((sel) * 0x40)
  20. #define BCM_MBOX_IRQ_BASE(sel) (((sel) * 0x20) + 0x800)
  21. #define BCM_MBOX_CFGA 0x0
  22. #define BCM_MBOX_CFGB 0x4
  23. #define BCM_MBOX_CFGC 0x8
  24. #define BCM_MBOX_CFGD 0xc
  25. #define BCM_MBOX_CTRL 0x10
  26. #define BCM_MBOX_CTRL_EN BIT(0)
  27. #define BCM_MBOX_CTRL_CLR BIT(1)
  28. #define BCM_MBOX_STATUS0 0x14
  29. #define BCM_MBOX_STATUS0_NOT_EMPTY BIT(28)
  30. #define BCM_MBOX_STATUS0_FULL BIT(29)
  31. #define BCM_MBOX_STATUS1 0x18
  32. #define BCM_MBOX_STATUS2 0x1c
  33. #define BCM_MBOX_WDATA 0x20
  34. #define BCM_MBOX_RDATA 0x28
  35. #define BCM_MBOX_IRQ_STATUS 0x0
  36. #define BCM_MBOX_IRQ_SET 0x4
  37. #define BCM_MBOX_IRQ_CLEAR 0x8
  38. #define BCM_MBOX_IRQ_MASK_STATUS 0xc
  39. #define BCM_MBOX_IRQ_MASK_SET 0x10
  40. #define BCM_MBOX_IRQ_MASK_CLEAR 0x14
  41. #define BCM_MBOX_IRQ_TIMEOUT BIT(0)
  42. #define BCM_MBOX_IRQ_NOT_EMPTY BIT(1)
  43. #define BCM_MBOX_IRQ_FULL BIT(2)
  44. #define BCM_MBOX_IRQ_LOW_WM BIT(3)
  45. #define BCM_MBOX_IRQ_HIGH_WM BIT(4)
  46. #define BCM_LINK_CODE0 0xbe0
  47. #define BCM_LINK_CODE1 0xbe1
  48. #define BCM_LINK_CODE2 0xbe2
  49. enum {
  50. BCM_MSG_FUNC_LINK_START = 0,
  51. BCM_MSG_FUNC_LINK_STOP,
  52. BCM_MSG_FUNC_SHMEM_TX,
  53. BCM_MSG_FUNC_SHMEM_RX,
  54. BCM_MSG_FUNC_SHMEM_STOP,
  55. BCM_MSG_FUNC_MAX,
  56. };
  57. enum {
  58. BCM_MSG_SVC_INIT = 0,
  59. BCM_MSG_SVC_PMC,
  60. BCM_MSG_SVC_SCMI,
  61. BCM_MSG_SVC_DPFE,
  62. BCM_MSG_SVC_MAX,
  63. };
  64. struct bcm74110_mbox_msg {
  65. struct list_head list_entry;
  66. #define BCM_MSG_VERSION_MASK GENMASK(31, 29)
  67. #define BCM_MSG_VERSION 0x1
  68. #define BCM_MSG_REQ_MASK BIT(28)
  69. #define BCM_MSG_RPLY_MASK BIT(27)
  70. #define BCM_MSG_SVC_MASK GENMASK(26, 24)
  71. #define BCM_MSG_FUNC_MASK GENMASK(23, 16)
  72. #define BCM_MSG_LENGTH_MASK GENMASK(15, 4)
  73. #define BCM_MSG_SLOT_MASK GENMASK(3, 0)
  74. #define BCM_MSG_SET_FIELD(hdr, field, val) \
  75. do { \
  76. hdr &= ~BCM_MSG_##field##_MASK; \
  77. hdr |= FIELD_PREP(BCM_MSG_##field##_MASK, val); \
  78. } while (0)
  79. #define BCM_MSG_GET_FIELD(hdr, field) \
  80. FIELD_GET(BCM_MSG_##field##_MASK, hdr)
  81. u32 msg;
  82. };
  83. struct bcm74110_mbox_chan {
  84. struct bcm74110_mbox *mbox;
  85. bool en;
  86. int slot;
  87. int type;
  88. };
  89. struct bcm74110_mbox {
  90. struct platform_device *pdev;
  91. void __iomem *base;
  92. int tx_chan;
  93. int rx_chan;
  94. int rx_irq;
  95. struct list_head rx_svc_init_list;
  96. spinlock_t rx_svc_list_lock;
  97. struct mbox_controller controller;
  98. struct bcm74110_mbox_chan *mbox_chan;
  99. };
  100. #define BCM74110_OFFSET_IO_WRITEL_MACRO(name, offset_base) \
  101. static void bcm74110_##name##_writel(struct bcm74110_mbox *mbox,\
  102. u32 val, u32 off) \
  103. { \
  104. writel_relaxed(val, mbox->base + offset_base + off); \
  105. }
  106. BCM74110_OFFSET_IO_WRITEL_MACRO(tx, BCM_MBOX_BASE(mbox->tx_chan));
  107. BCM74110_OFFSET_IO_WRITEL_MACRO(irq, BCM_MBOX_IRQ_BASE(mbox->rx_chan));
  108. #define BCM74110_OFFSET_IO_READL_MACRO(name, offset_base) \
  109. static u32 bcm74110_##name##_readl(struct bcm74110_mbox *mbox, \
  110. u32 off) \
  111. { \
  112. return readl_relaxed(mbox->base + offset_base + off); \
  113. }
  114. BCM74110_OFFSET_IO_READL_MACRO(tx, BCM_MBOX_BASE(mbox->tx_chan));
  115. BCM74110_OFFSET_IO_READL_MACRO(rx, BCM_MBOX_BASE(mbox->rx_chan));
  116. BCM74110_OFFSET_IO_READL_MACRO(irq, BCM_MBOX_IRQ_BASE(mbox->rx_chan));
  117. static inline struct bcm74110_mbox *bcm74110_mbox_from_cntrl(
  118. struct mbox_controller *cntrl)
  119. {
  120. return container_of(cntrl, struct bcm74110_mbox, controller);
  121. }
  122. static void bcm74110_rx_push_init_msg(struct bcm74110_mbox *mbox, u32 val)
  123. {
  124. struct bcm74110_mbox_msg *msg;
  125. msg = kzalloc_obj(*msg, GFP_ATOMIC);
  126. if (!msg)
  127. return;
  128. INIT_LIST_HEAD(&msg->list_entry);
  129. msg->msg = val;
  130. spin_lock(&mbox->rx_svc_list_lock);
  131. list_add_tail(&msg->list_entry, &mbox->rx_svc_init_list);
  132. spin_unlock(&mbox->rx_svc_list_lock);
  133. }
  134. static void bcm74110_rx_process_msg(struct bcm74110_mbox *mbox)
  135. {
  136. struct device *dev = &mbox->pdev->dev;
  137. struct bcm74110_mbox_chan *chan_priv;
  138. struct mbox_chan *chan;
  139. u32 msg, status;
  140. int type;
  141. do {
  142. msg = bcm74110_rx_readl(mbox, BCM_MBOX_RDATA);
  143. status = bcm74110_rx_readl(mbox, BCM_MBOX_STATUS0);
  144. dev_dbg(dev, "rx: [{req=%lu|rply=%lu|srv=%lu|fn=%lu|length=%lu|slot=%lu]\n",
  145. BCM_MSG_GET_FIELD(msg, REQ), BCM_MSG_GET_FIELD(msg, RPLY),
  146. BCM_MSG_GET_FIELD(msg, SVC), BCM_MSG_GET_FIELD(msg, FUNC),
  147. BCM_MSG_GET_FIELD(msg, LENGTH), BCM_MSG_GET_FIELD(msg, SLOT));
  148. type = BCM_MSG_GET_FIELD(msg, SVC);
  149. switch (type) {
  150. case BCM_MSG_SVC_INIT:
  151. bcm74110_rx_push_init_msg(mbox, msg);
  152. break;
  153. case BCM_MSG_SVC_PMC:
  154. case BCM_MSG_SVC_SCMI:
  155. case BCM_MSG_SVC_DPFE:
  156. chan = &mbox->controller.chans[type];
  157. chan_priv = chan->con_priv;
  158. if (chan_priv->en)
  159. mbox_chan_received_data(chan, NULL);
  160. else
  161. dev_warn(dev, "Channel not enabled\n");
  162. break;
  163. default:
  164. dev_warn(dev, "Unsupported msg received\n");
  165. }
  166. } while (status & BCM_MBOX_STATUS0_NOT_EMPTY);
  167. }
  168. static irqreturn_t bcm74110_mbox_isr(int irq, void *data)
  169. {
  170. struct bcm74110_mbox *mbox = data;
  171. u32 status;
  172. status = bcm74110_irq_readl(mbox, BCM_MBOX_IRQ_STATUS);
  173. bcm74110_irq_writel(mbox, 0xffffffff, BCM_MBOX_IRQ_CLEAR);
  174. if (status & BCM_MBOX_IRQ_NOT_EMPTY)
  175. bcm74110_rx_process_msg(mbox);
  176. else
  177. dev_warn(&mbox->pdev->dev, "Spurious interrupt\n");
  178. return IRQ_HANDLED;
  179. }
  180. static void bcm74110_mbox_mask_and_clear(struct bcm74110_mbox *mbox)
  181. {
  182. bcm74110_irq_writel(mbox, 0xffffffff, BCM_MBOX_IRQ_MASK_SET);
  183. bcm74110_irq_writel(mbox, 0xffffffff, BCM_MBOX_IRQ_CLEAR);
  184. }
  185. static int bcm74110_rx_pop_init_msg(struct bcm74110_mbox *mbox, u32 func_type,
  186. u32 *val)
  187. {
  188. struct bcm74110_mbox_msg *msg, *msg_tmp;
  189. unsigned long flags;
  190. bool found = false;
  191. spin_lock_irqsave(&mbox->rx_svc_list_lock, flags);
  192. list_for_each_entry_safe(msg, msg_tmp, &mbox->rx_svc_init_list,
  193. list_entry) {
  194. if (BCM_MSG_GET_FIELD(msg->msg, FUNC) == func_type) {
  195. list_del(&msg->list_entry);
  196. found = true;
  197. break;
  198. }
  199. }
  200. spin_unlock_irqrestore(&mbox->rx_svc_list_lock, flags);
  201. if (!found)
  202. return -EINVAL;
  203. *val = msg->msg;
  204. kfree(msg);
  205. return 0;
  206. }
  207. static void bcm74110_rx_flush_msg(struct bcm74110_mbox *mbox)
  208. {
  209. struct bcm74110_mbox_msg *msg, *msg_tmp;
  210. LIST_HEAD(list_temp);
  211. unsigned long flags;
  212. spin_lock_irqsave(&mbox->rx_svc_list_lock, flags);
  213. list_splice_init(&mbox->rx_svc_init_list, &list_temp);
  214. spin_unlock_irqrestore(&mbox->rx_svc_list_lock, flags);
  215. list_for_each_entry_safe(msg, msg_tmp, &list_temp, list_entry) {
  216. list_del(&msg->list_entry);
  217. kfree(msg);
  218. }
  219. }
  220. #define BCM_DEQUEUE_TIMEOUT_MS 30
  221. static int bcm74110_rx_pop_init_msg_block(struct bcm74110_mbox *mbox, u32 func_type,
  222. u32 *val)
  223. {
  224. int ret, timeout = 0;
  225. do {
  226. ret = bcm74110_rx_pop_init_msg(mbox, func_type, val);
  227. if (!ret)
  228. return 0;
  229. /* TODO: Figure out what is a good sleep here. */
  230. usleep_range(1000, 2000);
  231. timeout++;
  232. } while (timeout < BCM_DEQUEUE_TIMEOUT_MS);
  233. dev_warn(&mbox->pdev->dev, "Timeout waiting for service init response\n");
  234. return -ETIMEDOUT;
  235. }
  236. static int bcm74110_mbox_create_msg(int req, int rply, int svc, int func,
  237. int length, int slot)
  238. {
  239. u32 msg = 0;
  240. BCM_MSG_SET_FIELD(msg, REQ, req);
  241. BCM_MSG_SET_FIELD(msg, RPLY, rply);
  242. BCM_MSG_SET_FIELD(msg, SVC, svc);
  243. BCM_MSG_SET_FIELD(msg, FUNC, func);
  244. BCM_MSG_SET_FIELD(msg, LENGTH, length);
  245. BCM_MSG_SET_FIELD(msg, SLOT, slot);
  246. return msg;
  247. }
  248. static int bcm74110_mbox_tx_msg(struct bcm74110_mbox *mbox, u32 msg)
  249. {
  250. int val;
  251. /* We can potentially poll with timeout here instead */
  252. val = bcm74110_tx_readl(mbox, BCM_MBOX_STATUS0);
  253. if (val & BCM_MBOX_STATUS0_FULL) {
  254. dev_err(&mbox->pdev->dev, "Mailbox full\n");
  255. return -EINVAL;
  256. }
  257. dev_dbg(&mbox->pdev->dev, "tx: [{req=%lu|rply=%lu|srv=%lu|fn=%lu|length=%lu|slot=%lu]\n",
  258. BCM_MSG_GET_FIELD(msg, REQ), BCM_MSG_GET_FIELD(msg, RPLY),
  259. BCM_MSG_GET_FIELD(msg, SVC), BCM_MSG_GET_FIELD(msg, FUNC),
  260. BCM_MSG_GET_FIELD(msg, LENGTH), BCM_MSG_GET_FIELD(msg, SLOT));
  261. bcm74110_tx_writel(mbox, msg, BCM_MBOX_WDATA);
  262. return 0;
  263. }
  264. #define BCM_MBOX_LINK_TRAINING_RETRIES 5
  265. static int bcm74110_mbox_link_training(struct bcm74110_mbox *mbox)
  266. {
  267. int ret, retries = 0;
  268. u32 msg = 0, orig_len = 0, len = BCM_LINK_CODE0;
  269. do {
  270. switch (len) {
  271. case 0:
  272. retries++;
  273. dev_warn(&mbox->pdev->dev,
  274. "Link train failed, trying again... %d\n",
  275. retries);
  276. if (retries > BCM_MBOX_LINK_TRAINING_RETRIES)
  277. return -EINVAL;
  278. len = BCM_LINK_CODE0;
  279. fallthrough;
  280. case BCM_LINK_CODE0:
  281. case BCM_LINK_CODE1:
  282. case BCM_LINK_CODE2:
  283. msg = bcm74110_mbox_create_msg(1, 0, BCM_MSG_SVC_INIT,
  284. BCM_MSG_FUNC_LINK_START,
  285. len, BCM_MSG_SVC_INIT);
  286. break;
  287. default:
  288. break;
  289. }
  290. bcm74110_mbox_tx_msg(mbox, msg);
  291. /* No response expected for LINK_CODE2 */
  292. if (len == BCM_LINK_CODE2)
  293. return 0;
  294. orig_len = len;
  295. ret = bcm74110_rx_pop_init_msg_block(mbox,
  296. BCM_MSG_GET_FIELD(msg, FUNC),
  297. &msg);
  298. if (ret) {
  299. len = 0;
  300. continue;
  301. }
  302. if ((BCM_MSG_GET_FIELD(msg, SVC) != BCM_MSG_SVC_INIT) ||
  303. (BCM_MSG_GET_FIELD(msg, FUNC) != BCM_MSG_FUNC_LINK_START) ||
  304. (BCM_MSG_GET_FIELD(msg, SLOT) != 0) ||
  305. (BCM_MSG_GET_FIELD(msg, RPLY) != 1) ||
  306. (BCM_MSG_GET_FIELD(msg, REQ) != 0)) {
  307. len = 0;
  308. continue;
  309. }
  310. len = BCM_MSG_GET_FIELD(msg, LENGTH);
  311. /* Make sure sequence is good */
  312. if (len != (orig_len + 1)) {
  313. len = 0;
  314. continue;
  315. }
  316. } while (1);
  317. return -EINVAL;
  318. }
  319. static int bcm74110_mbox_tx_msg_and_wait_ack(struct bcm74110_mbox *mbox, u32 msg)
  320. {
  321. int ret;
  322. u32 recv_msg;
  323. ret = bcm74110_mbox_tx_msg(mbox, msg);
  324. if (ret)
  325. return ret;
  326. ret = bcm74110_rx_pop_init_msg_block(mbox, BCM_MSG_GET_FIELD(msg, FUNC),
  327. &recv_msg);
  328. if (ret)
  329. return ret;
  330. /*
  331. * Modify tx message to verify rx ack.
  332. * Flip RPLY/REQ for synchronous messages
  333. */
  334. if (BCM_MSG_GET_FIELD(msg, REQ) == 1) {
  335. BCM_MSG_SET_FIELD(msg, RPLY, 1);
  336. BCM_MSG_SET_FIELD(msg, REQ, 0);
  337. }
  338. if (msg != recv_msg) {
  339. dev_err(&mbox->pdev->dev, "Found ack, but ack is invalid\n");
  340. return -EINVAL;
  341. }
  342. return 0;
  343. }
  344. /* Each index points to 0x100 of HAB MEM. IDX size counts from 0 */
  345. #define BCM_MBOX_HAB_MEM_IDX_START 0x30
  346. #define BCM_MBOX_HAB_MEM_IDX_SIZE 0x0
  347. static int bcm74110_mbox_shmem_init(struct bcm74110_mbox *mbox)
  348. {
  349. u32 msg = 0;
  350. int ret;
  351. msg = bcm74110_mbox_create_msg(1, 0, BCM_MSG_SVC_INIT,
  352. BCM_MSG_FUNC_SHMEM_STOP,
  353. 0, BCM_MSG_SVC_INIT);
  354. ret = bcm74110_mbox_tx_msg_and_wait_ack(mbox, msg);
  355. if (ret)
  356. return -EINVAL;
  357. msg = bcm74110_mbox_create_msg(1, 0, BCM_MSG_SVC_INIT,
  358. BCM_MSG_FUNC_SHMEM_TX,
  359. BCM_MBOX_HAB_MEM_IDX_START,
  360. BCM_MBOX_HAB_MEM_IDX_SIZE);
  361. ret = bcm74110_mbox_tx_msg_and_wait_ack(mbox, msg);
  362. if (ret)
  363. return -EINVAL;
  364. msg = bcm74110_mbox_create_msg(1, 0, BCM_MSG_SVC_INIT,
  365. BCM_MSG_FUNC_SHMEM_RX,
  366. BCM_MBOX_HAB_MEM_IDX_START,
  367. BCM_MBOX_HAB_MEM_IDX_SIZE);
  368. ret = bcm74110_mbox_tx_msg_and_wait_ack(mbox, msg);
  369. if (ret)
  370. return -EINVAL;
  371. return 0;
  372. }
  373. static int bcm74110_mbox_init(struct bcm74110_mbox *mbox)
  374. {
  375. int ret = 0;
  376. /* Disable queues tx/rx */
  377. bcm74110_tx_writel(mbox, 0x0, BCM_MBOX_CTRL);
  378. /* Clear status & restart tx/rx*/
  379. bcm74110_tx_writel(mbox, BCM_MBOX_CTRL_EN | BCM_MBOX_CTRL_CLR,
  380. BCM_MBOX_CTRL);
  381. /* Unmask irq */
  382. bcm74110_irq_writel(mbox, BCM_MBOX_IRQ_NOT_EMPTY, BCM_MBOX_IRQ_MASK_CLEAR);
  383. ret = bcm74110_mbox_link_training(mbox);
  384. if (ret) {
  385. dev_err(&mbox->pdev->dev, "Training failed\n");
  386. return ret;
  387. }
  388. return bcm74110_mbox_shmem_init(mbox);
  389. }
  390. static int bcm74110_mbox_send_data(struct mbox_chan *chan, void *data)
  391. {
  392. struct bcm74110_mbox_chan *chan_priv = chan->con_priv;
  393. u32 msg;
  394. switch (chan_priv->type) {
  395. case BCM_MSG_SVC_PMC:
  396. case BCM_MSG_SVC_SCMI:
  397. case BCM_MSG_SVC_DPFE:
  398. msg = bcm74110_mbox_create_msg(1, 0, chan_priv->type, 0,
  399. 128 + 28, chan_priv->slot);
  400. break;
  401. default:
  402. return -EINVAL;
  403. }
  404. return bcm74110_mbox_tx_msg(chan_priv->mbox, msg);
  405. }
  406. static int bcm74110_mbox_chan_startup(struct mbox_chan *chan)
  407. {
  408. struct bcm74110_mbox_chan *chan_priv = chan->con_priv;
  409. chan_priv->en = true;
  410. return 0;
  411. }
  412. static void bcm74110_mbox_chan_shutdown(struct mbox_chan *chan)
  413. {
  414. struct bcm74110_mbox_chan *chan_priv = chan->con_priv;
  415. chan_priv->en = false;
  416. }
  417. static const struct mbox_chan_ops bcm74110_mbox_chan_ops = {
  418. .send_data = bcm74110_mbox_send_data,
  419. .startup = bcm74110_mbox_chan_startup,
  420. .shutdown = bcm74110_mbox_chan_shutdown,
  421. };
  422. static void bcm74110_mbox_shutdown(struct platform_device *pdev)
  423. {
  424. struct bcm74110_mbox *mbox = dev_get_drvdata(&pdev->dev);
  425. u32 msg;
  426. msg = bcm74110_mbox_create_msg(1, 0, BCM_MSG_SVC_INIT,
  427. BCM_MSG_FUNC_LINK_STOP,
  428. 0, 0);
  429. bcm74110_mbox_tx_msg_and_wait_ack(mbox, msg);
  430. /* Even if we don't receive ACK, lets shut it down */
  431. bcm74110_mbox_mask_and_clear(mbox);
  432. /* Disable queues tx/rx */
  433. bcm74110_tx_writel(mbox, 0x0, BCM_MBOX_CTRL);
  434. /* Flush queues */
  435. bcm74110_rx_flush_msg(mbox);
  436. }
  437. static struct mbox_chan *bcm74110_mbox_of_xlate(struct mbox_controller *cntrl,
  438. const struct of_phandle_args *p)
  439. {
  440. struct bcm74110_mbox *mbox = bcm74110_mbox_from_cntrl(cntrl);
  441. struct device *dev = &mbox->pdev->dev;
  442. struct bcm74110_mbox_chan *chan_priv;
  443. int slot, type;
  444. if (p->args_count != 2) {
  445. dev_err(dev, "Invalid arguments\n");
  446. return ERR_PTR(-EINVAL);
  447. }
  448. type = p->args[0];
  449. slot = p->args[1];
  450. switch (type) {
  451. case BCM_MSG_SVC_PMC:
  452. case BCM_MSG_SVC_SCMI:
  453. case BCM_MSG_SVC_DPFE:
  454. if (slot > BCM_MBOX_HAB_MEM_IDX_SIZE) {
  455. dev_err(dev, "Not enough shared memory\n");
  456. return ERR_PTR(-EINVAL);
  457. }
  458. chan_priv = cntrl->chans[type].con_priv;
  459. chan_priv->slot = slot;
  460. chan_priv->type = type;
  461. break;
  462. default:
  463. dev_err(dev, "Invalid channel type: %d\n", type);
  464. return ERR_PTR(-EINVAL);
  465. }
  466. return &cntrl->chans[type];
  467. }
  468. static int bcm74110_mbox_probe(struct platform_device *pdev)
  469. {
  470. struct device *dev = &pdev->dev;
  471. struct bcm74110_mbox *mbox;
  472. int i, ret;
  473. mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
  474. if (!mbox)
  475. return -ENOMEM;
  476. mbox->pdev = pdev;
  477. platform_set_drvdata(pdev, mbox);
  478. mbox->base = devm_platform_ioremap_resource(pdev, 0);
  479. if (IS_ERR(mbox->base))
  480. return dev_err_probe(dev, PTR_ERR(mbox->base), "Failed to iomap\n");
  481. ret = of_property_read_u32(dev->of_node, "brcm,tx", &mbox->tx_chan);
  482. if (ret)
  483. return dev_err_probe(dev, ret, "Failed to find tx channel\n");
  484. ret = of_property_read_u32(dev->of_node, "brcm,rx", &mbox->rx_chan);
  485. if (ret)
  486. return dev_err_probe(dev, ret, "Failed to find rx channel\n");
  487. mbox->rx_irq = platform_get_irq(pdev, 0);
  488. if (mbox->rx_irq < 0)
  489. return mbox->rx_irq;
  490. INIT_LIST_HEAD(&mbox->rx_svc_init_list);
  491. spin_lock_init(&mbox->rx_svc_list_lock);
  492. bcm74110_mbox_mask_and_clear(mbox);
  493. ret = devm_request_irq(dev, mbox->rx_irq, bcm74110_mbox_isr,
  494. IRQF_NO_SUSPEND, pdev->name, mbox);
  495. if (ret)
  496. return dev_err_probe(dev, ret, "Failed to request irq\n");
  497. mbox->controller.ops = &bcm74110_mbox_chan_ops;
  498. mbox->controller.dev = dev;
  499. mbox->controller.num_chans = BCM_MSG_SVC_MAX;
  500. mbox->controller.of_xlate = &bcm74110_mbox_of_xlate;
  501. mbox->controller.chans = devm_kcalloc(dev, BCM_MSG_SVC_MAX,
  502. sizeof(*mbox->controller.chans),
  503. GFP_KERNEL);
  504. if (!mbox->controller.chans)
  505. return -ENOMEM;
  506. mbox->mbox_chan = devm_kcalloc(dev, BCM_MSG_SVC_MAX,
  507. sizeof(*mbox->mbox_chan),
  508. GFP_KERNEL);
  509. if (!mbox->mbox_chan)
  510. return -ENOMEM;
  511. for (i = 0; i < BCM_MSG_SVC_MAX; i++) {
  512. mbox->mbox_chan[i].mbox = mbox;
  513. mbox->controller.chans[i].con_priv = &mbox->mbox_chan[i];
  514. }
  515. ret = devm_mbox_controller_register(dev, &mbox->controller);
  516. if (ret)
  517. return ret;
  518. ret = bcm74110_mbox_init(mbox);
  519. if (ret)
  520. return ret;
  521. return 0;
  522. }
  523. static const struct of_device_id bcm74110_mbox_of_match[] = {
  524. { .compatible = "brcm,bcm74110-mbox", },
  525. { /* sentinel */ },
  526. };
  527. MODULE_DEVICE_TABLE(of, bcm74110_mbox_of_match);
  528. static struct platform_driver bcm74110_mbox_driver = {
  529. .driver = {
  530. .name = "bcm74110-mbox",
  531. .of_match_table = bcm74110_mbox_of_match,
  532. },
  533. .probe = bcm74110_mbox_probe,
  534. .shutdown = bcm74110_mbox_shutdown,
  535. };
  536. module_platform_driver(bcm74110_mbox_driver);
  537. MODULE_AUTHOR("Justin Chen <justin.chen@broadcom.com>");
  538. MODULE_DESCRIPTION("BCM74110 mailbox driver");
  539. MODULE_LICENSE("GPL");