[PATCH v3 3/3] mailbox: sophgo: add mailbox driver for CV18XX series SoC

Junhui Liu posted 3 patches 9 months, 2 weeks ago
There is a newer version of this series
[PATCH v3 3/3] mailbox: sophgo: add mailbox driver for CV18XX series SoC
Posted by Junhui Liu 9 months, 2 weeks ago
From: Yuntao Dai <d1581209858@live.com>

Add mailbox controller driver for CV18XX SoCs, which provides 8 channels
and each channel has an 8-byte FIFO.

Signed-off-by: Yuntao Dai <d1581209858@live.com>
Signed-off-by: Junhui Liu <junhui.liu@pigmoral.tech>
---
 drivers/mailbox/Kconfig          |  10 ++
 drivers/mailbox/Makefile         |   2 +
 drivers/mailbox/cv1800-mailbox.c | 218 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 230 insertions(+)

diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index ed52db272f4d059ff60d608f40e3845411bc63f7..fd3f28d705bc00166028c372d3398f2e225aa8a7 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -36,6 +36,16 @@ config ARM_MHU_V3
 	  that provides different means of transports: supported extensions
 	  will be discovered and possibly managed at probe-time.
 
+config CV1800_MBOX
+	tristate "cv1800 mailbox"
+	depends on ARCH_SOPHGO || COMPILE_TEST
+	help
+	  Mailbox driver implementation for Sophgo CV18XX SoCs. This driver
+	  can be used to send message between different processors in SoC. Any
+	  processer can write data in a channel, and set co-responding register
+	  to raise interrupt to notice another processor, and it is allowed to
+	  send data to itself.
+
 config EXYNOS_MBOX
 	tristate "Exynos Mailbox"
 	depends on ARCH_EXYNOS || COMPILE_TEST
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index 9a1542b55539c673af874c5c37fbb3d438fd05d3..13a3448b327115add5ebb8c4f116e68dedd755cb 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -11,6 +11,8 @@ obj-$(CONFIG_ARM_MHU_V2)	+= arm_mhuv2.o
 
 obj-$(CONFIG_ARM_MHU_V3)	+= arm_mhuv3.o
 
+obj-$(CONFIG_CV1800_MBOX)	+= cv1800-mailbox.o
+
 obj-$(CONFIG_EXYNOS_MBOX)	+= exynos-mailbox.o
 
 obj-$(CONFIG_IMX_MBOX)	+= imx-mailbox.o
