Add the MediaTek TinySYS mailbox, used for IPC with the TinySYS
MCU that is integrated in variousSoCs, enabling communication
with remote processors that use the MediaTek IPIC framework
through the TinySYS SCMI protocol.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/mailbox/Kconfig | 9 ++
drivers/mailbox/Makefile | 2 +
drivers/mailbox/mtk-tinysys-mailbox.c | 196 ++++++++++++++++++++++++++
3 files changed, 207 insertions(+)
create mode 100644 drivers/mailbox/mtk-tinysys-mailbox.c
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index 68eeed660a4a..35149110cb3a 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -285,6 +285,15 @@ config MTK_CMDQ_MBOX
critical time limitation, such as updating display configuration
during the vblank.
+config MTK_TINYSYS_MBOX
+ tristate "MediaTek TINYSYS Mailbox Support"
+ depends on ARCH_MEDIATEK || COMPILE_TEST
+ help
+ The MediaTek TinySYS mailbox is used to communicate with remote
+ processors based on the MediaTek IPIC framework.
+ Say yes here to add support for the MediaTek TinySYS mailbox
+ driver.
+
config ZYNQMP_IPI_MBOX
tristate "Xilinx ZynqMP IPI Mailbox"
depends on ARCH_ZYNQMP && OF
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index 13a3448b3271..415eb1d9ed47 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -61,6 +61,8 @@ obj-$(CONFIG_MTK_ADSP_MBOX) += mtk-adsp-mailbox.o
obj-$(CONFIG_MTK_CMDQ_MBOX) += mtk-cmdq-mailbox.o
+obj-$(CONFIG_MTK_TINYSYS_MBOX) += mtk-tinysys-mailbox.o
+
obj-$(CONFIG_ZYNQMP_IPI_MBOX) += zynqmp-ipi-mailbox.o
obj-$(CONFIG_SUN6I_MSGBOX) += sun6i-msgbox.o
diff --git a/drivers/mailbox/mtk-tinysys-mailbox.c b/drivers/mailbox/mtk-tinysys-mailbox.c
new file mode 100644
index 000000000000..ec84951230e6
--- /dev/null
+++ b/drivers/mailbox/mtk-tinysys-mailbox.c
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ * Copyright (c) 2025 Collabora Ltd
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mailbox_controller.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/soc/mediatek/mtk_sip_svc.h>
+
+#define MTK_SIP_TINYSYS_SSPM_CONTROL MTK_SIP_SMC_CMD(0x53c)
+#define MTK_TINYSYS_SSPM_OP_MBOX_CLR 0
+#define MTK_TINYSYS_SSPM_OP_MD2SPM_CLR 1
+
+#define INTR_SET_OFS 0x0
+#define INTR_CLR_OFS 0x4
+
+struct mtk_tinysys_mhu_mbox_pdata {
+ bool is_secure_mbox;
+ bool notify_spm;
+};
+
+struct mtk_tinysys_mhu_mbox {
+ void __iomem *base;
+ int irq;
+ const struct mtk_tinysys_mhu_mbox_pdata *pdata;
+ struct mbox_controller mbox;
+};
+
+static inline struct mtk_tinysys_mhu_mbox *to_mtk_tinysys_mhu_mbox(struct mbox_controller *mbox)
+{
+ return container_of(mbox, struct mtk_tinysys_mhu_mbox, mbox);
+}
+
+static irqreturn_t mtk_tinysys_mhu_mbox_irq(int irq, void *data)
+{
+ u32 val;
+ struct arm_smccc_res res;
+ struct mbox_chan *chan = data;
+ struct mtk_tinysys_mhu_mbox *priv = to_mtk_tinysys_mhu_mbox(chan->mbox);
+
+ val = readl_relaxed(priv->base + INTR_CLR_OFS);
+ if (!val)
+ return IRQ_NONE;
+
+ if (priv->pdata->is_secure_mbox) {
+ /* Can't fail: ignore res.a0 checks */
+ arm_smccc_smc(MTK_SIP_TINYSYS_SSPM_CONTROL,
+ MTK_TINYSYS_SSPM_OP_MBOX_CLR,
+ priv->irq, 0, 0, 0, 0, 0, &res);
+ } else {
+ writel(1, priv->base + INTR_CLR_OFS);
+ }
+
+ mbox_chan_received_data(chan, (void *)&val);
+
+ if (priv->pdata->notify_spm)
+ arm_smccc_smc(MTK_SIP_TINYSYS_SSPM_CONTROL,
+ MTK_TINYSYS_SSPM_OP_MD2SPM_CLR,
+ priv->irq, 0, 0, 0, 0, 0, &res);
+ return IRQ_HANDLED;
+}
+
+static bool mtk_tinysys_mhu_mbox_last_tx_done(struct mbox_chan *chan)
+{
+ struct mtk_tinysys_mhu_mbox *priv = to_mtk_tinysys_mhu_mbox(chan->mbox);
+ u32 val = readl_relaxed(priv->base + INTR_SET_OFS);
+
+ return val == 0;
+}
+
+static int mtk_tinysys_mhu_mbox_send_data(struct mbox_chan *chan, void *data)
+{
+ struct mtk_tinysys_mhu_mbox *priv = to_mtk_tinysys_mhu_mbox(chan->mbox);
+ u32 *arg = data;
+
+ writel_relaxed(*arg, priv->base + INTR_SET_OFS);
+
+ return 0;
+}
+
+static int mtk_tinysys_mhu_mbox_startup(struct mbox_chan *chan)
+{
+ struct mtk_tinysys_mhu_mbox *priv = to_mtk_tinysys_mhu_mbox(chan->mbox);
+
+ irq_clear_status_flags(priv->irq, IRQ_NOAUTOEN);
+ enable_irq(priv->irq);
+
+ return 0;
+}
+
+static void mtk_tinysys_mhu_mbox_shutdown(struct mbox_chan *chan)
+{
+ struct mtk_tinysys_mhu_mbox *priv = to_mtk_tinysys_mhu_mbox(chan->mbox);
+
+ disable_irq(priv->irq);
+}
+
+static const struct mbox_chan_ops tinysys_mbox_chan_ops = {
+ .send_data = mtk_tinysys_mhu_mbox_send_data,
+ .startup = mtk_tinysys_mhu_mbox_startup,
+ .shutdown = mtk_tinysys_mhu_mbox_shutdown,
+ .last_tx_done = mtk_tinysys_mhu_mbox_last_tx_done,
+};
+
+static int mtk_tinysys_mhu_mbox_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mtk_tinysys_mhu_mbox *priv;
+ struct mbox_controller *mbox;
+ int ret;
+
+ /* Allocate memory for device */
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ priv->irq = platform_get_irq(pdev, 0);
+ if (priv->irq < 0)
+ return priv->irq;
+
+ priv->pdata = device_get_match_data(dev);
+ if (!priv->pdata)
+ return -EINVAL;
+
+ mbox = &priv->mbox;
+ mbox->dev = dev;
+ mbox->ops = &tinysys_mbox_chan_ops;
+ mbox->txdone_irq = false;
+ mbox->txdone_poll = true;
+ mbox->txpoll_period = 1;
+ mbox->num_chans = 1;
+ mbox->chans = devm_kzalloc(dev, sizeof(*mbox->chans), GFP_KERNEL);
+ if (!mbox->chans)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, priv);
+
+ irq_set_status_flags(priv->irq, IRQ_NOAUTOEN);
+ ret = devm_request_irq(dev, priv->irq, mtk_tinysys_mhu_mbox_irq,
+ IRQF_TRIGGER_NONE, dev_name(dev), mbox->chans);
+ if (ret < 0)
+ return ret;
+
+ ret = devm_mbox_controller_register(dev, &priv->mbox);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register mailbox\n");
+
+ return 0;
+}
+
+static const struct mtk_tinysys_mhu_mbox_pdata mt6985_tsmhu_mbox_cfg = {
+ /* Unsecured mailbox, no SPM notification */
+};
+
+static const struct mtk_tinysys_mhu_mbox_pdata mt6989_tsmhu_mbox_cfg = {
+ .is_secure_mbox = true,
+};
+
+static const struct mtk_tinysys_mhu_mbox_pdata mt8196_tsmhu_mbox_cfg = {
+ .notify_spm = true,
+};
+
+static const struct of_device_id mtk_tinysys_mhu_mbox_of_match[] = {
+ { .compatible = "mediatek,mt6985-tinysys-mhu-mbox", .data = &mt6985_tsmhu_mbox_cfg },
+ { .compatible = "mediatek,mt6989-tinysys-mhu-mbox", .data = &mt6989_tsmhu_mbox_cfg },
+ { .compatible = "mediatek,mt8196-tinysys-mhu-mbox", .data = &mt8196_tsmhu_mbox_cfg },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mtk_tinysys_mhu_mbox_of_match);
+
+static struct platform_driver mtk_tinysys_mhu_mbox_drv = {
+ .probe = mtk_tinysys_mhu_mbox_probe,
+ .driver = {
+ .name = "mtk-tinysys-mhu-mbox",
+ .of_match_table = mtk_tinysys_mhu_mbox_of_match,
+ }
+};
+module_platform_driver(mtk_tinysys_mhu_mbox_drv);
+
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_DESCRIPTION("MediaTek TinySYS Mailbox Controller");
+MODULE_LICENSE("GPL");
--
2.49.0
Hi AngeloGioacchino, kernel test robot noticed the following build errors: [auto build test ERROR on jassibrar-mailbox/for-next] [also build test ERROR on robh/for-next soc/for-next linus/master v6.16-rc3 next-20250623] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/AngeloGioacchino-Del-Regno/dt-bindings-mailbox-Add-MediaTek-TinySYS-MHU-mailbox/20250623-201139 base: https://git.kernel.org/pub/scm/linux/kernel/git/jassibrar/mailbox.git for-next patch link: https://lore.kernel.org/r/20250623120127.109237-3-angelogioacchino.delregno%40collabora.com patch subject: [PATCH v1 2/2] mailbox: Add MediaTek TinySYS MHU-like Mailbox config: i386-allmodconfig (https://download.01.org/0day-ci/archive/20250624/202506241946.HEKwafHB-lkp@intel.com/config) compiler: gcc-12 (Debian 12.2.0-14) 12.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250624/202506241946.HEKwafHB-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202506241946.HEKwafHB-lkp@intel.com/ All errors (new ones prefixed by >>): drivers/mailbox/mtk-tinysys-mailbox.c: In function 'mtk_tinysys_mhu_mbox_startup': >> drivers/mailbox/mtk-tinysys-mailbox.c:95:9: error: implicit declaration of function 'irq_clear_status_flags' [-Werror=implicit-function-declaration] 95 | irq_clear_status_flags(priv->irq, IRQ_NOAUTOEN); | ^~~~~~~~~~~~~~~~~~~~~~ >> drivers/mailbox/mtk-tinysys-mailbox.c:95:43: error: 'IRQ_NOAUTOEN' undeclared (first use in this function); did you mean 'IRQF_NO_AUTOEN'? 95 | irq_clear_status_flags(priv->irq, IRQ_NOAUTOEN); | ^~~~~~~~~~~~ | IRQF_NO_AUTOEN drivers/mailbox/mtk-tinysys-mailbox.c:95:43: note: each undeclared identifier is reported only once for each function it appears in drivers/mailbox/mtk-tinysys-mailbox.c: In function 'mtk_tinysys_mhu_mbox_probe': >> drivers/mailbox/mtk-tinysys-mailbox.c:152:9: error: implicit declaration of function 'irq_set_status_flags' [-Werror=implicit-function-declaration] 152 | irq_set_status_flags(priv->irq, IRQ_NOAUTOEN); | ^~~~~~~~~~~~~~~~~~~~ drivers/mailbox/mtk-tinysys-mailbox.c:152:41: error: 'IRQ_NOAUTOEN' undeclared (first use in this function); did you mean 'IRQF_NO_AUTOEN'? 152 | irq_set_status_flags(priv->irq, IRQ_NOAUTOEN); | ^~~~~~~~~~~~ | IRQF_NO_AUTOEN cc1: some warnings being treated as errors vim +/irq_clear_status_flags +95 drivers/mailbox/mtk-tinysys-mailbox.c 90 91 static int mtk_tinysys_mhu_mbox_startup(struct mbox_chan *chan) 92 { 93 struct mtk_tinysys_mhu_mbox *priv = to_mtk_tinysys_mhu_mbox(chan->mbox); 94 > 95 irq_clear_status_flags(priv->irq, IRQ_NOAUTOEN); 96 enable_irq(priv->irq); 97 98 return 0; 99 } 100 101 static void mtk_tinysys_mhu_mbox_shutdown(struct mbox_chan *chan) 102 { 103 struct mtk_tinysys_mhu_mbox *priv = to_mtk_tinysys_mhu_mbox(chan->mbox); 104 105 disable_irq(priv->irq); 106 } 107 108 static const struct mbox_chan_ops tinysys_mbox_chan_ops = { 109 .send_data = mtk_tinysys_mhu_mbox_send_data, 110 .startup = mtk_tinysys_mhu_mbox_startup, 111 .shutdown = mtk_tinysys_mhu_mbox_shutdown, 112 .last_tx_done = mtk_tinysys_mhu_mbox_last_tx_done, 113 }; 114 115 static int mtk_tinysys_mhu_mbox_probe(struct platform_device *pdev) 116 { 117 struct device *dev = &pdev->dev; 118 struct mtk_tinysys_mhu_mbox *priv; 119 struct mbox_controller *mbox; 120 int ret; 121 122 /* Allocate memory for device */ 123 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 124 if (!priv) 125 return -ENOMEM; 126 127 priv->base = devm_platform_ioremap_resource(pdev, 0); 128 if (IS_ERR(priv->base)) 129 return PTR_ERR(priv->base); 130 131 priv->irq = platform_get_irq(pdev, 0); 132 if (priv->irq < 0) 133 return priv->irq; 134 135 priv->pdata = device_get_match_data(dev); 136 if (!priv->pdata) 137 return -EINVAL; 138 139 mbox = &priv->mbox; 140 mbox->dev = dev; 141 mbox->ops = &tinysys_mbox_chan_ops; 142 mbox->txdone_irq = false; 143 mbox->txdone_poll = true; 144 mbox->txpoll_period = 1; 145 mbox->num_chans = 1; 146 mbox->chans = devm_kzalloc(dev, sizeof(*mbox->chans), GFP_KERNEL); 147 if (!mbox->chans) 148 return -ENOMEM; 149 150 platform_set_drvdata(pdev, priv); 151 > 152 irq_set_status_flags(priv->irq, IRQ_NOAUTOEN); 153 ret = devm_request_irq(dev, priv->irq, mtk_tinysys_mhu_mbox_irq, 154 IRQF_TRIGGER_NONE, dev_name(dev), mbox->chans); 155 if (ret < 0) 156 return ret; 157 158 ret = devm_mbox_controller_register(dev, &priv->mbox); 159 if (ret) 160 return dev_err_probe(dev, ret, "Failed to register mailbox\n"); 161 162 return 0; 163 } 164 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
© 2016 - 2025 Red Hat, Inc.