0007-driver-mailbox-Add-mailbox-driver.patch 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. From f7db05ea5fffebed6db6693333a6877aa707b16d Mon Sep 17 00:00:00 2001
  2. From: "shanlong.li" <[email protected]>
  3. Date: Thu, 8 Jun 2023 00:07:15 -0700
  4. Subject: [PATCH 07/55] driver: mailbox: Add mailbox driver
  5. Add mailbox driver.
  6. Signed-off-by: shanlong.li <[email protected]>
  7. Signed-off-by: Hal Feng <[email protected]>
  8. ---
  9. drivers/mailbox/Kconfig | 13 +
  10. drivers/mailbox/Makefile | 4 +
  11. drivers/mailbox/starfive_mailbox-test.c | 405 ++++++++++++++++++++++++
  12. drivers/mailbox/starfive_mailbox.c | 345 ++++++++++++++++++++
  13. 4 files changed, 767 insertions(+)
  14. create mode 100644 drivers/mailbox/starfive_mailbox-test.c
  15. create mode 100644 drivers/mailbox/starfive_mailbox.c
  16. --- a/drivers/mailbox/Kconfig
  17. +++ b/drivers/mailbox/Kconfig
  18. @@ -295,4 +295,17 @@ config QCOM_IPCC
  19. acts as an interrupt controller for receiving interrupts from clients.
  20. Say Y here if you want to build this driver.
  21. +config STARFIVE_MBOX
  22. + tristate "Platform Starfive Mailbox"
  23. + depends on OF
  24. + help
  25. + Say Y here if you want to build a platform specific variant RISCV
  26. + controller driver.
  27. +
  28. +config STARFIVE_MBOX_TEST
  29. + tristate "Starfive Mailbox Test Client"
  30. + depends on OF
  31. + depends on HAS_IOMEM
  32. + help
  33. + Test client to help with testing new Controller driver implementations.
  34. endif
  35. --- a/drivers/mailbox/Makefile
  36. +++ b/drivers/mailbox/Makefile
  37. @@ -64,3 +64,7 @@ obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox
  38. obj-$(CONFIG_QCOM_CPUCP_MBOX) += qcom-cpucp-mbox.o
  39. obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o
  40. +
  41. +obj-$(CONFIG_STARFIVE_MBOX) += starfive_mailbox.o
  42. +ccflags-$(CONFIG_STARFIVE_MBOX) := -Wno-error=missing-prototypes
  43. +obj-$(CONFIG_STARFIVE_MBOX_TEST) += starfive_mailbox-test.o
  44. --- /dev/null
  45. +++ b/drivers/mailbox/starfive_mailbox-test.c
  46. @@ -0,0 +1,405 @@
  47. +// SPDX-License-Identifier: GPL-2.0-or-later
  48. +/*
  49. + * Copyright (C) 2015 ST Microelectronics
  50. + *
  51. + * Author: Lee Jones <[email protected]>
  52. + */
  53. +
  54. +#include <linux/debugfs.h>
  55. +#include <linux/err.h>
  56. +#include <linux/fs.h>
  57. +#include <linux/io.h>
  58. +#include <linux/kernel.h>
  59. +#include <linux/mailbox_client.h>
  60. +#include <linux/module.h>
  61. +#include <linux/of.h>
  62. +#include <linux/platform_device.h>
  63. +#include <linux/poll.h>
  64. +#include <linux/slab.h>
  65. +#include <linux/uaccess.h>
  66. +#include <linux/sched/signal.h>
  67. +
  68. +#include <linux/mailbox_controller.h>
  69. +
  70. +#define MBOX_MAX_SIG_LEN 8
  71. +#define MBOX_MAX_MSG_LEN 16
  72. +#define MBOX_BYTES_PER_LINE 16
  73. +#define MBOX_HEXDUMP_LINE_LEN ((MBOX_BYTES_PER_LINE * 4) + 2)
  74. +#define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE))
  75. +
  76. +static bool mbox_data_ready;
  77. +
  78. +struct mbox_test_device {
  79. + struct device *dev;
  80. + void __iomem *tx_mmio;
  81. + void __iomem *rx_mmio;
  82. + struct mbox_chan *tx_channel;
  83. + struct mbox_chan *rx_channel;
  84. + char *rx_buffer;
  85. + char *signal;
  86. + char *message;
  87. + spinlock_t lock;
  88. + wait_queue_head_t waitq;
  89. + struct fasync_struct *async_queue;
  90. + struct dentry *root_debugfs_dir;
  91. +};
  92. +
  93. +static ssize_t mbox_test_signal_write(struct file *filp,
  94. + const char __user *userbuf,
  95. + size_t count, loff_t *ppos)
  96. +{
  97. + struct mbox_test_device *tdev = filp->private_data;
  98. +
  99. + if (!tdev->tx_channel) {
  100. + dev_err(tdev->dev, "Channel cannot do Tx\n");
  101. + return -EINVAL;
  102. + }
  103. +
  104. + if (count > MBOX_MAX_SIG_LEN) {
  105. + dev_err(tdev->dev,
  106. + "Signal length %zd greater than max allowed %d\n",
  107. + count, MBOX_MAX_SIG_LEN);
  108. + return -EINVAL;
  109. + }
  110. +
  111. + /* Only allocate memory if we need to */
  112. + if (!tdev->signal) {
  113. + tdev->signal = kzalloc(MBOX_MAX_SIG_LEN, GFP_KERNEL);
  114. + if (!tdev->signal)
  115. + return -ENOMEM;
  116. + }
  117. +
  118. + if (copy_from_user(tdev->signal, userbuf, count)) {
  119. + kfree(tdev->signal);
  120. + tdev->signal = NULL;
  121. + return -EFAULT;
  122. + }
  123. +
  124. + return count;
  125. +}
  126. +
  127. +static const struct file_operations mbox_test_signal_ops = {
  128. + .write = mbox_test_signal_write,
  129. + .open = simple_open,
  130. + .llseek = generic_file_llseek,
  131. +};
  132. +
  133. +static int mbox_test_message_fasync(int fd, struct file *filp, int on)
  134. +{
  135. + struct mbox_test_device *tdev = filp->private_data;
  136. +
  137. + return fasync_helper(fd, filp, on, &tdev->async_queue);
  138. +}
  139. +
  140. +static ssize_t mbox_test_message_write(struct file *filp,
  141. + const char __user *userbuf,
  142. + size_t count, loff_t *ppos)
  143. +{
  144. + struct mbox_test_device *tdev = filp->private_data;
  145. + void *data;
  146. + int ret;
  147. +
  148. + if (!tdev->tx_channel) {
  149. + dev_err(tdev->dev, "Channel cannot do Tx\n");
  150. + return -EINVAL;
  151. + }
  152. +
  153. + if (count > MBOX_MAX_MSG_LEN) {
  154. + dev_err(tdev->dev,
  155. + "Message length %zd greater than max allowed %d\n",
  156. + count, MBOX_MAX_MSG_LEN);
  157. + return -EINVAL;
  158. + }
  159. +
  160. + tdev->message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL);
  161. + if (!tdev->message)
  162. + return -ENOMEM;
  163. +
  164. + ret = copy_from_user(tdev->message, userbuf, count);
  165. + if (ret) {
  166. + ret = -EFAULT;
  167. + goto out;
  168. + }
  169. +
  170. + if (tdev->tx_mmio && tdev->signal) {
  171. + print_hex_dump_bytes("Client: Sending: Signal: ", DUMP_PREFIX_ADDRESS,
  172. + tdev->signal, MBOX_MAX_SIG_LEN);
  173. +
  174. + data = tdev->signal;
  175. + } else
  176. + data = tdev->message;
  177. +
  178. + print_hex_dump_bytes("Client: Sending: Message: ", DUMP_PREFIX_ADDRESS,
  179. + tdev->message, MBOX_MAX_MSG_LEN);
  180. +
  181. + ret = mbox_send_message(tdev->tx_channel, data);
  182. + mbox_chan_txdone(tdev->tx_channel, ret);
  183. + if (ret < 0)
  184. + dev_err(tdev->dev, "Failed to send message via mailbox\n");
  185. +
  186. +out:
  187. + kfree(tdev->signal);
  188. + kfree(tdev->message);
  189. + tdev->signal = NULL;
  190. +
  191. + return ret < 0 ? ret : count;
  192. +}
  193. +
  194. +static bool mbox_test_message_data_ready(struct mbox_test_device *tdev)
  195. +{
  196. + bool data_ready;
  197. + unsigned long flags;
  198. +
  199. + spin_lock_irqsave(&tdev->lock, flags);
  200. + data_ready = mbox_data_ready;
  201. + spin_unlock_irqrestore(&tdev->lock, flags);
  202. +
  203. + return data_ready;
  204. +}
  205. +
  206. +static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
  207. + size_t count, loff_t *ppos)
  208. +{
  209. + struct mbox_test_device *tdev = filp->private_data;
  210. + unsigned long flags;
  211. + char *touser, *ptr;
  212. + int ret;
  213. +
  214. + touser = kzalloc(MBOX_HEXDUMP_MAX_LEN + 1, GFP_KERNEL);
  215. + if (!touser)
  216. + return -ENOMEM;
  217. +
  218. + if (!tdev->rx_channel) {
  219. + ret = snprintf(touser, 20, "<NO RX CAPABILITY>\n");
  220. + ret = simple_read_from_buffer(userbuf, count, ppos,
  221. + touser, ret);
  222. + goto kfree_err;
  223. + }
  224. +
  225. + do {
  226. + if (mbox_test_message_data_ready(tdev))
  227. + break;
  228. +
  229. + if (filp->f_flags & O_NONBLOCK) {
  230. + ret = -EAGAIN;
  231. + goto waitq_err;
  232. + }
  233. +
  234. + if (signal_pending(current)) {
  235. + ret = -ERESTARTSYS;
  236. + goto waitq_err;
  237. + }
  238. + schedule();
  239. +
  240. + } while (1);
  241. +
  242. + spin_lock_irqsave(&tdev->lock, flags);
  243. +
  244. + ptr = tdev->rx_buffer;
  245. +
  246. + mbox_data_ready = false;
  247. +
  248. + spin_unlock_irqrestore(&tdev->lock, flags);
  249. + if (copy_to_user((void __user *)userbuf, ptr, 4))
  250. + ret = -EFAULT;
  251. +
  252. +waitq_err:
  253. + __set_current_state(TASK_RUNNING);
  254. +kfree_err:
  255. + kfree(touser);
  256. + return ret;
  257. +}
  258. +
  259. +static __poll_t
  260. +mbox_test_message_poll(struct file *filp, struct poll_table_struct *wait)
  261. +{
  262. + struct mbox_test_device *tdev = filp->private_data;
  263. +
  264. + poll_wait(filp, &tdev->waitq, wait);
  265. +
  266. + if (mbox_test_message_data_ready(tdev))
  267. + return EPOLLIN | EPOLLRDNORM;
  268. + return 0;
  269. +}
  270. +
  271. +static const struct file_operations mbox_test_message_ops = {
  272. + .write = mbox_test_message_write,
  273. + .read = mbox_test_message_read,
  274. + .fasync = mbox_test_message_fasync,
  275. + .poll = mbox_test_message_poll,
  276. + .open = simple_open,
  277. + .llseek = generic_file_llseek,
  278. +};
  279. +
  280. +static int mbox_test_add_debugfs(struct platform_device *pdev,
  281. + struct mbox_test_device *tdev)
  282. +{
  283. + if (!debugfs_initialized())
  284. + return 0;
  285. +
  286. + tdev->root_debugfs_dir = debugfs_create_dir(dev_name(&pdev->dev), NULL);
  287. + if (!tdev->root_debugfs_dir) {
  288. + dev_err(&pdev->dev, "Failed to create Mailbox debugfs\n");
  289. + return -EINVAL;
  290. + }
  291. +
  292. + debugfs_create_file("message", 0600, tdev->root_debugfs_dir,
  293. + tdev, &mbox_test_message_ops);
  294. +
  295. + debugfs_create_file("signal", 0200, tdev->root_debugfs_dir,
  296. + tdev, &mbox_test_signal_ops);
  297. +
  298. + return 0;
  299. +}
  300. +
  301. +static void mbox_test_receive_message(struct mbox_client *client, void *message)
  302. +{
  303. + struct mbox_test_device *tdev = dev_get_drvdata(client->dev);
  304. + unsigned long flags;
  305. +
  306. + spin_lock_irqsave(&tdev->lock, flags);
  307. + if (tdev->rx_mmio) {
  308. + memcpy_fromio(tdev->rx_buffer, tdev->rx_mmio, MBOX_MAX_MSG_LEN);
  309. + print_hex_dump_bytes("Client: Received [MMIO]: ", DUMP_PREFIX_ADDRESS,
  310. + tdev->rx_buffer, MBOX_MAX_MSG_LEN);
  311. + } else if (message) {
  312. + print_hex_dump_bytes("Client: Received [API]: ", DUMP_PREFIX_ADDRESS,
  313. + message, MBOX_MAX_MSG_LEN);
  314. + memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN);
  315. + }
  316. + mbox_data_ready = true;
  317. + spin_unlock_irqrestore(&tdev->lock, flags);
  318. +}
  319. +
  320. +static void mbox_test_prepare_message(struct mbox_client *client, void *message)
  321. +{
  322. + struct mbox_test_device *tdev = dev_get_drvdata(client->dev);
  323. +
  324. + if (tdev->tx_mmio) {
  325. + if (tdev->signal)
  326. + memcpy_toio(tdev->tx_mmio, tdev->message, MBOX_MAX_MSG_LEN);
  327. + else
  328. + memcpy_toio(tdev->tx_mmio, message, MBOX_MAX_MSG_LEN);
  329. + }
  330. +}
  331. +
  332. +static struct mbox_chan *
  333. +mbox_test_request_channel(struct platform_device *pdev, const char *name)
  334. +{
  335. + struct mbox_client *client;
  336. + struct mbox_chan *channel;
  337. +
  338. + client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL);
  339. + if (!client)
  340. + return ERR_PTR(-ENOMEM);
  341. +
  342. + client->dev = &pdev->dev;
  343. + client->rx_callback = mbox_test_receive_message;
  344. + client->tx_prepare = mbox_test_prepare_message;
  345. + client->tx_block = false;
  346. + client->knows_txdone = false;
  347. + client->tx_tout = 500;
  348. +
  349. + channel = mbox_request_channel_byname(client, name);
  350. + if (IS_ERR(channel)) {
  351. + dev_warn(&pdev->dev, "Failed to request %s channel\n", name);
  352. + return NULL;
  353. + }
  354. +
  355. + return channel;
  356. +}
  357. +
  358. +static int mbox_test_probe(struct platform_device *pdev)
  359. +{
  360. + struct mbox_test_device *tdev;
  361. + struct resource *res;
  362. + resource_size_t size;
  363. + int ret;
  364. +
  365. + tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL);
  366. + if (!tdev)
  367. + return -ENOMEM;
  368. +
  369. + /* It's okay for MMIO to be NULL */
  370. + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  371. + tdev->tx_mmio = devm_ioremap_resource(&pdev->dev, res);
  372. + if (PTR_ERR(tdev->tx_mmio) == -EBUSY) {
  373. + /* if reserved area in SRAM, try just ioremap */
  374. + size = resource_size(res);
  375. + tdev->tx_mmio = devm_ioremap(&pdev->dev, res->start, size);
  376. + } else if (IS_ERR(tdev->tx_mmio)) {
  377. + tdev->tx_mmio = NULL;
  378. + }
  379. +
  380. + /* If specified, second reg entry is Rx MMIO */
  381. + res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
  382. + tdev->rx_mmio = devm_ioremap_resource(&pdev->dev, res);
  383. + if (PTR_ERR(tdev->rx_mmio) == -EBUSY) {
  384. + size = resource_size(res);
  385. + tdev->rx_mmio = devm_ioremap(&pdev->dev, res->start, size);
  386. + } else if (IS_ERR(tdev->rx_mmio)) {
  387. + tdev->rx_mmio = tdev->tx_mmio;
  388. + }
  389. +
  390. + tdev->tx_channel = mbox_test_request_channel(pdev, "tx");
  391. + tdev->rx_channel = mbox_test_request_channel(pdev, "rx");
  392. +
  393. + if (!tdev->tx_channel && !tdev->rx_channel)
  394. + return -EPROBE_DEFER;
  395. +
  396. + /* If Rx is not specified but has Rx MMIO, then Rx = Tx */
  397. + if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio))
  398. + tdev->rx_channel = tdev->tx_channel;
  399. +
  400. + tdev->dev = &pdev->dev;
  401. + platform_set_drvdata(pdev, tdev);
  402. +
  403. + spin_lock_init(&tdev->lock);
  404. +
  405. + if (tdev->rx_channel) {
  406. + tdev->rx_buffer = devm_kzalloc(&pdev->dev,
  407. + MBOX_MAX_MSG_LEN, GFP_KERNEL);
  408. + if (!tdev->rx_buffer)
  409. + return -ENOMEM;
  410. + }
  411. +
  412. + ret = mbox_test_add_debugfs(pdev, tdev);
  413. + if (ret)
  414. + return ret;
  415. +
  416. + dev_info(&pdev->dev, "Successfully registered\n");
  417. +
  418. + return 0;
  419. +}
  420. +
  421. +static void mbox_test_remove(struct platform_device *pdev)
  422. +{
  423. + struct mbox_test_device *tdev = platform_get_drvdata(pdev);
  424. +
  425. + debugfs_remove_recursive(tdev->root_debugfs_dir);
  426. +
  427. + if (tdev->tx_channel)
  428. + mbox_free_channel(tdev->tx_channel);
  429. + if (tdev->rx_channel)
  430. + mbox_free_channel(tdev->rx_channel);
  431. +}
  432. +
  433. +static const struct of_device_id mbox_test_match[] = {
  434. + { .compatible = "starfive,mailbox-test" },
  435. + {},
  436. +};
  437. +MODULE_DEVICE_TABLE(of, mbox_test_match);
  438. +
  439. +static struct platform_driver mbox_test_driver = {
  440. + .driver = {
  441. + .name = "mailbox_test",
  442. + .of_match_table = mbox_test_match,
  443. + },
  444. + .probe = mbox_test_probe,
  445. + .remove = mbox_test_remove,
  446. +};
  447. +module_platform_driver(mbox_test_driver);
  448. +
  449. +MODULE_DESCRIPTION("Generic Mailbox Testing Facility");
  450. +MODULE_AUTHOR("Lee Jones <[email protected]");
  451. +MODULE_LICENSE("GPL v2");
  452. --- /dev/null
  453. +++ b/drivers/mailbox/starfive_mailbox.c
  454. @@ -0,0 +1,345 @@
  455. +// SPDX-License-Identifier: GPL-2.0
  456. +/*
  457. + * mailbox driver for StarFive JH7110 SoC
  458. + *
  459. + * Copyright (c) 2021 StarFive Technology Co., Ltd.
  460. + * Author: Shanlong Li <[email protected]>
  461. + */
  462. +
  463. +#include <linux/bitops.h>
  464. +#include <linux/delay.h>
  465. +#include <linux/device.h>
  466. +#include <linux/err.h>
  467. +#include <linux/interrupt.h>
  468. +#include <linux/io.h>
  469. +#include <linux/iopoll.h>
  470. +#include <linux/mailbox_controller.h>
  471. +#include <linux/module.h>
  472. +#include <linux/platform_device.h>
  473. +#include <linux/slab.h>
  474. +#include <linux/clk.h>
  475. +#include <linux/reset.h>
  476. +#include <linux/pm_runtime.h>
  477. +
  478. +#include "mailbox.h"
  479. +
  480. +#define MBOX_CHAN_MAX 4
  481. +
  482. +#define MBOX_BASE(mbox, ch) ((mbox)->base + ((ch) * 0x10))
  483. +#define MBOX_IRQ_REG 0x00
  484. +#define MBOX_SET_REG 0x04
  485. +#define MBOX_CLR_REG 0x08
  486. +#define MBOX_CMD_REG 0x0c
  487. +#define MBC_PEND_SMRY 0x100
  488. +
  489. +typedef enum {
  490. + MAILBOX_CORE_U7 = 0,
  491. + MAILBOX_CORE_HIFI4,
  492. + MAILBOX_CORE_E2,
  493. + MAILBOX_CORE_RSVD0,
  494. + MAILBOX_CORE_NUM,
  495. +} mailbox_core_t;
  496. +
  497. +struct mailbox_irq_name_c{
  498. + int id;
  499. + char name[16];
  500. +};
  501. +
  502. +static const struct mailbox_irq_name_c irq_peer_name[MBOX_CHAN_MAX] = {
  503. + {MAILBOX_CORE_U7, "u74_core"},
  504. + {MAILBOX_CORE_HIFI4, "hifi4_core"},
  505. + {MAILBOX_CORE_E2, "e24_core"},
  506. + {MAILBOX_CORE_RSVD0, "" },
  507. +};
  508. +
  509. +/**
  510. + * starfive mailbox channel information
  511. + *
  512. + * A channel can be used for TX or RX, it can trigger remote
  513. + * processor interrupt to notify remote processor and can receive
  514. + * interrupt if has incoming message.
  515. + *
  516. + * @dst_irq: Interrupt vector for remote processor
  517. + * @core_id: id for remote processor
  518. + */
  519. +struct starfive_chan_info {
  520. + unsigned int dst_irq;
  521. + mailbox_core_t core_id;
  522. +};
  523. +
  524. +/**
  525. + * starfive mailbox controller data
  526. + *
  527. + * Mailbox controller includes 4 channels and can allocate
  528. + * channel for message transferring.
  529. + *
  530. + * @dev: Device to which it is attached
  531. + * @base: Base address of the register mapping region
  532. + * @chan: Representation of channels in mailbox controller
  533. + * @mchan: Representation of channel info
  534. + * @controller: Representation of a communication channel controller
  535. + */
  536. +struct starfive_mbox {
  537. + struct device *dev;
  538. + void __iomem *base;
  539. + struct mbox_chan chan[MBOX_CHAN_MAX];
  540. + struct starfive_chan_info mchan[MBOX_CHAN_MAX];
  541. + struct mbox_controller controller;
  542. + struct clk *clk;
  543. + struct reset_control *rst_rresetn;
  544. +};
  545. +
  546. +static struct starfive_mbox *to_starfive_mbox(struct mbox_controller *mbox)
  547. +{
  548. + return container_of(mbox, struct starfive_mbox, controller);
  549. +}
  550. +
  551. +static struct mbox_chan *
  552. +starfive_of_mbox_index_xlate(struct mbox_controller *mbox,
  553. + const struct of_phandle_args *sp)
  554. +{
  555. + struct starfive_mbox *sbox;
  556. +
  557. + int ind = sp->args[0];
  558. + int core_id = sp->args[1];
  559. +
  560. + if (ind >= mbox->num_chans || core_id >= MAILBOX_CORE_NUM)
  561. + return ERR_PTR(-EINVAL);
  562. +
  563. + sbox = to_starfive_mbox(mbox);
  564. +
  565. + sbox->mchan[ind].core_id = core_id;
  566. +
  567. + return &mbox->chans[ind];
  568. +}
  569. +
  570. +static irqreturn_t starfive_rx_irq_handler(int irq, void *p)
  571. +{
  572. + struct mbox_chan *chan = p;
  573. + unsigned long ch = (unsigned long)chan->con_priv;
  574. + struct starfive_mbox *mbox = to_starfive_mbox(chan->mbox);
  575. + void __iomem *base = MBOX_BASE(mbox, ch);
  576. + u32 val;
  577. +
  578. + val = readl(base + MBOX_CMD_REG);
  579. + if (!val)
  580. + return IRQ_NONE;
  581. +
  582. + mbox_chan_received_data(chan, (void *)&val);
  583. + writel(val, base + MBOX_CLR_REG);
  584. + return IRQ_HANDLED;
  585. +}
  586. +
  587. +static int starfive_mbox_check_state(struct mbox_chan *chan)
  588. +{
  589. + unsigned long ch = (unsigned long)chan->con_priv;
  590. + struct starfive_mbox *mbox = to_starfive_mbox(chan->mbox);
  591. + unsigned long irq_flag = IRQF_SHARED;
  592. + long ret = 0;
  593. +
  594. + pm_runtime_get_sync(mbox->dev);
  595. + /* MAILBOX should be with IRQF_NO_SUSPEND set */
  596. + if (!mbox->dev->pm_domain)
  597. + irq_flag |= IRQF_NO_SUSPEND;
  598. +
  599. + /* Mailbox is idle so directly bail out */
  600. + if (readl(mbox->base + MBC_PEND_SMRY) & BIT(ch))
  601. + return -EBUSY;
  602. +
  603. + if (mbox->mchan[ch].dst_irq > 0) {
  604. + dev_dbg(mbox->dev, "%s: host IRQ = %d, ch:%ld", __func__, mbox->mchan[ch].dst_irq, ch);
  605. + ret = devm_request_irq(mbox->dev, mbox->mchan[ch].dst_irq, starfive_rx_irq_handler,
  606. + irq_flag, irq_peer_name[ch].name, chan);
  607. + if (ret < 0)
  608. + dev_err(mbox->dev, "request_irq %d failed\n", mbox->mchan[ch].dst_irq);
  609. + }
  610. +
  611. + return ret;
  612. +}
  613. +
  614. +static int starfive_mbox_startup(struct mbox_chan *chan)
  615. +{
  616. + return starfive_mbox_check_state(chan);
  617. +}
  618. +
  619. +static void starfive_mbox_shutdown(struct mbox_chan *chan)
  620. +{
  621. + struct starfive_mbox *mbox = to_starfive_mbox(chan->mbox);
  622. + unsigned long ch = (unsigned long)chan->con_priv;
  623. + void __iomem *base = MBOX_BASE(mbox, ch);
  624. +
  625. + writel(0x0, base + MBOX_IRQ_REG);
  626. + writel(0x0, base + MBOX_CLR_REG);
  627. +
  628. + if (mbox->mchan[ch].dst_irq > 0)
  629. + devm_free_irq(mbox->dev, mbox->mchan[ch].dst_irq, chan);
  630. + pm_runtime_put_sync(mbox->dev);
  631. +}
  632. +
  633. +static int starfive_mbox_send_data(struct mbox_chan *chan, void *msg)
  634. +{
  635. + unsigned long ch = (unsigned long)chan->con_priv;
  636. + struct starfive_mbox *mbox = to_starfive_mbox(chan->mbox);
  637. + struct starfive_chan_info *mchan = &mbox->mchan[ch];
  638. + void __iomem *base = MBOX_BASE(mbox, ch);
  639. + u32 *buf = msg;
  640. +
  641. + /* Ensure channel is released */
  642. + if (readl(mbox->base + MBC_PEND_SMRY) & BIT(ch)) {
  643. + pr_debug("%s:%d. busy\n", __func__, __LINE__);
  644. + return -EBUSY;
  645. + }
  646. +
  647. + /* Clear mask for destination interrupt */
  648. + writel(BIT(mchan->core_id), base + MBOX_IRQ_REG);
  649. +
  650. + /* Fill message data */
  651. + writel(*buf, base + MBOX_SET_REG);
  652. + return 0;
  653. +}
  654. +
  655. +static struct mbox_chan_ops starfive_mbox_ops = {
  656. + .startup = starfive_mbox_startup,
  657. + .send_data = starfive_mbox_send_data,
  658. + .shutdown = starfive_mbox_shutdown,
  659. +};
  660. +
  661. +static const struct of_device_id starfive_mbox_of_match[] = {
  662. + { .compatible = "starfive,mail_box",},
  663. + {},
  664. +};
  665. +
  666. +MODULE_DEVICE_TABLE(of, starfive_mbox_of_match);
  667. +
  668. +void starfive_mailbox_init(struct starfive_mbox *mbox)
  669. +{
  670. + mbox->clk = devm_clk_get_optional(mbox->dev, "clk_apb");
  671. + if (IS_ERR(mbox->clk)) {
  672. + dev_err(mbox->dev, "failed to get mailbox\n");
  673. + return;
  674. + }
  675. +
  676. + mbox->rst_rresetn = devm_reset_control_get_exclusive(mbox->dev, "mbx_rre");
  677. + if (IS_ERR(mbox->rst_rresetn)) {
  678. + dev_err(mbox->dev, "failed to get mailbox reset\n");
  679. + return;
  680. + }
  681. +
  682. + clk_prepare_enable(mbox->clk);
  683. + reset_control_deassert(mbox->rst_rresetn);
  684. +}
  685. +
  686. +static int starfive_mbox_probe(struct platform_device *pdev)
  687. +{
  688. + struct device *dev = &pdev->dev;
  689. + struct starfive_mbox *mbox;
  690. + struct mbox_chan *chan;
  691. + struct resource *res;
  692. + unsigned long ch;
  693. + int err;
  694. +
  695. + mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
  696. + if (!mbox)
  697. + return -ENOMEM;
  698. +
  699. + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  700. + mbox->base = devm_ioremap_resource(dev, res);
  701. + mbox->dev = dev;
  702. +
  703. + if (IS_ERR(mbox->base))
  704. + return PTR_ERR(mbox->base);
  705. +
  706. + starfive_mailbox_init(mbox);
  707. +
  708. + mbox->controller.dev = dev;
  709. + mbox->controller.chans = mbox->chan;
  710. + mbox->controller.num_chans = MBOX_CHAN_MAX;
  711. + mbox->controller.ops = &starfive_mbox_ops;
  712. + mbox->controller.of_xlate = starfive_of_mbox_index_xlate;
  713. + mbox->controller.txdone_irq = true;
  714. + mbox->controller.txdone_poll = false;
  715. +
  716. + /* Initialize mailbox channel data */
  717. + chan = mbox->chan;
  718. + for (ch = 0; ch < MBOX_CHAN_MAX; ch++) {
  719. + mbox->mchan[ch].dst_irq = 0;
  720. + mbox->mchan[ch].core_id = (mailbox_core_t)ch;
  721. + chan[ch].con_priv = (void *)ch;
  722. + }
  723. + mbox->mchan[MAILBOX_CORE_HIFI4].dst_irq = platform_get_irq(pdev, 0);
  724. + mbox->mchan[MAILBOX_CORE_E2].dst_irq = platform_get_irq(pdev, 1);
  725. +
  726. + err = mbox_controller_register(&mbox->controller);
  727. + if (err) {
  728. + dev_err(dev, "Failed to register mailbox %d\n", err);
  729. + return err;
  730. + }
  731. +
  732. + platform_set_drvdata(pdev, mbox);
  733. + dev_info(dev, "Mailbox enabled\n");
  734. + pm_runtime_set_active(dev);
  735. + pm_runtime_enable(dev);
  736. +
  737. + return 0;
  738. +}
  739. +
  740. +static void starfive_mbox_remove(struct platform_device *pdev)
  741. +{
  742. + struct starfive_mbox *mbox = platform_get_drvdata(pdev);
  743. +
  744. + mbox_controller_unregister(&mbox->controller);
  745. + devm_clk_put(mbox->dev, mbox->clk);
  746. + pm_runtime_disable(mbox->dev);
  747. +}
  748. +
  749. +static int __maybe_unused starfive_mbox_suspend(struct device *dev)
  750. +{
  751. + struct starfive_mbox *mbox = dev_get_drvdata(dev);
  752. +
  753. + clk_disable_unprepare(mbox->clk);
  754. +
  755. + return 0;
  756. +}
  757. +
  758. +static int __maybe_unused starfive_mbox_resume(struct device *dev)
  759. +{
  760. + struct starfive_mbox *mbox = dev_get_drvdata(dev);
  761. + int ret;
  762. +
  763. + ret = clk_prepare_enable(mbox->clk);
  764. + if (ret)
  765. + dev_err(dev, "failed to enable clock\n");
  766. +
  767. + return ret;
  768. +}
  769. +
  770. +static const struct dev_pm_ops starfive_mbox_pm_ops = {
  771. + .suspend = starfive_mbox_suspend,
  772. + .resume = starfive_mbox_resume,
  773. + SET_RUNTIME_PM_OPS(starfive_mbox_suspend, starfive_mbox_resume, NULL)
  774. +};
  775. +static struct platform_driver starfive_mbox_driver = {
  776. + .probe = starfive_mbox_probe,
  777. + .remove = starfive_mbox_remove,
  778. + .driver = {
  779. + .name = "mailbox",
  780. + .of_match_table = starfive_mbox_of_match,
  781. + .pm = &starfive_mbox_pm_ops,
  782. + },
  783. +};
  784. +
  785. +static int __init starfive_mbox_init(void)
  786. +{
  787. + return platform_driver_register(&starfive_mbox_driver);
  788. +}
  789. +core_initcall(starfive_mbox_init);
  790. +
  791. +static void __exit starfive_mbox_exit(void)
  792. +{
  793. + platform_driver_unregister(&starfive_mbox_driver);
  794. +}
  795. +module_exit(starfive_mbox_exit);
  796. +
  797. +MODULE_DESCRIPTION("StarFive Mailbox Controller driver");
  798. +MODULE_AUTHOR("Shanlong Li <[email protected]>");
  799. +MODULE_LICENSE("GPL");