diff --git a/drivers/mailbox/cv1800-mailbox.c b/drivers/mailbox/cv1800-mailbox.c
new file mode 100644
index 0000000000000000000000000000000000000000..339c155fb98ddf4155a84d5208c595043fc7a7ce
--- /dev/null
+++ b/drivers/mailbox/cv1800-mailbox.c
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2024 Sophgo Technology Inc.
+ * Copyright (C) 2024 Yuntao Dai <d1581209858@live.com>
+ * Copyright (C) 2025 Junhui Liu <junhui.liu@pigmoral.tech>
+ */
+
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kfifo.h>
+#include <linux/mailbox_client.h>
+#include <linux/mailbox_controller.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define RECV_CPU		1
+
+#define MAILBOX_MAX_CHAN	8
+
+#define MBOX_EN_REG(cpu)	(cpu << 2)
+#define MBOX_DONE_REG(cpu)	((cpu << 2) + 2)
+#define MBOX_SET_CLR_REG(cpu)	(0x10 + (cpu << 4))
+#define MBOX_SET_INT_REG(cpu)	(0x18 + (cpu << 4))
+#define MBOX_SET_REG		0x60
+
+#define MAILBOX_CONTEXT_OFFSET	0x0400
+#define MAILBOX_CONTEXT_SIZE	0x0040
+
+#define MBOX_CONTEXT_BASE_INDEX(base, index) \
+	((u64 *)(base + MAILBOX_CONTEXT_OFFSET) + index)
+
+/**
+ * struct cv1800_mbox_chan_priv - cv1800 mailbox channel private data
+ * @idx: index of channel
+ * @cpu: send to which processor
+ */
+struct cv1800_mbox_chan_priv {
+	int idx;
+	int cpu;
+};
+
+struct cv1800_mbox {
+	struct mbox_controller mbox;
+	struct cv1800_mbox_chan_priv priv[MAILBOX_MAX_CHAN];
+	struct mbox_chan chans[MAILBOX_MAX_CHAN];
+	u64 __iomem *content[MAILBOX_MAX_CHAN];
+	void __iomem *mbox_base;
+	int recvid;
+};
+
+static irqreturn_t cv1800_mbox_isr(int irq, void *dev_id)
+{
+	struct cv1800_mbox *mbox = (struct cv1800_mbox *)dev_id;
+	size_t i;
+	int ret = IRQ_NONE;
+
+	for (i = 0; i < MAILBOX_MAX_CHAN; i++) {
+		if (mbox->content[i] && mbox->chans[i].cl) {
+			mbox_chan_received_data(&mbox->chans[i],
+						(void *)mbox->content[i]);
+			mbox->content[i] = NULL;
+			ret = IRQ_HANDLED;
+		}
+	}
+
+	return ret;
+}
+
+static irqreturn_t cv1800_mbox_irq(int irq, void *dev_id)
+{
+	struct cv1800_mbox *mbox = (struct cv1800_mbox *)dev_id;
+	u8 set, valid;
+	size_t i;
+	int ret = IRQ_NONE;
+
+	set = readb(mbox->mbox_base + MBOX_SET_INT_REG(RECV_CPU));
+
+	if (!set)
+		return ret;
+
+	for (i = 0; i < MAILBOX_MAX_CHAN; i++) {
+		valid = set & BIT(i);
+		if (valid) {
+			mbox->content[i] =
+				MBOX_CONTEXT_BASE_INDEX(mbox->mbox_base, i);
+			writeb(valid,
+			       mbox->mbox_base + MBOX_SET_CLR_REG(RECV_CPU));
+			writeb(~valid, mbox->mbox_base + MBOX_EN_REG(RECV_CPU));
+			ret = IRQ_WAKE_THREAD;
+		}
+	}
+
+	return ret;
+}
+
+static int cv1800_mbox_send_data(struct mbox_chan *chan, void *data)
+{
+	struct cv1800_mbox_chan_priv *priv =
+		(struct cv1800_mbox_chan_priv *)chan->con_priv;
+	struct cv1800_mbox *mbox = dev_get_drvdata(chan->mbox->dev);
+	int idx = priv->idx;
+	int cpu = priv->cpu;
+	u8 en, valid;
+
+	memcpy_toio(MBOX_CONTEXT_BASE_INDEX(mbox->mbox_base, idx),
+		    data, 8);
+
+	valid = BIT(idx);
+	writeb(valid, mbox->mbox_base + MBOX_SET_CLR_REG(cpu));
+	en = readb(mbox->mbox_base + MBOX_EN_REG(cpu));
+	writeb(en | valid, mbox->mbox_base + MBOX_EN_REG(cpu));
+	writeb(valid, mbox->mbox_base + MBOX_SET_REG);
+
+	return 0;
+}
+
+static bool cv1800_last_tx_done(struct mbox_chan *chan)
+{
+	struct cv1800_mbox_chan_priv *priv =
+		(struct cv1800_mbox_chan_priv *)chan->con_priv;
+	struct cv1800_mbox *mbox = dev_get_drvdata(chan->mbox->dev);
+	u8 en;
+
+	en = readb(mbox->mbox_base + MBOX_EN_REG(priv->cpu));
+
+	return !(en & BIT(priv->idx));
+}
+
+static const struct mbox_chan_ops cv1800_mbox_chan_ops = {
+	.send_data = cv1800_mbox_send_data,
+	.last_tx_done = cv1800_last_tx_done,
+};
+
+static struct mbox_chan *cv1800_mbox_xlate(struct mbox_controller *mbox,
+					   const struct of_phandle_args *spec)
+{
+	struct cv1800_mbox_chan_priv *priv;
+
+	int idx = spec->args[0];
+	int cpu = spec->args[1];
+
+	if (idx >= mbox->num_chans)
+		return ERR_PTR(-EINVAL);
+
+	priv = mbox->chans[idx].con_priv;
+	priv->cpu = cpu;
+
+	return &mbox->chans[idx];
+}
+
+static const struct of_device_id cv1800_mbox_of_match[] = {
+	{ .compatible = "sophgo,cv1800b-mailbox", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, cv1800_mbox_of_match);
+
+static int cv1800_mbox_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct cv1800_mbox *mb;
+	int irq, idx, err;
+
+	mb = devm_kzalloc(dev, sizeof(*mb), GFP_KERNEL);
+	if (!mb)
+		return -ENOMEM;
+
+	mb->mbox_base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(mb->mbox_base))
+		return dev_err_probe(dev, PTR_ERR(mb->mbox_base),
+				     "Failed to map resource\n");
+
+	mb->mbox.dev = dev;
+	mb->mbox.chans = mb->chans;
+	mb->mbox.txdone_poll = true;
+	mb->mbox.ops = &cv1800_mbox_chan_ops;
+	mb->mbox.num_chans = MAILBOX_MAX_CHAN;
+	mb->mbox.of_xlate = cv1800_mbox_xlate;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	err = devm_request_threaded_irq(dev, irq, cv1800_mbox_irq,
+					cv1800_mbox_isr, IRQF_ONESHOT,
+					dev_name(&pdev->dev), mb);
+	if (err < 0)
+		return dev_err_probe(dev, err, "Failed to register irq\n");
+
+	for (idx = 0; idx < MAILBOX_MAX_CHAN; idx++) {
+		mb->priv[idx].idx = idx;
+		mb->mbox.chans[idx].con_priv = &mb->priv[idx];
+	}
+
+	platform_set_drvdata(pdev, mb);
+
+	err = devm_mbox_controller_register(dev, &mb->mbox);
+	if (err)
+		return dev_err_probe(dev, err, "Failed to register mailbox\n");
+
+	return 0;
+}
+
+static struct platform_driver cv1800_mbox_driver = {
+	.driver = {
+		.name = "cv1800-mbox",
+		.of_match_table = cv1800_mbox_of_match,
+	},
+	.probe	= cv1800_mbox_probe,
+};
+
+module_platform_driver(cv1800_mbox_driver);
+
+MODULE_DESCRIPTION("cv1800 mailbox driver");
+MODULE_LICENSE("GPL");

