Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mailbox: mediatek: Add mtk-vcp-mailbox driver

Add mtk-vcp-mailbox driver to support the communication with
VCP remote microprocessor.

Signed-off-by: Jjian Zhou <jjian.zhou@mediatek.com>
Reviewed-by: Chen-Yu Tsai <wenst@chromium.org>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Jassi Brar <jassisinghbrar@gmail.com>

authored by

Jjian Zhou and committed by
Jassi Brar
b562abd9 c2b75a53

+213
+9
drivers/mailbox/Kconfig
··· 304 304 Say Y or m here if you want to support the MT8196 SoC in your kernel 305 305 build. 306 306 307 + config MTK_VCP_MBOX 308 + tristate "MediaTek VCP Mailbox Support" 309 + depends on ARCH_MEDIATEK || COMPILE_TEST 310 + help 311 + Say yes here to add support for the MediaTek VCP mailbox driver. 312 + The mailbox implementation provides access from the application 313 + processor to Video Companion Processor Unit. 314 + If unsure say N. 315 + 307 316 config ZYNQMP_IPI_MBOX 308 317 tristate "Xilinx ZynqMP IPI Mailbox" 309 318 depends on ARCH_ZYNQMP && OF
+2
drivers/mailbox/Makefile
··· 65 65 66 66 obj-$(CONFIG_MTK_GPUEB_MBOX) += mtk-gpueb-mailbox.o 67 67 68 + obj-$(CONFIG_MTK_VCP_MBOX) += mtk-vcp-mailbox.o 69 + 68 70 obj-$(CONFIG_ZYNQMP_IPI_MBOX) += zynqmp-ipi-mailbox.o 69 71 70 72 obj-$(CONFIG_SUN6I_MSGBOX) += sun6i-msgbox.o
+170
drivers/mailbox/mtk-vcp-mailbox.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (c) 2025 MediaTek Corporation. All rights reserved. 4 + * Author: Jjian Zhou <jjian.zhou.@mediatek.com> 5 + */ 6 + 7 + #include <linux/interrupt.h> 8 + #include <linux/io.h> 9 + #include <linux/kernel.h> 10 + #include <linux/mailbox_controller.h> 11 + #include <linux/mailbox/mtk-vcp-mailbox.h> 12 + #include <linux/module.h> 13 + #include <linux/of.h> 14 + #include <linux/platform_device.h> 15 + #include <linux/slab.h> 16 + 17 + struct mtk_vcp_mbox { 18 + struct mbox_controller mbox; 19 + void __iomem *base; 20 + struct device *dev; 21 + const struct mtk_vcp_mbox_cfg *cfg; 22 + struct mtk_ipi_info ipi_recv; 23 + struct mbox_chan chans; 24 + }; 25 + 26 + struct mtk_vcp_mbox_cfg { 27 + u16 set_in; 28 + u16 clr_out; 29 + }; 30 + 31 + static irqreturn_t mtk_vcp_mbox_irq_thread(int irq, void *data) 32 + { 33 + struct mtk_vcp_mbox *priv = data; 34 + 35 + /* get irq status */ 36 + priv->ipi_recv.irq_status = readl(priv->base + priv->cfg->clr_out); 37 + 38 + __ioread32_copy(priv->ipi_recv.msg, priv->base, 39 + MTK_VCP_MBOX_SLOT_MAX_SIZE / 4); 40 + 41 + mbox_chan_received_data(&priv->chans, &priv->ipi_recv); 42 + 43 + /* clear irq status */ 44 + writel(priv->ipi_recv.irq_status, priv->base + priv->cfg->clr_out); 45 + 46 + return IRQ_HANDLED; 47 + } 48 + 49 + static struct mbox_chan *mtk_vcp_mbox_xlate(struct mbox_controller *mbox, 50 + const struct of_phandle_args *sp) 51 + { 52 + if (sp->args_count) 53 + return NULL; 54 + 55 + return &mbox->chans[0]; 56 + } 57 + 58 + static int mtk_vcp_mbox_send_data(struct mbox_chan *chan, void *data) 59 + { 60 + struct mtk_vcp_mbox *priv = chan->con_priv; 61 + struct mtk_ipi_info *ipi_info = data; 62 + u32 status; 63 + 64 + if (!ipi_info->msg) { 65 + dev_err(priv->dev, "msg buffer is NULL.\n"); 66 + return -EINVAL; 67 + } 68 + 69 + status = readl(priv->base + priv->cfg->set_in); 70 + if (status & BIT(ipi_info->index)) { 71 + dev_warn(priv->dev, "mailbox IPI %d is busy.\n", ipi_info->id); 72 + return -EBUSY; 73 + } 74 + 75 + if (ipi_info->slot_ofs + ipi_info->len > MTK_VCP_MBOX_SLOT_MAX_SIZE) 76 + return -EINVAL; 77 + __iowrite32_copy(priv->base + ipi_info->slot_ofs, ipi_info->msg, 78 + ipi_info->len); 79 + 80 + writel(BIT(ipi_info->index), priv->base + priv->cfg->set_in); 81 + 82 + return 0; 83 + } 84 + 85 + static bool mtk_vcp_mbox_last_tx_done(struct mbox_chan *chan) 86 + { 87 + struct mtk_ipi_info *ipi_info = chan->active_req; 88 + struct mtk_vcp_mbox *priv = chan->con_priv; 89 + 90 + return !(readl(priv->base + priv->cfg->set_in) & BIT(ipi_info->index)); 91 + } 92 + 93 + static const struct mbox_chan_ops mtk_vcp_mbox_chan_ops = { 94 + .send_data = mtk_vcp_mbox_send_data, 95 + .last_tx_done = mtk_vcp_mbox_last_tx_done, 96 + }; 97 + 98 + static int mtk_vcp_mbox_probe(struct platform_device *pdev) 99 + { 100 + struct device *dev = &pdev->dev; 101 + struct mtk_vcp_mbox *priv; 102 + struct mbox_controller *mbox; 103 + int ret, irq; 104 + 105 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 106 + if (!priv) 107 + return -ENOMEM; 108 + 109 + priv->dev = dev; 110 + priv->chans.con_priv = priv; 111 + mbox = &priv->mbox; 112 + mbox->dev = dev; 113 + mbox->ops = &mtk_vcp_mbox_chan_ops; 114 + mbox->txdone_irq = false; 115 + mbox->txdone_poll = true; 116 + mbox->of_xlate = mtk_vcp_mbox_xlate; 117 + mbox->num_chans = 1; 118 + mbox->chans = &priv->chans; 119 + 120 + priv->ipi_recv.msg = devm_kzalloc(dev, MTK_VCP_MBOX_SLOT_MAX_SIZE, 121 + GFP_KERNEL); 122 + if (!priv->ipi_recv.msg) 123 + return -ENOMEM; 124 + 125 + priv->base = devm_platform_ioremap_resource(pdev, 0); 126 + if (IS_ERR(priv->base)) 127 + return PTR_ERR(priv->base); 128 + 129 + priv->cfg = of_device_get_match_data(dev); 130 + if (!priv->cfg) 131 + return -EINVAL; 132 + 133 + platform_set_drvdata(pdev, priv); 134 + 135 + irq = platform_get_irq(pdev, 0); 136 + if (irq < 0) 137 + return irq; 138 + 139 + ret = devm_request_threaded_irq(dev, irq, NULL, 140 + mtk_vcp_mbox_irq_thread, IRQF_ONESHOT, 141 + dev_name(dev), priv); 142 + if (ret < 0) 143 + return ret; 144 + 145 + return devm_mbox_controller_register(dev, &priv->mbox); 146 + } 147 + 148 + static const struct mtk_vcp_mbox_cfg mt8196_cfg = { 149 + .set_in = 0x100, 150 + .clr_out = 0x10c, 151 + }; 152 + 153 + static const struct of_device_id mtk_vcp_mbox_of_match[] = { 154 + { .compatible = "mediatek,mt8196-vcp-mbox", .data = &mt8196_cfg }, 155 + {}, 156 + }; 157 + MODULE_DEVICE_TABLE(of, mtk_vcp_mbox_of_match); 158 + 159 + static struct platform_driver mtk_vcp_mbox_driver = { 160 + .probe = mtk_vcp_mbox_probe, 161 + .driver = { 162 + .name = "mtk_vcp_mbox", 163 + .of_match_table = mtk_vcp_mbox_of_match, 164 + }, 165 + }; 166 + module_platform_driver(mtk_vcp_mbox_driver); 167 + 168 + MODULE_AUTHOR("Jjian Zhou <jjian.zhou@mediatek.com>"); 169 + MODULE_DESCRIPTION("MTK VCP Mailbox Controller"); 170 + MODULE_LICENSE("GPL");
+32
include/linux/mailbox/mtk-vcp-mailbox.h
··· 1 + /* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ 2 + /* 3 + * Copyright (c) 2025 MediaTek Inc. 4 + */ 5 + 6 + #ifndef __MTK_VCP_MAILBOX_H__ 7 + #define __MTK_VCP_MAILBOX_H__ 8 + 9 + #define MTK_VCP_MBOX_SLOT_MAX_SIZE 0x100 /* mbox max slot size */ 10 + 11 + /** 12 + * struct mtk_ipi_info - mailbox message info for mtk-vcp-mailbox 13 + * @msg: The share buffer between IPC and mailbox driver 14 + * @len: Message length 15 + * @id: This is for identification purposes and not actually used 16 + * by the mailbox hardware. 17 + * @index: The signal number of the mailbox message. 18 + * @slot_ofs: Data slot offset. 19 + * @irq_status: Captures incoming signals for the RX path. 20 + * 21 + * It is used between IPC with mailbox driver. 22 + */ 23 + struct mtk_ipi_info { 24 + void *msg; 25 + u32 len; 26 + u32 id; 27 + u32 index; 28 + u32 slot_ofs; 29 + u32 irq_status; 30 + }; 31 + 32 + #endif