Message ID | SYBP282MB2238F93565D20F0A5F3EEB6BC4A02@SYBP282MB2238.AUSP282.PROD.OUTLOOK.COM (mailing list archive) |
---|---|
State | Handled Elsewhere |
Headers | show |
Series | riscv: sophgo: add mailbox support for cv18x SoCs | expand |
Hi Yuntao, kernel test robot noticed the following build warnings: [auto build test WARNING on robh/for-next] [also build test WARNING on linus/master v6.10 next-20240712] [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/Yuntao-Dai/dt-bindings-mailbox-add-Sophgo-cv18x-SoCs-mailbox/20240715-003952 base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next patch link: https://lore.kernel.org/r/SYBP282MB2238F93565D20F0A5F3EEB6BC4A02%40SYBP282MB2238.AUSP282.PROD.OUTLOOK.COM patch subject: [PATCH v2 3/3] mailbox: sophgo: add mailbox driver for cv18x SoCs config: alpha-allyesconfig (https://download.01.org/0day-ci/archive/20240715/202407150911.KZchf5cj-lkp@intel.com/config) compiler: alpha-linux-gcc (GCC) 13.3.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240715/202407150911.KZchf5cj-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/202407150911.KZchf5cj-lkp@intel.com/ All warnings (new ones prefixed by >>): >> drivers/mailbox/cv1800-mailbox.c:30: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst * cv1800 mailbox channel private data vim +30 drivers/mailbox/cv1800-mailbox.c 28 29 /** > 30 * cv1800 mailbox channel private data 31 * @idx: index of channel 32 * @cpu: send to which processor 33 */ 34 struct cv1800_mbox_chan_priv { 35 int idx; 36 int cpu; 37 }; 38
Hi Yuntao, kernel test robot noticed the following build warnings: [auto build test WARNING on robh/for-next] [also build test WARNING on linus/master v6.10 next-20240715] [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/Yuntao-Dai/dt-bindings-mailbox-add-Sophgo-cv18x-SoCs-mailbox/20240715-003952 base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next patch link: https://lore.kernel.org/r/SYBP282MB2238F93565D20F0A5F3EEB6BC4A02%40SYBP282MB2238.AUSP282.PROD.OUTLOOK.COM patch subject: [PATCH v2 3/3] mailbox: sophgo: add mailbox driver for cv18x SoCs config: powerpc-randconfig-r113-20240715 (https://download.01.org/0day-ci/archive/20240715/202407151649.ExTr3xXL-lkp@intel.com/config) compiler: powerpc-linux-gcc (GCC) 14.1.0 reproduce: (https://download.01.org/0day-ci/archive/20240715/202407151649.ExTr3xXL-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/202407151649.ExTr3xXL-lkp@intel.com/ sparse warnings: (new ones prefixed by >>) >> drivers/mailbox/cv1800-mailbox.c:56:62: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void *data @@ got unsigned long long [noderef] [usertype] __iomem * @@ drivers/mailbox/cv1800-mailbox.c:56:62: sparse: expected void *data drivers/mailbox/cv1800-mailbox.c:56:62: sparse: got unsigned long long [noderef] [usertype] __iomem * >> drivers/mailbox/cv1800-mailbox.c:78:25: sparse: sparse: cast removes address space '__iomem' of expression >> drivers/mailbox/cv1800-mailbox.c:78:22: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected unsigned long long [noderef] [usertype] __iomem *addr @@ got unsigned long long [usertype] * @@ drivers/mailbox/cv1800-mailbox.c:78:22: sparse: expected unsigned long long [noderef] [usertype] __iomem *addr drivers/mailbox/cv1800-mailbox.c:78:22: sparse: got unsigned long long [usertype] * drivers/mailbox/cv1800-mailbox.c:102:17: sparse: sparse: cast removes address space '__iomem' of expression drivers/mailbox/cv1800-mailbox.c:102:14: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected unsigned long long [noderef] [usertype] __iomem *addr @@ got unsigned long long [usertype] * @@ drivers/mailbox/cv1800-mailbox.c:102:14: sparse: expected unsigned long long [noderef] [usertype] __iomem *addr drivers/mailbox/cv1800-mailbox.c:102:14: sparse: got unsigned long long [usertype] * vim +56 drivers/mailbox/cv1800-mailbox.c 47 48 static irqreturn_t cv1800_mbox_isr(int irq, void *dev_id) 49 { 50 struct cv1800_mbox *mbox = (struct cv1800_mbox *)dev_id; 51 size_t i; 52 53 for (i = 0; i < MAILBOX_MAX_CHAN; i++) { 54 if (mbox->content[i] && mbox->chans[i].cl) { 55 mbox_chan_received_data(&mbox->chans[i], > 56 mbox->content[i]); 57 mbox->content[i] = NULL; 58 return IRQ_HANDLED; 59 } 60 } 61 return IRQ_NONE; 62 } 63 64 static irqreturn_t cv1800_mbox_irq(int irq, void *dev_id) 65 { 66 struct cv1800_mbox *mbox = (struct cv1800_mbox *)dev_id; 67 u64 __iomem *addr; 68 u8 set, valid; 69 size_t i; 70 71 set = readb(mbox->mbox_base + MBOX_SET_INT_REG(RECV_CPU)); 72 73 if (!set) 74 return IRQ_NONE; 75 76 for (i = 0; i < MAILBOX_MAX_CHAN; i++) { 77 valid = set & (1 << i); > 78 addr = (u64 *)(mbox->mbox_base + MAILBOX_CONTEXT_OFFSET) + i; 79 if (valid) { 80 mbox->content[i] = addr; 81 writeb(valid, 82 mbox->mbox_base + MBOX_SET_CLR_REG(RECV_CPU)); 83 writeb(~valid, mbox->mbox_base + MBOX_EN_REG(RECV_CPU)); 84 return IRQ_WAKE_THREAD; 85 } 86 } 87 88 return IRQ_NONE; 89 } 90
On 2024-07-14 11:36 AM, Yuntao Dai wrote: > Add mailbox controller driver for cv18x SoCs, tested on mailbox-test > client. > > Signed-off-by: Yuntao Dai <d1581209858@live.com> > --- > drivers/mailbox/Kconfig | 11 ++ > drivers/mailbox/Makefile | 2 + > drivers/mailbox/cv1800-mailbox.c | 203 +++++++++++++++++++++++++++++++ > 3 files changed, 216 insertions(+) > create mode 100644 drivers/mailbox/cv1800-mailbox.c > > diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig > index 3b8842c4a..db856ec7e 100644 > --- a/drivers/mailbox/Kconfig > +++ b/drivers/mailbox/Kconfig > @@ -286,4 +286,15 @@ config QCOM_IPCC > acts as an interrupt controller for receiving interrupts from clients. > Say Y here if you want to build this driver. > > +config CV1800_MBOX > + tristate "cv1800 mailbox" > + depends on OF This dependency is not necessary once the probe function is fixed (see below). > + depends on ARCH_SOPHGO || COMPILE_TEST > + help > + Mailbox driver implementation for Sophgo cv180x 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. > + > endif > diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile > index 5cf2f54de..2c6db8c5c 100644 > --- a/drivers/mailbox/Makefile > +++ b/drivers/mailbox/Makefile > @@ -62,3 +62,5 @@ obj-$(CONFIG_SUN6I_MSGBOX) += sun6i-msgbox.o > obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox.o > > obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o > + > +obj-$(CONFIG_CV1800_MBOX) += cv1800-mailbox.o > \ No newline at end of file Please add the missing newline. > diff --git a/drivers/mailbox/cv1800-mailbox.c b/drivers/mailbox/cv1800-mailbox.c > new file mode 100644 > index 000000000..a3b214b4d > --- /dev/null > +++ b/drivers/mailbox/cv1800-mailbox.c > @@ -0,0 +1,203 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > + > +#include <linux/device.h> > +#include <linux/err.h> > +#include <linux/interrupt.h> > +#include <linux/io.h> > +#include <linux/kfifo.h> > +#include <linux/mailbox_controller.h> > +#include <linux/mailbox_client.h> > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/slab.h> > + > +#define RECV_CPU 2 > + > +#define MAILBOX_MAX_CHAN 0x0008 > +#define MAILBOX_DONE_OFFSET 0x0002 > +#define MAILBOX_CONTEXT_SIZE 0x0040 > +#define MAILBOX_CONTEXT_OFFSET 0x0400 > + > +#define MBOX_EN_REG(cpu) (cpu << 2) > +#define MBOX_DONE_REG(cpu) ((cpu << 2) + MAILBOX_DONE_OFFSET) > + > +#define MBOX_SET_CLR_REG(cpu) (0x10 + (cpu << 4)) > +#define MBOX_SET_INT_REG(cpu) (0x18 + (cpu << 4)) > + > +#define MBOX_SET_REG 0x60 > + > +/** > + * 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; > + > + for (i = 0; i < MAILBOX_MAX_CHAN; i++) { > + if (mbox->content[i] && mbox->chans[i].cl) { > + mbox_chan_received_data(&mbox->chans[i], > + mbox->content[i]); > + mbox->content[i] = NULL; > + return IRQ_HANDLED; Are you sure you only want to handle one channel per interrupt? Should this be "ret = IRQ_HANDLED;" or similar instead of early return? The same applies to cv1800_mbox_irq(). > + } > + } > + return IRQ_NONE; > +} > + > +static irqreturn_t cv1800_mbox_irq(int irq, void *dev_id) > +{ > + struct cv1800_mbox *mbox = (struct cv1800_mbox *)dev_id; > + u64 __iomem *addr; > + u8 set, valid; > + size_t i; > + > + set = readb(mbox->mbox_base + MBOX_SET_INT_REG(RECV_CPU)); > + > + if (!set) > + return IRQ_NONE; > + > + for (i = 0; i < MAILBOX_MAX_CHAN; i++) { > + valid = set & (1 << i); > + addr = (u64 *)(mbox->mbox_base + MAILBOX_CONTEXT_OFFSET) + i; > + if (valid) { > + mbox->content[i] = addr; > + writeb(valid, > + mbox->mbox_base + MBOX_SET_CLR_REG(RECV_CPU)); > + writeb(~valid, mbox->mbox_base + MBOX_EN_REG(RECV_CPU)); > + return IRQ_WAKE_THREAD; > + } > + } > + > + return IRQ_NONE; > +} > + > +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); > + u64 __iomem *addr; > + u8 en, valid; > + > + int idx = priv->idx; > + int cpu = priv->cpu; > + > + addr = (u64 *)(mbox->mbox_base + MAILBOX_CONTEXT_OFFSET) + idx; > + memcpy_toio(addr, data, 8); > + > + valid = 1 << 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) > +{ > + return true; Shouldn't this check MBOX_EN_REG(priv->cpu) or similar to check that the receiver has read the message? > +} > + > +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,cv1800-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; > + > + if (!dev->of_node) > + return -ENODEV; No need for this check. > + > + mb = devm_kzalloc(dev, sizeof(*mb), GFP_KERNEL); > + if (!mb) > + return -ENOMEM; > + > + mb->mbox_base = devm_of_iomap(dev, dev->of_node, 0, NULL); Please use devm_platform_ioremap_resource() here, which abstracts away the OF node. > + 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_byname(pdev, "mailbox"); > + 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]; > + } > + > + err = devm_mbox_controller_register(dev, &mb->mbox); > + if (err) > + return dev_err_probe(dev, err, "Failed to register mailbox\n"); > + > + platform_set_drvdata(pdev, mb); cv1800_mbox_send_data() could be called even inside devm_mbox_controller_register(), so this needs to be moved up. > + 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");
> From: Samuel Holland <samuel.holland@sifive.com> > Sent: Friday, July 19, 2024 09:35 > To: Yuntao Dai <d1581209858@live.com> > Cc: linux-kernel@vger.kernel.org <linux-kernel@vger.kernel.org>; > devicetree@vger.kernel.org <devicetree@vger.kernel.org>; > linux-riscv@lists.infradead.org <linux-riscv@lists.infradead.org>; > jassisinghbrar@gmail.com <jassisinghbrar@gmail.com>; robh@kernel.org > <robh@kernel.org>; krzk+dt@kernel.org <krzk+dt@kernel.org>; > conor+dt@kernel.org <conor+dt@kernel.org>; unicorn_wang@outlook.com > <unicorn_wang@outlook.com>; inochiama@outlook.com > <inochiama@outlook.com>; paul.walmsley@sifive.com > <paul.walmsley@sifive.com>; palmer@dabbelt.com <palmer@dabbelt.com>; > aou@eecs.berkeley.edu <aou@eecs.berkeley.edu> > Subject: Re: [PATCH v2 3/3] mailbox: sophgo: add mailbox driver for > cv18x SoCs > > On 2024-07-14 11:36 AM, Yuntao Dai wrote: > > Add mailbox controller driver for cv18x SoCs, tested on > mailbox-test > > client. > > > > Signed-off-by: Yuntao Dai <d1581209858@live.com> > > --- > > drivers/mailbox/Kconfig | 11 ++ > > drivers/mailbox/Makefile | 2 + > > drivers/mailbox/cv1800-mailbox.c | 203 > +++++++++++++++++++++++++++++++ > > 3 files changed, 216 insertions(+) > > create mode 100644 drivers/mailbox/cv1800-mailbox.c > > > > diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig > > index 3b8842c4a..db856ec7e 100644 > > --- a/drivers/mailbox/Kconfig > > +++ b/drivers/mailbox/Kconfig > > @@ -286,4 +286,15 @@ config QCOM_IPCC > > acts as an interrupt controller for receiving interrupts > from clients. > > Say Y here if you want to build this driver. > > > > +config CV1800_MBOX > > + tristate "cv1800 mailbox" > > + depends on OF > > This dependency is not necessary once the probe function is fixed > (see below). > I will fix it. > > + depends on ARCH_SOPHGO || COMPILE_TEST > > + help > > + Mailbox driver implementation for Sophgo cv180x 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. > > + > > endif > > diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile > > index 5cf2f54de..2c6db8c5c 100644 > > --- a/drivers/mailbox/Makefile > > +++ b/drivers/mailbox/Makefile > > @@ -62,3 +62,5 @@ obj-$(CONFIG_SUN6I_MSGBOX) += sun6i-msgbox.o > > obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox.o > > > > obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o > > + > > +obj-$(CONFIG_CV1800_MBOX) += cv1800-mailbox.o > > \ No newline at end of file > > Please add the missing newline. > > I will fix it > > diff --git a/drivers/mailbox/cv1800-mailbox.c > b/drivers/mailbox/cv1800-mailbox.c > > new file mode 100644 > > index 000000000..a3b214b4d > > --- /dev/null > > +++ b/drivers/mailbox/cv1800-mailbox.c > > @@ -0,0 +1,203 @@ > > +// SPDX-License-Identifier: GPL-2.0-or-later > > + > > +#include <linux/device.h> > > +#include <linux/err.h> > > +#include <linux/interrupt.h> > > +#include <linux/io.h> > > +#include <linux/kfifo.h> > > +#include <linux/mailbox_controller.h> > > +#include <linux/mailbox_client.h> > > +#include <linux/module.h> > > +#include <linux/platform_device.h> > > +#include <linux/slab.h> > > + > > +#define RECV_CPU 2 > > + > > +#define MAILBOX_MAX_CHAN 0x0008 > > +#define MAILBOX_DONE_OFFSET 0x0002 > > +#define MAILBOX_CONTEXT_SIZE 0x0040 > > +#define MAILBOX_CONTEXT_OFFSET 0x0400 > > + > > +#define MBOX_EN_REG(cpu) (cpu << 2) > > +#define MBOX_DONE_REG(cpu) ((cpu << 2) + MAILBOX_DONE_OFFSET) > > + > > +#define MBOX_SET_CLR_REG(cpu) (0x10 + (cpu << 4)) > > +#define MBOX_SET_INT_REG(cpu) (0x18 + (cpu << 4)) > > + > > +#define MBOX_SET_REG 0x60 > > + > > +/** > > + * 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; > > + > > + for (i = 0; i < MAILBOX_MAX_CHAN; i++) { > > + if (mbox->content[i] && mbox->chans[i].cl) { > > + mbox_chan_received_data(&mbox->chans[i], > > + mbox->content[i]); > > + mbox->content[i] = NULL; > > + return IRQ_HANDLED; > > Are you sure you only want to handle one channel per interrupt? > Should this be > "ret = IRQ_HANDLED;" or similar instead of early return? The same > applies to > cv1800_mbox_irq(). > > I believe this approach can simplify the implementation. I utilize IRQ_ONESHOT to prevent interrupt racing, thereby avoiding the need for locking mbox->content in this scenario. And I see rockchip mailbox did the same thing. > > + } > > + } > > + return IRQ_NONE; > > +} > > + > > +static irqreturn_t cv1800_mbox_irq(int irq, void *dev_id) > > +{ > > + struct cv1800_mbox *mbox = (struct cv1800_mbox *)dev_id; > > + u64 __iomem *addr; > > + u8 set, valid; > > + size_t i; > > + > > + set = readb(mbox->mbox_base + MBOX_SET_INT_REG(RECV_CPU)); > > + > > + if (!set) > > + return IRQ_NONE; > > + > > + for (i = 0; i < MAILBOX_MAX_CHAN; i++) { > > + valid = set & (1 << i); > > + addr = (u64 *)(mbox->mbox_base + > MAILBOX_CONTEXT_OFFSET) + i; > > + if (valid) { > > + mbox->content[i] = addr; > > + writeb(valid, > > + mbox->mbox_base + > MBOX_SET_CLR_REG(RECV_CPU)); > > + writeb(~valid, mbox->mbox_base + > MBOX_EN_REG(RECV_CPU)); > > + return IRQ_WAKE_THREAD; > > + } > > + } > > + > > + return IRQ_NONE; > > +} > > + > > +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); > > + u64 __iomem *addr; > > + u8 en, valid; > > + > > + int idx = priv->idx; > > + int cpu = priv->cpu; > > + > > + addr = (u64 *)(mbox->mbox_base + MAILBOX_CONTEXT_OFFSET) + > idx; > > + memcpy_toio(addr, data, 8); > > + > > + valid = 1 << 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) > > +{ > > + return true; > > Shouldn't this check MBOX_EN_REG(priv->cpu) or similar to check that > the > receiver has read the message? > Yes, I think check MBOX_EN_REG(priv->cpu) is a good way to ensure content has been writen into hardware. And I think driver should only send the message and upper layer is responsible for ack and things like that. There is a vendor implementation of linux mailbox and RTOS mailbox: https://github.com/milkv-duo/duo-buildroot-sdk/blob/develop/linux_5.10/drivers/soc/cvitek/rtos_cmdqu/rtos_cmdqu.c https://github.com/milkv-duo/duo-buildroot-sdk/blob/develop/freertos/cvitek/task/comm/src/riscv64/comm_main.c These implementations define a protocol structure for communication between linux and RTOS, the linux mailbox controller just need to provide API for client and do not consider the content of msg. > > +} > > + > > +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,cv1800-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; > > + > > + if (!dev->of_node) > > + return -ENODEV; > > No need for this check. I will fix it > > > + > > + mb = devm_kzalloc(dev, sizeof(*mb), GFP_KERNEL); > > + if (!mb) > > + return -ENOMEM; > > + > > + mb->mbox_base = devm_of_iomap(dev, dev->of_node, 0, NULL); > > Please use devm_platform_ioremap_resource() here, which abstracts > away the OF node. I will fix it > > > + 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_byname(pdev, "mailbox"); > > + 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]; > > + } > > + > > + err = devm_mbox_controller_register(dev, &mb->mbox); > > + if (err) > > + return dev_err_probe(dev, err, "Failed to register > mailbox\n"); > > + > > + platform_set_drvdata(pdev, mb); > > cv1800_mbox_send_data() could be called even inside > devm_mbox_controller_register(), so this needs to be moved up. I will fix it > > > + 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"); >
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 3b8842c4a..db856ec7e 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -286,4 +286,15 @@ config QCOM_IPCC acts as an interrupt controller for receiving interrupts from clients. Say Y here if you want to build this driver. +config CV1800_MBOX + tristate "cv1800 mailbox" + depends on OF + depends on ARCH_SOPHGO || COMPILE_TEST + help + Mailbox driver implementation for Sophgo cv180x 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. + endif diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index 5cf2f54de..2c6db8c5c 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -62,3 +62,5 @@ obj-$(CONFIG_SUN6I_MSGBOX) += sun6i-msgbox.o obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox.o obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o + +obj-$(CONFIG_CV1800_MBOX) += cv1800-mailbox.o \ No newline at end of file diff --git a/drivers/mailbox/cv1800-mailbox.c b/drivers/mailbox/cv1800-mailbox.c new file mode 100644 index 000000000..a3b214b4d --- /dev/null +++ b/drivers/mailbox/cv1800-mailbox.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kfifo.h> +#include <linux/mailbox_controller.h> +#include <linux/mailbox_client.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#define RECV_CPU 2 + +#define MAILBOX_MAX_CHAN 0x0008 +#define MAILBOX_DONE_OFFSET 0x0002 +#define MAILBOX_CONTEXT_SIZE 0x0040 +#define MAILBOX_CONTEXT_OFFSET 0x0400 + +#define MBOX_EN_REG(cpu) (cpu << 2) +#define MBOX_DONE_REG(cpu) ((cpu << 2) + MAILBOX_DONE_OFFSET) + +#define MBOX_SET_CLR_REG(cpu) (0x10 + (cpu << 4)) +#define MBOX_SET_INT_REG(cpu) (0x18 + (cpu << 4)) + +#define MBOX_SET_REG 0x60 + +/** + * 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; + + for (i = 0; i < MAILBOX_MAX_CHAN; i++) { + if (mbox->content[i] && mbox->chans[i].cl) { + mbox_chan_received_data(&mbox->chans[i], + mbox->content[i]); + mbox->content[i] = NULL; + return IRQ_HANDLED; + } + } + return IRQ_NONE; +} + +static irqreturn_t cv1800_mbox_irq(int irq, void *dev_id) +{ + struct cv1800_mbox *mbox = (struct cv1800_mbox *)dev_id; + u64 __iomem *addr; + u8 set, valid; + size_t i; + + set = readb(mbox->mbox_base + MBOX_SET_INT_REG(RECV_CPU)); + + if (!set) + return IRQ_NONE; + + for (i = 0; i < MAILBOX_MAX_CHAN; i++) { + valid = set & (1 << i); + addr = (u64 *)(mbox->mbox_base + MAILBOX_CONTEXT_OFFSET) + i; + if (valid) { + mbox->content[i] = addr; + writeb(valid, + mbox->mbox_base + MBOX_SET_CLR_REG(RECV_CPU)); + writeb(~valid, mbox->mbox_base + MBOX_EN_REG(RECV_CPU)); + return IRQ_WAKE_THREAD; + } + } + + return IRQ_NONE; +} + +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); + u64 __iomem *addr; + u8 en, valid; + + int idx = priv->idx; + int cpu = priv->cpu; + + addr = (u64 *)(mbox->mbox_base + MAILBOX_CONTEXT_OFFSET) + idx; + memcpy_toio(addr, data, 8); + + valid = 1 << 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) +{ + return true; +} + +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,cv1800-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; + + if (!dev->of_node) + return -ENODEV; + + mb = devm_kzalloc(dev, sizeof(*mb), GFP_KERNEL); + if (!mb) + return -ENOMEM; + + mb->mbox_base = devm_of_iomap(dev, dev->of_node, 0, NULL); + 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_byname(pdev, "mailbox"); + 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]; + } + + err = devm_mbox_controller_register(dev, &mb->mbox); + if (err) + return dev_err_probe(dev, err, "Failed to register mailbox\n"); + + platform_set_drvdata(pdev, mb); + 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");
Add mailbox controller driver for cv18x SoCs, tested on mailbox-test client. Signed-off-by: Yuntao Dai <d1581209858@live.com> --- drivers/mailbox/Kconfig | 11 ++ drivers/mailbox/Makefile | 2 + drivers/mailbox/cv1800-mailbox.c | 203 +++++++++++++++++++++++++++++++ 3 files changed, 216 insertions(+) create mode 100644 drivers/mailbox/cv1800-mailbox.c