-- 
2.49.0
Re: [PATCH v3 3/3] mailbox: sophgo: add mailbox driver for CV18XX series SoC
Posted by kernel test robot 9 months, 1 week ago
Hi Junhui,

kernel test robot noticed the following build warnings:

[auto build test WARNING on b4432656b36e5cc1d50a1f2dc15357543add530e]

url:    https://github.com/intel-lab-lkp/linux/commits/Junhui-Liu/dt-bindings-mailbox-add-Sophgo-CV18XX-series-SoC/20250428-221604
base:   b4432656b36e5cc1d50a1f2dc15357543add530e
patch link:    https://lore.kernel.org/r/20250428-cv18xx-mbox-v3-3-ed18dfd836d1%40pigmoral.tech
patch subject: [PATCH v3 3/3] mailbox: sophgo: add mailbox driver for CV18XX series SoC
config: m68k-randconfig-r121-20250429 (https://download.01.org/0day-ci/archive/20250507/202505071325.uHimwt0g-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 7.5.0
reproduce: (https://download.01.org/0day-ci/archive/20250507/202505071325.uHimwt0g-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/202505071325.uHimwt0g-lkp@intel.com/

sparse warnings: (new ones prefixed by >>)
>> drivers/mailbox/cv1800-mailbox.c:64:50: sparse: sparse: cast removes address space '__iomem' of expression
   drivers/mailbox/cv1800-mailbox.c:89:33: sparse: sparse: cast removes address space '__iomem' of expression
>> drivers/mailbox/cv1800-mailbox.c:88:42: sparse: sparse: incorrect type in assignment (different address spaces) @@     expected unsigned long long [noderef] [usertype] __iomem * @@     got unsigned long long [usertype] * @@
   drivers/mailbox/cv1800-mailbox.c:88:42: sparse:     expected unsigned long long [noderef] [usertype] __iomem *
   drivers/mailbox/cv1800-mailbox.c:88:42: sparse:     got unsigned long long [usertype] *
   drivers/mailbox/cv1800-mailbox.c:109:21: sparse: sparse: cast removes address space '__iomem' of expression
>> drivers/mailbox/cv1800-mailbox.c:109:21: sparse: sparse: incorrect type in argument 1 (different address spaces) @@     expected void volatile [noderef] __iomem *dst @@     got unsigned long long [usertype] * @@
   drivers/mailbox/cv1800-mailbox.c:109:21: sparse:     expected void volatile [noderef] __iomem *dst
   drivers/mailbox/cv1800-mailbox.c:109:21: sparse:     got unsigned long long [usertype] *

vim +/__iomem +64 drivers/mailbox/cv1800-mailbox.c

    54	
    55	static irqreturn_t cv1800_mbox_isr(int irq, void *dev_id)
    56	{
    57		struct cv1800_mbox *mbox = (struct cv1800_mbox *)dev_id;
    58		size_t i;
    59		int ret = IRQ_NONE;
    60	
    61		for (i = 0; i < MAILBOX_MAX_CHAN; i++) {
    62			if (mbox->content[i] && mbox->chans[i].cl) {
    63				mbox_chan_received_data(&mbox->chans[i],
  > 64							(void *)mbox->content[i]);
    65				mbox->content[i] = NULL;
    66				ret = IRQ_HANDLED;
    67			}
    68		}
    69	
    70		return ret;
    71	}
    72	
    73	static irqreturn_t cv1800_mbox_irq(int irq, void *dev_id)
    74	{
    75		struct cv1800_mbox *mbox = (struct cv1800_mbox *)dev_id;
    76		u8 set, valid;
    77		size_t i;
    78		int ret = IRQ_NONE;
    79	
    80		set = readb(mbox->mbox_base + MBOX_SET_INT_REG(RECV_CPU));
    81	
    82		if (!set)
    83			return ret;
    84	
    85		for (i = 0; i < MAILBOX_MAX_CHAN; i++) {
    86			valid = set & BIT(i);
    87			if (valid) {
  > 88				mbox->content[i] =
    89					MBOX_CONTEXT_BASE_INDEX(mbox->mbox_base, i);
    90				writeb(valid,
    91				       mbox->mbox_base + MBOX_SET_CLR_REG(RECV_CPU));
    92				writeb(~valid, mbox->mbox_base + MBOX_EN_REG(RECV_CPU));
    93				ret = IRQ_WAKE_THREAD;
    94			}
    95		}
    96	
    97		return ret;
    98	}
    99	
   100	static int cv1800_mbox_send_data(struct mbox_chan *chan, void *data)
   101	{
   102		struct cv1800_mbox_chan_priv *priv =
   103			(struct cv1800_mbox_chan_priv *)chan->con_priv;
   104		struct cv1800_mbox *mbox = dev_get_drvdata(chan->mbox->dev);
   105		int idx = priv->idx;
   106		int cpu = priv->cpu;
   107		u8 en, valid;
   108	
 > 109		memcpy_toio(MBOX_CONTEXT_BASE_INDEX(mbox->mbox_base, idx),
   110			    data, 8);
   111	
   112		valid = BIT(idx);
   113		writeb(valid, mbox->mbox_base + MBOX_SET_CLR_REG(cpu));
   114		en = readb(mbox->mbox_base + MBOX_EN_REG(cpu));
   115		writeb(en | valid, mbox->mbox_base + MBOX_EN_REG(cpu));
   116		writeb(valid, mbox->mbox_base + MBOX_SET_REG);
   117	
   118		return 0;
   119	}
   120	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki