mirror of
https://github.com/torvalds/linux.git
synced 2026-03-07 23:04:33 +01:00
mailbox: platform and core updates
PCC
- Updates to transmission and interrupt handling, including
dynamic txdone configuration, ->last_tx_done() wiring, and SHMEM
initialization fixes. Reverted previous shared buffer patch.
MediaTek
- Introduce mtk-vcp-mailbox driver and bindings for MT8196 VCP.
- Expand mtk-cmdq for MT8196 with GCE virtualization, mminfra_offset,
and instruction generation data.
Spreadtrum (SPRD)
- Add Mailbox Revision 2 support and UMS9230 bindings.
- Fix unhandled interrupt masking and TX done delivery flags.
Microchip
- Add pic64gx compatibility to MPFS.
- Fix out-of-bounds access and smatch warnings in mchp-ipc-sbi.
Core & Misc Platform Updates
- Prevent out-of-bounds access in fw_mbox_index_xlate().
- Add bindings for Qualcomm CPUCP (Kaanapali).
- Simplify mtk-cmdq and zynqmp-ipi with scoped OF child iterators.
- Consolidate various minor fixes, dead code removal, and typo
corrections across Broadcom, NXP, Samsung, Xilinx, ARM, and
core headers.
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEE6EwehDt/SOnwFyTyf9lkf8eYP5UFAmmP4QkACgkQf9lkf8eY
P5XRlg//Ye7g0M4uLODJCPRBCG9WsBfHTi3FrpPi9yiaXXy0v5t8+2vwq8YEzevU
/4UbuC1hANdVbDB8ETtyeI+kmpcIw9VbZz/B4MW5PNr0bNuO1UUKgueoalXwkT6g
4S8zNX+Kx2dvjHjf4UF/tmBDDM0MAMKuTwEiugree2S7tuusrn0MFYt3XEeMVpKN
0ob+JTzSi3kHIiWHLi6ZagK8PqtZtOJTdJEziAz0OgOXdLWg614M0lAwPwdnkqX0
I+nIYeNaDqsR2tmMldPxRGv4A7sKKsZm/nnzrTC7OAvU/q+l7JNjF3ejeMJWehpF
4I6/jFsnAhmBBr/4U+HuzMxwARI11VjexQYlTH+aoZFtfiAEGfCNVYLAnbzOX1jh
7mnb1ccwWlgfuj0GtVYjYbrR0wjZVfsgSZX6mfbEOuDVLeQE/AWV1pq2V2Ptcl/s
qzKQwzDtAuHIJRB73xYthAE4jWF/EigEHyedDPoEXE8K+pkv8G9zuVHQYsejYmNF
oWlnoJZH/q+z7vMKCgblKQDPb++bUbXQr/x4PNLGW7J+ROikOOux0zOBJDaPSWoM
Mpw2sUaWI40IgpmEswtoifqzspYUwN7t/C7nBM/vdyFy/13KVOjV0Jbk2oW7mtMA
BzotYgVIThScG0P7iflXFvQz0fEMN8p4up/nYxbitgBFaBtHdU0=
=9BUB
-----END PGP SIGNATURE-----
Merge tag 'mailbox-v6.20' of git://git.kernel.org/pub/scm/linux/kernel/git/jassibrar/mailbox
Pull mailbox updates from Jassi Brar:
"Platform and core updates
PCC:
- Updates to transmission and interrupt handling, including dynamic
txdone configuration, ->last_tx_done() wiring, and SHMEM
initialization fixes. Reverted previous shared buffer patch
MediaTek
- Introduce mtk-vcp-mailbox driver and bindings for MT8196 VCP
- Expand mtk-cmdq for MT8196 with GCE virtualization, mminfra_offset,
and instruction generation data
Spreadtrum (SPRD)
- Add Mailbox Revision 2 support and UMS9230 bindings
- Fix unhandled interrupt masking and TX done delivery flags
Microchip
- Add pic64gx compatibility to MPFS
- Fix out-of-bounds access and smatch warnings in mchp-ipc-sbi
Core & Misc Platform Updates
- Prevent out-of-bounds access in fw_mbox_index_xlate()
- Add bindings for Qualcomm CPUCP (Kaanapali)
- Simplify mtk-cmdq and zynqmp-ipi with scoped OF child iterators
- Consolidate various minor fixes, dead code removal, and typo
corrections across Broadcom, NXP, Samsung, Xilinx, ARM, and core
headers"
* tag 'mailbox-v6.20' of git://git.kernel.org/pub/scm/linux/kernel/git/jassibrar/mailbox: (34 commits)
mailbox: sprd: mask interrupts that are not handled
mailbox: sprd: add support for mailbox revision 2
mailbox: sprd: clear delivery flag before handling TX done
dt-bindings: mailbox: sprd: add compatible for UMS9230
mailbox: bcm-ferxrm-mailbox: Use default primary handler
mailbox: Remove mailbox_client.h from controller drivers
mailbox: zynqmp-ipi: Simplify with scoped for each OF child loop
mailbox: mtk-cmdq: Simplify with scoped for each OF child loop
dt-bindings: mailbox: xlnx,zynqmp-ipi-mailbox: Document msg region requirement
mailbox: Improve RISCV_SBI_MPXY_MBOX guidance
mailbox: mchp-ipc-sbi: fix uninitialized symbol and other smatch warnings
mailbox: arm_mhuv3: fix typo in comment
mailbox: cix: fix typo in error message
mailbox: imx: Skip the suspend flag for i.MX7ULP
mailbox: exynos: drop unneeded runtime pointer (pclk)
mailbox: pcc: Remove spurious IRQF_ONESHOT usage
mailbox: mtk-cmdq: Add driver data to support for MT8196
mailbox: mtk-cmdq: Add mminfra_offset configuration for DRAM transaction
mailbox: mtk-cmdq: Add GCE hardware virtualization configuration
mailbox: mtk-cmdq: Add cmdq private data to cmdq_pkt for generating instruction
...
This commit is contained in:
commit
f0a475aedd
22 changed files with 434 additions and 208 deletions
|
|
@ -0,0 +1,49 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mailbox/mediatek,mt8196-vcp-mbox.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MediaTek Video Companion Processor (VCP) mailbox
|
||||
|
||||
maintainers:
|
||||
- Jjian Zhou <Jjian.Zhou@mediatek.com>
|
||||
|
||||
description:
|
||||
The MTK VCP mailbox enables the SoC to communicate with the VCP by passing
|
||||
messages through 64 32-bit wide registers. It has 32 interrupt vectors in
|
||||
either direction for signalling purposes.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt8196-vcp-mbox
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
"#mbox-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- "#mbox-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
mailbox@31b80000 {
|
||||
compatible = "mediatek,mt8196-vcp-mbox";
|
||||
reg = <0x31b80000 0x1000>;
|
||||
interrupts = <GIC_SPI 789 IRQ_TYPE_LEVEL_HIGH 0>;
|
||||
#mbox-cells = <0>;
|
||||
};
|
||||
|
|
@ -11,7 +11,11 @@ maintainers:
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
const: microchip,mpfs-mailbox
|
||||
oneOf:
|
||||
- items:
|
||||
- const: microchip,pic64gx-mailbox
|
||||
- const: microchip,mpfs-mailbox
|
||||
- const: microchip,mpfs-mailbox
|
||||
|
||||
reg:
|
||||
oneOf:
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ properties:
|
|||
enum:
|
||||
- sprd,sc9860-mailbox
|
||||
- sprd,sc9863a-mailbox
|
||||
- sprd,ums9230-mailbox
|
||||
|
||||
reg:
|
||||
items:
|
||||
|
|
|
|||
|
|
@ -11,6 +11,17 @@ description: |
|
|||
messaging between two Xilinx Zynq UltraScale+ MPSoC IPI agents. Each IPI
|
||||
agent owns registers used for notification and buffers for message.
|
||||
|
||||
For Versal devices, there are two types of IPI channels:
|
||||
- Buffered channels: Support message passing and require the "msg"
|
||||
register region to be present on both the host and remote IPI agents.
|
||||
- Buffer-less channels: Support notification only and do not require the
|
||||
"msg" register region. For these channels, the "msg" region should be
|
||||
omitted.
|
||||
|
||||
For message passing, both the host and remote IPI agents must define the "msg"
|
||||
register region. If either agent omits the "msg" region, only notification
|
||||
based communication is possible.
|
||||
|
||||
+-------------------------------------+
|
||||
| Xilinx ZynqMP IPI Controller |
|
||||
+-------------------------------------+
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ config POLARFIRE_SOC_MAILBOX
|
|||
tristate "PolarFire SoC (MPFS) Mailbox"
|
||||
depends on HAS_IOMEM
|
||||
depends on MFD_SYSCON
|
||||
depends on ARCH_MICROCHIP_POLARFIRE || COMPILE_TEST
|
||||
depends on ARCH_MICROCHIP || COMPILE_TEST
|
||||
help
|
||||
This driver adds support for the PolarFire SoC (MPFS) mailbox controller.
|
||||
|
||||
|
|
@ -279,7 +279,7 @@ config MTK_ADSP_MBOX
|
|||
tristate "MediaTek ADSP Mailbox Controller"
|
||||
depends on ARCH_MEDIATEK || COMPILE_TEST
|
||||
help
|
||||
Say yes here to add support for "MediaTek ADSP Mailbox Controller.
|
||||
Say yes here to add support for MediaTek ADSP Mailbox Controller.
|
||||
This mailbox driver is used to send notification or short message
|
||||
between processors with ADSP. It will place the message to share
|
||||
buffer and will access the ipc control.
|
||||
|
|
@ -304,6 +304,15 @@ config MTK_GPUEB_MBOX
|
|||
Say Y or m here if you want to support the MT8196 SoC in your kernel
|
||||
build.
|
||||
|
||||
config MTK_VCP_MBOX
|
||||
tristate "MediaTek VCP Mailbox Support"
|
||||
depends on ARCH_MEDIATEK || COMPILE_TEST
|
||||
help
|
||||
Say yes here to add support for the MediaTek VCP mailbox driver.
|
||||
The mailbox implementation provides access from the application
|
||||
processor to Video Companion Processor Unit.
|
||||
If unsure say N.
|
||||
|
||||
config ZYNQMP_IPI_MBOX
|
||||
tristate "Xilinx ZynqMP IPI Mailbox"
|
||||
depends on ARCH_ZYNQMP && OF
|
||||
|
|
@ -387,7 +396,7 @@ config RISCV_SBI_MPXY_MBOX
|
|||
Mailbox driver implementation for RISC-V SBI Message Proxy (MPXY)
|
||||
extension. This mailbox driver is used to send messages to the
|
||||
remote processor through the SBI implementation (M-mode firmware
|
||||
or HS-mode hypervisor). Say Y here if you want to have this support.
|
||||
If unsure say N.
|
||||
or HS-mode hypervisor). Say Y here, unless you are sure you do not
|
||||
need this.
|
||||
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -65,6 +65,8 @@ obj-$(CONFIG_MTK_CMDQ_MBOX) += mtk-cmdq-mailbox.o
|
|||
|
||||
obj-$(CONFIG_MTK_GPUEB_MBOX) += mtk-gpueb-mailbox.o
|
||||
|
||||
obj-$(CONFIG_MTK_VCP_MBOX) += mtk-vcp-mailbox.o
|
||||
|
||||
obj-$(CONFIG_ZYNQMP_IPI_MBOX) += zynqmp-ipi-mailbox.o
|
||||
|
||||
obj-$(CONFIG_SUN6I_MSGBOX) += sun6i-msgbox.o
|
||||
|
|
|
|||
|
|
@ -333,7 +333,7 @@ struct mhuv3_extension {
|
|||
* @rev: MHUv3 controller IIDR revision.
|
||||
* @var: MHUv3 controller IIDR variant.
|
||||
* @prod_id: MHUv3 controller IIDR product_id.
|
||||
* @num_chans: The total number of channnels discovered across all extensions.
|
||||
* @num_chans: The total number of channels discovered across all extensions.
|
||||
* @cmb_irq: Combined IRQ number if any found defined.
|
||||
* @ctrl: A reference to the MHUv3 control page for this block.
|
||||
* @pbx: Base address of the PBX register mapping region.
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mailbox_controller.h>
|
||||
#include <linux/mailbox_client.h>
|
||||
#include <linux/mailbox/brcm-message.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/msi.h>
|
||||
|
|
|
|||
|
|
@ -346,7 +346,7 @@ static void cix_mbox_isr_fifo(struct mbox_chan *chan)
|
|||
/* FIFO overflow is generated */
|
||||
if (int_status & CIX_FIFO_OFLOW_INT) {
|
||||
status = cix_mbox_read(priv, CIX_FIFO_STAS);
|
||||
dev_err(priv->dev, "fifo overlow: int_stats %d\n", status);
|
||||
dev_err(priv->dev, "fifo overflow: int_stats %d\n", status);
|
||||
cix_mbox_write(priv, CIX_FIFO_OFLOW_INT, CIX_INT_CLEAR);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
#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>
|
||||
|
|
|
|||
|
|
@ -35,12 +35,10 @@
|
|||
* struct exynos_mbox - driver's private data.
|
||||
* @regs: mailbox registers base address.
|
||||
* @mbox: pointer to the mailbox controller.
|
||||
* @pclk: pointer to the mailbox peripheral clock.
|
||||
*/
|
||||
struct exynos_mbox {
|
||||
void __iomem *regs;
|
||||
struct mbox_controller *mbox;
|
||||
struct clk *pclk;
|
||||
};
|
||||
|
||||
static int exynos_mbox_send_data(struct mbox_chan *chan, void *data)
|
||||
|
|
@ -100,6 +98,7 @@ static int exynos_mbox_probe(struct platform_device *pdev)
|
|||
struct exynos_mbox *exynos_mbox;
|
||||
struct mbox_controller *mbox;
|
||||
struct mbox_chan *chans;
|
||||
struct clk *pclk;
|
||||
int i;
|
||||
|
||||
exynos_mbox = devm_kzalloc(dev, sizeof(*exynos_mbox), GFP_KERNEL);
|
||||
|
|
@ -119,9 +118,9 @@ static int exynos_mbox_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(exynos_mbox->regs))
|
||||
return PTR_ERR(exynos_mbox->regs);
|
||||
|
||||
exynos_mbox->pclk = devm_clk_get_enabled(dev, "pclk");
|
||||
if (IS_ERR(exynos_mbox->pclk))
|
||||
return dev_err_probe(dev, PTR_ERR(exynos_mbox->pclk),
|
||||
pclk = devm_clk_get_enabled(dev, "pclk");
|
||||
if (IS_ERR(pclk))
|
||||
return dev_err_probe(dev, PTR_ERR(pclk),
|
||||
"Failed to enable clock.\n");
|
||||
|
||||
mbox->num_chans = EXYNOS_MBOX_CHAN_COUNT;
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ struct imx_mu_dcfg {
|
|||
u32 xRR; /* Receive Register0 */
|
||||
u32 xSR[IMX_MU_xSR_MAX]; /* Status Registers */
|
||||
u32 xCR[IMX_MU_xCR_MAX]; /* Control Registers */
|
||||
bool skip_suspend_flag;
|
||||
};
|
||||
|
||||
#define IMX_MU_xSR_GIPn(type, x) (type & IMX_MU_V2 ? BIT(x) : BIT(28 + (3 - (x))))
|
||||
|
|
@ -988,6 +989,7 @@ static const struct imx_mu_dcfg imx_mu_cfg_imx7ulp = {
|
|||
.xRR = 0x40,
|
||||
.xSR = {0x60, 0x60, 0x60, 0x60},
|
||||
.xCR = {0x64, 0x64, 0x64, 0x64, 0x64},
|
||||
.skip_suspend_flag = true,
|
||||
};
|
||||
|
||||
static const struct imx_mu_dcfg imx_mu_cfg_imx8ulp = {
|
||||
|
|
@ -1071,7 +1073,8 @@ static int __maybe_unused imx_mu_suspend_noirq(struct device *dev)
|
|||
priv->xcr[i] = imx_mu_read(priv, priv->dcfg->xCR[i]);
|
||||
}
|
||||
|
||||
priv->suspend = true;
|
||||
if (!priv->dcfg->skip_suspend_flag)
|
||||
priv->suspend = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1094,7 +1097,8 @@ static int __maybe_unused imx_mu_resume_noirq(struct device *dev)
|
|||
imx_mu_write(priv, priv->xcr[i], priv->dcfg->xCR[i]);
|
||||
}
|
||||
|
||||
priv->suspend = false;
|
||||
if (!priv->dcfg->skip_suspend_flag)
|
||||
priv->suspend = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -174,26 +174,30 @@ static irqreturn_t mchp_ipc_cluster_aggr_isr(int irq, void *data)
|
|||
struct mchp_ipc_msg ipc_msg;
|
||||
struct mchp_ipc_status status_msg;
|
||||
int ret;
|
||||
unsigned long hartid;
|
||||
u32 i, chan_index, chan_id;
|
||||
bool found = false;
|
||||
|
||||
/* Find out the hart that originated the irq */
|
||||
for_each_online_cpu(i) {
|
||||
hartid = cpuid_to_hartid_map(i);
|
||||
if (irq == ipc->cluster_cfg[hartid].irq)
|
||||
if (irq == ipc->cluster_cfg[i].irq) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
status_msg.cluster = hartid;
|
||||
memcpy(ipc->cluster_cfg[hartid].buf_base, &status_msg, sizeof(struct mchp_ipc_status));
|
||||
if (unlikely(!found))
|
||||
return IRQ_NONE;
|
||||
|
||||
ret = mchp_ipc_sbi_send(SBI_EXT_IPC_STATUS, ipc->cluster_cfg[hartid].buf_base_addr);
|
||||
status_msg.cluster = cpuid_to_hartid_map(i);
|
||||
memcpy(ipc->cluster_cfg[i].buf_base, &status_msg, sizeof(struct mchp_ipc_status));
|
||||
|
||||
ret = mchp_ipc_sbi_send(SBI_EXT_IPC_STATUS, ipc->cluster_cfg[i].buf_base_addr);
|
||||
if (ret < 0) {
|
||||
dev_err_ratelimited(ipc->dev, "could not get IHC irq status ret=%d\n", ret);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
memcpy(&status_msg, ipc->cluster_cfg[hartid].buf_base, sizeof(struct mchp_ipc_status));
|
||||
memcpy(&status_msg, ipc->cluster_cfg[i].buf_base, sizeof(struct mchp_ipc_status));
|
||||
|
||||
/*
|
||||
* Iterate over each bit set in the IHC interrupt status register (IRQ_STATUS) to identify
|
||||
|
|
@ -321,13 +325,6 @@ static int mchp_ipc_startup(struct mbox_chan *chan)
|
|||
goto fail_free_buf_msg_rx;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
dev_err(ipc->dev, "failed to register interrupt(s)\n");
|
||||
goto fail_free_buf_msg_rx;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
fail_free_buf_msg_rx:
|
||||
kfree(chan_info->msg_buf_rx);
|
||||
fail_free_buf_msg_tx:
|
||||
|
|
@ -385,21 +382,21 @@ static int mchp_ipc_get_cluster_aggr_irq(struct mchp_ipc_sbi_mbox *ipc)
|
|||
if (ret <= 0)
|
||||
continue;
|
||||
|
||||
ipc->cluster_cfg[hartid].irq = ret;
|
||||
ret = devm_request_irq(ipc->dev, ipc->cluster_cfg[hartid].irq,
|
||||
ipc->cluster_cfg[cpuid].irq = ret;
|
||||
ret = devm_request_irq(ipc->dev, ipc->cluster_cfg[cpuid].irq,
|
||||
mchp_ipc_cluster_aggr_isr, IRQF_SHARED,
|
||||
"miv-ihc-irq", ipc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ipc->cluster_cfg[hartid].buf_base = devm_kmalloc(ipc->dev,
|
||||
sizeof(struct mchp_ipc_status),
|
||||
GFP_KERNEL);
|
||||
ipc->cluster_cfg[cpuid].buf_base = devm_kmalloc(ipc->dev,
|
||||
sizeof(struct mchp_ipc_status),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!ipc->cluster_cfg[hartid].buf_base)
|
||||
if (!ipc->cluster_cfg[cpuid].buf_base)
|
||||
return -ENOMEM;
|
||||
|
||||
ipc->cluster_cfg[hartid].buf_base_addr = __pa(ipc->cluster_cfg[hartid].buf_base);
|
||||
ipc->cluster_cfg[cpuid].buf_base_addr = __pa(ipc->cluster_cfg[cpuid].buf_base);
|
||||
|
||||
irq_found = true;
|
||||
}
|
||||
|
|
@ -419,7 +416,7 @@ static int mchp_ipc_probe(struct platform_device *pdev)
|
|||
|
||||
ret = sbi_probe_extension(SBI_EXT_MICROCHIP_TECHNOLOGY);
|
||||
if (ret <= 0)
|
||||
return dev_err_probe(dev, ret, "Microchip SBI extension not detected\n");
|
||||
return dev_err_probe(dev, -ENODEV, "Microchip SBI extension not detected\n");
|
||||
|
||||
ipc = devm_kzalloc(dev, sizeof(*ipc), GFP_KERNEL);
|
||||
if (!ipc)
|
||||
|
|
|
|||
|
|
@ -489,12 +489,10 @@ EXPORT_SYMBOL_GPL(mbox_free_channel);
|
|||
static struct mbox_chan *fw_mbox_index_xlate(struct mbox_controller *mbox,
|
||||
const struct fwnode_reference_args *sp)
|
||||
{
|
||||
int ind = sp->args[0];
|
||||
|
||||
if (ind >= mbox->num_chans)
|
||||
if (sp->nargs < 1 || sp->args[0] >= mbox->num_chans)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return &mbox->chans[ind];
|
||||
return &mbox->chans[sp->args[0]];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -636,7 +636,7 @@ static struct mbox_chan *cmdq_xlate(struct mbox_controller *mbox,
|
|||
static int cmdq_get_clocks(struct device *dev, struct cmdq *cmdq)
|
||||
{
|
||||
static const char * const gce_name = "gce";
|
||||
struct device_node *node, *parent = dev->of_node->parent;
|
||||
struct device_node *parent = dev->of_node->parent;
|
||||
struct clk_bulk_data *clks;
|
||||
|
||||
cmdq->clocks = devm_kcalloc(dev, cmdq->pdata->gce_num,
|
||||
|
|
@ -661,7 +661,7 @@ static int cmdq_get_clocks(struct device *dev, struct cmdq *cmdq)
|
|||
* as the clock of the main GCE must be enabled for additional IPs
|
||||
* to be reachable.
|
||||
*/
|
||||
for_each_child_of_node(parent, node) {
|
||||
for_each_child_of_node_scoped(parent, node) {
|
||||
int alias_id = of_alias_get_id(node, gce_name);
|
||||
|
||||
if (alias_id < 0 || alias_id >= cmdq->pdata->gce_num)
|
||||
|
|
@ -670,17 +670,13 @@ static int cmdq_get_clocks(struct device *dev, struct cmdq *cmdq)
|
|||
clks = &cmdq->clocks[alias_id];
|
||||
|
||||
clks->id = devm_kasprintf(dev, GFP_KERNEL, "gce%d", alias_id);
|
||||
if (!clks->id) {
|
||||
of_node_put(node);
|
||||
if (!clks->id)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
clks->clk = of_clk_get(node, 0);
|
||||
if (IS_ERR(clks->clk)) {
|
||||
of_node_put(node);
|
||||
if (IS_ERR(clks->clk))
|
||||
return dev_err_probe(dev, PTR_ERR(clks->clk),
|
||||
"failed to get gce%d clock\n", alias_id);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
170
drivers/mailbox/mtk-vcp-mailbox.c
Normal file
170
drivers/mailbox/mtk-vcp-mailbox.c
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2025 MediaTek Corporation. All rights reserved.
|
||||
* Author: Jjian Zhou <jjian.zhou.@mediatek.com>
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mailbox_controller.h>
|
||||
#include <linux/mailbox/mtk-vcp-mailbox.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct mtk_vcp_mbox {
|
||||
struct mbox_controller mbox;
|
||||
void __iomem *base;
|
||||
struct device *dev;
|
||||
const struct mtk_vcp_mbox_cfg *cfg;
|
||||
struct mtk_ipi_info ipi_recv;
|
||||
struct mbox_chan chans;
|
||||
};
|
||||
|
||||
struct mtk_vcp_mbox_cfg {
|
||||
u16 set_in;
|
||||
u16 clr_out;
|
||||
};
|
||||
|
||||
static irqreturn_t mtk_vcp_mbox_irq_thread(int irq, void *data)
|
||||
{
|
||||
struct mtk_vcp_mbox *priv = data;
|
||||
|
||||
/* get irq status */
|
||||
priv->ipi_recv.irq_status = readl(priv->base + priv->cfg->clr_out);
|
||||
|
||||
__ioread32_copy(priv->ipi_recv.msg, priv->base,
|
||||
MTK_VCP_MBOX_SLOT_MAX_SIZE / 4);
|
||||
|
||||
mbox_chan_received_data(&priv->chans, &priv->ipi_recv);
|
||||
|
||||
/* clear irq status */
|
||||
writel(priv->ipi_recv.irq_status, priv->base + priv->cfg->clr_out);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct mbox_chan *mtk_vcp_mbox_xlate(struct mbox_controller *mbox,
|
||||
const struct of_phandle_args *sp)
|
||||
{
|
||||
if (sp->args_count)
|
||||
return NULL;
|
||||
|
||||
return &mbox->chans[0];
|
||||
}
|
||||
|
||||
static int mtk_vcp_mbox_send_data(struct mbox_chan *chan, void *data)
|
||||
{
|
||||
struct mtk_vcp_mbox *priv = chan->con_priv;
|
||||
struct mtk_ipi_info *ipi_info = data;
|
||||
u32 status;
|
||||
|
||||
if (!ipi_info->msg) {
|
||||
dev_err(priv->dev, "msg buffer is NULL.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
status = readl(priv->base + priv->cfg->set_in);
|
||||
if (status & BIT(ipi_info->index)) {
|
||||
dev_warn(priv->dev, "mailbox IPI %d is busy.\n", ipi_info->id);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (ipi_info->slot_ofs + ipi_info->len > MTK_VCP_MBOX_SLOT_MAX_SIZE)
|
||||
return -EINVAL;
|
||||
__iowrite32_copy(priv->base + ipi_info->slot_ofs, ipi_info->msg,
|
||||
ipi_info->len);
|
||||
|
||||
writel(BIT(ipi_info->index), priv->base + priv->cfg->set_in);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool mtk_vcp_mbox_last_tx_done(struct mbox_chan *chan)
|
||||
{
|
||||
struct mtk_ipi_info *ipi_info = chan->active_req;
|
||||
struct mtk_vcp_mbox *priv = chan->con_priv;
|
||||
|
||||
return !(readl(priv->base + priv->cfg->set_in) & BIT(ipi_info->index));
|
||||
}
|
||||
|
||||
static const struct mbox_chan_ops mtk_vcp_mbox_chan_ops = {
|
||||
.send_data = mtk_vcp_mbox_send_data,
|
||||
.last_tx_done = mtk_vcp_mbox_last_tx_done,
|
||||
};
|
||||
|
||||
static int mtk_vcp_mbox_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct mtk_vcp_mbox *priv;
|
||||
struct mbox_controller *mbox;
|
||||
int ret, irq;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->dev = dev;
|
||||
priv->chans.con_priv = priv;
|
||||
mbox = &priv->mbox;
|
||||
mbox->dev = dev;
|
||||
mbox->ops = &mtk_vcp_mbox_chan_ops;
|
||||
mbox->txdone_irq = false;
|
||||
mbox->txdone_poll = true;
|
||||
mbox->of_xlate = mtk_vcp_mbox_xlate;
|
||||
mbox->num_chans = 1;
|
||||
mbox->chans = &priv->chans;
|
||||
|
||||
priv->ipi_recv.msg = devm_kzalloc(dev, MTK_VCP_MBOX_SLOT_MAX_SIZE,
|
||||
GFP_KERNEL);
|
||||
if (!priv->ipi_recv.msg)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->base))
|
||||
return PTR_ERR(priv->base);
|
||||
|
||||
priv->cfg = of_device_get_match_data(dev);
|
||||
if (!priv->cfg)
|
||||
return -EINVAL;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
ret = devm_request_threaded_irq(dev, irq, NULL,
|
||||
mtk_vcp_mbox_irq_thread, IRQF_ONESHOT,
|
||||
dev_name(dev), priv);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return devm_mbox_controller_register(dev, &priv->mbox);
|
||||
}
|
||||
|
||||
static const struct mtk_vcp_mbox_cfg mt8196_cfg = {
|
||||
.set_in = 0x100,
|
||||
.clr_out = 0x10c,
|
||||
};
|
||||
|
||||
static const struct of_device_id mtk_vcp_mbox_of_match[] = {
|
||||
{ .compatible = "mediatek,mt8196-vcp-mbox", .data = &mt8196_cfg },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mtk_vcp_mbox_of_match);
|
||||
|
||||
static struct platform_driver mtk_vcp_mbox_driver = {
|
||||
.probe = mtk_vcp_mbox_probe,
|
||||
.driver = {
|
||||
.name = "mtk_vcp_mbox",
|
||||
.of_match_table = mtk_vcp_mbox_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(mtk_vcp_mbox_driver);
|
||||
|
||||
MODULE_AUTHOR("Jjian Zhou <jjian.zhou@mediatek.com>");
|
||||
MODULE_DESCRIPTION("MTK VCP Mailbox Controller");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -21,7 +21,6 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/mailbox_controller.h>
|
||||
#include <linux/mailbox_client.h>
|
||||
|
||||
#include "mailbox.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -305,22 +305,6 @@ static void pcc_chan_acknowledge(struct pcc_chan_info *pchan)
|
|||
pcc_chan_reg_read_modify_write(&pchan->db);
|
||||
}
|
||||
|
||||
static void *write_response(struct pcc_chan_info *pchan)
|
||||
{
|
||||
struct pcc_header pcc_header;
|
||||
void *buffer;
|
||||
int data_len;
|
||||
|
||||
memcpy_fromio(&pcc_header, pchan->chan.shmem,
|
||||
sizeof(pcc_header));
|
||||
data_len = pcc_header.length - sizeof(u32) + sizeof(struct pcc_header);
|
||||
|
||||
buffer = pchan->chan.rx_alloc(pchan->chan.mchan->cl, data_len);
|
||||
if (buffer != NULL)
|
||||
memcpy_fromio(buffer, pchan->chan.shmem, data_len);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* pcc_mbox_irq - PCC mailbox interrupt handler
|
||||
* @irq: interrupt number
|
||||
|
|
@ -332,8 +316,6 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p)
|
|||
{
|
||||
struct pcc_chan_info *pchan;
|
||||
struct mbox_chan *chan = p;
|
||||
struct pcc_header *pcc_header = chan->active_req;
|
||||
void *handle = NULL;
|
||||
|
||||
pchan = chan->con_priv;
|
||||
|
||||
|
|
@ -357,17 +339,8 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p)
|
|||
* required to avoid any possible race in updatation of this flag.
|
||||
*/
|
||||
pchan->chan_in_use = false;
|
||||
|
||||
if (pchan->chan.rx_alloc)
|
||||
handle = write_response(pchan);
|
||||
|
||||
if (chan->active_req) {
|
||||
pcc_header = chan->active_req;
|
||||
if (pcc_header->flags & PCC_CMD_COMPLETION_NOTIFY)
|
||||
mbox_chan_txdone(chan, 0);
|
||||
}
|
||||
|
||||
mbox_chan_received_data(chan, handle);
|
||||
mbox_chan_received_data(chan, NULL);
|
||||
mbox_chan_txdone(chan, 0);
|
||||
|
||||
pcc_chan_acknowledge(pchan);
|
||||
|
||||
|
|
@ -404,33 +377,20 @@ pcc_mbox_request_channel(struct mbox_client *cl, int subspace_id)
|
|||
return ERR_PTR(-EBUSY);
|
||||
}
|
||||
|
||||
rc = mbox_bind_client(chan, cl);
|
||||
if (rc)
|
||||
return ERR_PTR(rc);
|
||||
|
||||
pcc_mchan = &pchan->chan;
|
||||
pcc_mchan->shmem = acpi_os_ioremap(pcc_mchan->shmem_base_addr,
|
||||
pcc_mchan->shmem_size);
|
||||
if (!pcc_mchan->shmem)
|
||||
goto err;
|
||||
return ERR_PTR(-ENXIO);
|
||||
|
||||
pcc_mchan->manage_writes = false;
|
||||
|
||||
/* This indicates that the channel is ready to accept messages.
|
||||
* This needs to happen after the channel has registered
|
||||
* its callback. There is no access point to do that in
|
||||
* the mailbox API. That implies that the mailbox client must
|
||||
* have set the allocate callback function prior to
|
||||
* sending any messages.
|
||||
*/
|
||||
if (pchan->type == ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE)
|
||||
pcc_chan_reg_read_modify_write(&pchan->cmd_update);
|
||||
rc = mbox_bind_client(chan, cl);
|
||||
if (rc) {
|
||||
iounmap(pcc_mchan->shmem);
|
||||
pcc_mchan->shmem = NULL;
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
return pcc_mchan;
|
||||
|
||||
err:
|
||||
mbox_free_channel(chan);
|
||||
return ERR_PTR(-ENXIO);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pcc_mbox_request_channel);
|
||||
|
||||
|
|
@ -459,38 +419,8 @@ void pcc_mbox_free_channel(struct pcc_mbox_chan *pchan)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(pcc_mbox_free_channel);
|
||||
|
||||
static int pcc_write_to_buffer(struct mbox_chan *chan, void *data)
|
||||
{
|
||||
struct pcc_chan_info *pchan = chan->con_priv;
|
||||
struct pcc_mbox_chan *pcc_mbox_chan = &pchan->chan;
|
||||
struct pcc_header *pcc_header = data;
|
||||
|
||||
if (!pchan->chan.manage_writes)
|
||||
return 0;
|
||||
|
||||
/* The PCC header length includes the command field
|
||||
* but not the other values from the header.
|
||||
*/
|
||||
int len = pcc_header->length - sizeof(u32) + sizeof(struct pcc_header);
|
||||
u64 val;
|
||||
|
||||
pcc_chan_reg_read(&pchan->cmd_complete, &val);
|
||||
if (!val) {
|
||||
pr_info("%s pchan->cmd_complete not set", __func__);
|
||||
return -1;
|
||||
}
|
||||
memcpy_toio(pcc_mbox_chan->shmem, data, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pcc_send_data - Called from Mailbox Controller code. If
|
||||
* pchan->chan.rx_alloc is set, then the command complete
|
||||
* flag is checked and the data is written to the shared
|
||||
* buffer io memory.
|
||||
*
|
||||
* If pchan->chan.rx_alloc is not set, then it is used
|
||||
* pcc_send_data - Called from Mailbox Controller code. Used
|
||||
* here only to ring the channel doorbell. The PCC client
|
||||
* specific read/write is done in the client driver in
|
||||
* order to maintain atomicity over PCC channel once
|
||||
|
|
@ -506,37 +436,24 @@ static int pcc_send_data(struct mbox_chan *chan, void *data)
|
|||
int ret;
|
||||
struct pcc_chan_info *pchan = chan->con_priv;
|
||||
|
||||
ret = pcc_write_to_buffer(chan, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pcc_chan_reg_read_modify_write(&pchan->cmd_update);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pcc_chan_reg_read_modify_write(&pchan->db);
|
||||
|
||||
if (!ret && pchan->plat_irq > 0)
|
||||
pchan->chan_in_use = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static bool pcc_last_tx_done(struct mbox_chan *chan)
|
||||
{
|
||||
struct pcc_chan_info *pchan = chan->con_priv;
|
||||
u64 val;
|
||||
|
||||
pcc_chan_reg_read(&pchan->cmd_complete, &val);
|
||||
if (!val)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
return pcc_mbox_cmd_complete_check(pchan);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* pcc_startup - Called from Mailbox Controller code. Used here
|
||||
* to request the interrupt.
|
||||
|
|
@ -550,9 +467,15 @@ static int pcc_startup(struct mbox_chan *chan)
|
|||
unsigned long irqflags;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Clear and acknowledge any pending interrupts on responder channel
|
||||
* before enabling the interrupt
|
||||
*/
|
||||
pcc_chan_acknowledge(pchan);
|
||||
|
||||
if (pchan->plat_irq > 0) {
|
||||
irqflags = pcc_chan_plat_irq_can_be_shared(pchan) ?
|
||||
IRQF_SHARED | IRQF_ONESHOT : 0;
|
||||
IRQF_SHARED : 0;
|
||||
rc = devm_request_irq(chan->mbox->dev, pchan->plat_irq, pcc_mbox_irq,
|
||||
irqflags, MBOX_IRQ_NAME, chan);
|
||||
if (unlikely(rc)) {
|
||||
|
|
@ -877,8 +800,13 @@ static int pcc_mbox_probe(struct platform_device *pdev)
|
|||
(unsigned long) pcct_tbl + sizeof(struct acpi_table_pcct));
|
||||
|
||||
acpi_pcct_tbl = (struct acpi_table_pcct *) pcct_tbl;
|
||||
if (acpi_pcct_tbl->flags & ACPI_PCCT_DOORBELL)
|
||||
if (acpi_pcct_tbl->flags & ACPI_PCCT_DOORBELL) {
|
||||
pcc_mbox_ctrl->txdone_irq = true;
|
||||
pcc_mbox_ctrl->txdone_poll = false;
|
||||
} else {
|
||||
pcc_mbox_ctrl->txdone_irq = false;
|
||||
pcc_mbox_ctrl->txdone_poll = true;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
struct pcc_chan_info *pchan = chan_info + i;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@
|
|||
#define SPRD_MBOX_IRQ_STS 0x18
|
||||
#define SPRD_MBOX_IRQ_MSK 0x1c
|
||||
#define SPRD_MBOX_LOCK 0x20
|
||||
#define SPRD_MBOX_FIFO_DEPTH 0x24
|
||||
#define SPRD_MBOX_FIFO_DEPTH 0x24 /* outbox only */
|
||||
#define SPRD_MBOX_IN_FIFO_STS2 0x24 /* inbox only, revision 2 */
|
||||
|
||||
/* Bit and mask definition for inbox's SPRD_MBOX_FIFO_STS register */
|
||||
#define SPRD_INBOX_FIFO_DELIVER_MASK GENMASK(23, 16)
|
||||
|
|
@ -32,8 +33,18 @@
|
|||
#define SPRD_INBOX_FIFO_DELIVER_SHIFT 16
|
||||
#define SPRD_INBOX_FIFO_BUSY_MASK GENMASK(7, 0)
|
||||
|
||||
/* Bit and mask definition for R2 inbox's SPRD_MBOX_FIFO_RST register */
|
||||
#define SPRD_INBOX_R2_FIFO_OVERFLOW_DELIVER_RST GENMASK(31, 0)
|
||||
|
||||
/* Bit and mask definition for R2 inbox's SPRD_MBOX_FIFO_STS register */
|
||||
#define SPRD_INBOX_R2_FIFO_DELIVER_MASK GENMASK(15, 0)
|
||||
|
||||
/* Bit and mask definition for SPRD_MBOX_IN_FIFO_STS2 register */
|
||||
#define SPRD_INBOX_R2_FIFO_OVERFLOW_MASK GENMASK(31, 16)
|
||||
#define SPRD_INBOX_R2_FIFO_BUSY_MASK GENMASK(15, 0)
|
||||
|
||||
/* Bit and mask definition for SPRD_MBOX_IRQ_STS register */
|
||||
#define SPRD_MBOX_IRQ_CLR BIT(0)
|
||||
#define SPRD_MBOX_IRQ_CLR GENMASK(31, 0)
|
||||
|
||||
/* Bit and mask definition for outbox's SPRD_MBOX_FIFO_STS register */
|
||||
#define SPRD_OUTBOX_FIFO_FULL BIT(2)
|
||||
|
|
@ -52,8 +63,18 @@
|
|||
#define SPRD_OUTBOX_FIFO_IRQ_MASK GENMASK(4, 0)
|
||||
|
||||
#define SPRD_OUTBOX_BASE_SPAN 0x1000
|
||||
#define SPRD_MBOX_CHAN_MAX 8
|
||||
#define SPRD_SUPP_INBOX_ID_SC9863A 7
|
||||
#define SPRD_MBOX_R1_CHAN_MAX 8
|
||||
#define SPRD_MBOX_R2_CHAN_MAX 16
|
||||
|
||||
enum sprd_mbox_version {
|
||||
SPRD_MBOX_R1,
|
||||
SPRD_MBOX_R2,
|
||||
};
|
||||
|
||||
struct sprd_mbox_info {
|
||||
enum sprd_mbox_version version;
|
||||
unsigned long supp_id;
|
||||
};
|
||||
|
||||
struct sprd_mbox_priv {
|
||||
struct mbox_controller mbox;
|
||||
|
|
@ -64,9 +85,11 @@ struct sprd_mbox_priv {
|
|||
void __iomem *supp_base;
|
||||
u32 outbox_fifo_depth;
|
||||
|
||||
const struct sprd_mbox_info *info;
|
||||
|
||||
struct mutex lock;
|
||||
u32 refcnt;
|
||||
struct mbox_chan chan[SPRD_MBOX_CHAN_MAX];
|
||||
struct mbox_chan chan[SPRD_MBOX_R2_CHAN_MAX];
|
||||
};
|
||||
|
||||
static struct sprd_mbox_priv *to_sprd_mbox_priv(struct mbox_controller *mbox)
|
||||
|
|
@ -154,18 +177,35 @@ static irqreturn_t sprd_mbox_inbox_isr(int irq, void *data)
|
|||
{
|
||||
struct sprd_mbox_priv *priv = data;
|
||||
struct mbox_chan *chan;
|
||||
u32 fifo_sts, send_sts, busy, id;
|
||||
u32 fifo_sts, fifo_sts2, send_sts, busy, id;
|
||||
|
||||
fifo_sts = readl(priv->inbox_base + SPRD_MBOX_FIFO_STS);
|
||||
|
||||
if (priv->info->version == SPRD_MBOX_R2)
|
||||
fifo_sts2 = readl(priv->inbox_base + SPRD_MBOX_IN_FIFO_STS2);
|
||||
|
||||
/* Get the inbox data delivery status */
|
||||
send_sts = (fifo_sts & SPRD_INBOX_FIFO_DELIVER_MASK) >>
|
||||
SPRD_INBOX_FIFO_DELIVER_SHIFT;
|
||||
if (priv->info->version == SPRD_MBOX_R2) {
|
||||
send_sts = fifo_sts & SPRD_INBOX_R2_FIFO_DELIVER_MASK;
|
||||
} else {
|
||||
send_sts = (fifo_sts & SPRD_INBOX_FIFO_DELIVER_MASK) >>
|
||||
SPRD_INBOX_FIFO_DELIVER_SHIFT;
|
||||
}
|
||||
|
||||
if (!send_sts) {
|
||||
dev_warn_ratelimited(priv->dev, "spurious inbox interrupt\n");
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/* Clear FIFO delivery and overflow status first */
|
||||
if (priv->info->version == SPRD_MBOX_R2) {
|
||||
writel(SPRD_INBOX_R2_FIFO_OVERFLOW_DELIVER_RST,
|
||||
priv->inbox_base + SPRD_MBOX_FIFO_RST);
|
||||
} else {
|
||||
writel(fifo_sts & (SPRD_INBOX_FIFO_DELIVER_MASK | SPRD_INBOX_FIFO_OVERLOW_MASK),
|
||||
priv->inbox_base + SPRD_MBOX_FIFO_RST);
|
||||
}
|
||||
|
||||
while (send_sts) {
|
||||
id = __ffs(send_sts);
|
||||
send_sts &= (send_sts - 1);
|
||||
|
|
@ -176,16 +216,15 @@ static irqreturn_t sprd_mbox_inbox_isr(int irq, void *data)
|
|||
* Check if the message was fetched by remote target, if yes,
|
||||
* that means the transmission has been completed.
|
||||
*/
|
||||
busy = fifo_sts & SPRD_INBOX_FIFO_BUSY_MASK;
|
||||
if (priv->info->version == SPRD_MBOX_R2)
|
||||
busy = fifo_sts2 & SPRD_INBOX_R2_FIFO_BUSY_MASK;
|
||||
else
|
||||
busy = fifo_sts & SPRD_INBOX_FIFO_BUSY_MASK;
|
||||
|
||||
if (!(busy & BIT(id)))
|
||||
mbox_chan_txdone(chan, 0);
|
||||
}
|
||||
|
||||
/* Clear FIFO delivery and overflow status */
|
||||
writel(fifo_sts &
|
||||
(SPRD_INBOX_FIFO_DELIVER_MASK | SPRD_INBOX_FIFO_OVERLOW_MASK),
|
||||
priv->inbox_base + SPRD_MBOX_FIFO_RST);
|
||||
|
||||
/* Clear irq status */
|
||||
writel(SPRD_MBOX_IRQ_CLR, priv->inbox_base + SPRD_MBOX_IRQ_STS);
|
||||
|
||||
|
|
@ -243,21 +282,19 @@ static int sprd_mbox_startup(struct mbox_chan *chan)
|
|||
/* Select outbox FIFO mode and reset the outbox FIFO status */
|
||||
writel(0x0, priv->outbox_base + SPRD_MBOX_FIFO_RST);
|
||||
|
||||
/* Enable inbox FIFO overflow and delivery interrupt */
|
||||
val = readl(priv->inbox_base + SPRD_MBOX_IRQ_MSK);
|
||||
val &= ~(SPRD_INBOX_FIFO_OVERFLOW_IRQ | SPRD_INBOX_FIFO_DELIVER_IRQ);
|
||||
/* Enable inbox FIFO delivery interrupt */
|
||||
val = SPRD_INBOX_FIFO_IRQ_MASK;
|
||||
val &= ~SPRD_INBOX_FIFO_DELIVER_IRQ;
|
||||
writel(val, priv->inbox_base + SPRD_MBOX_IRQ_MSK);
|
||||
|
||||
/* Enable outbox FIFO not empty interrupt */
|
||||
val = readl(priv->outbox_base + SPRD_MBOX_IRQ_MSK);
|
||||
val = SPRD_OUTBOX_FIFO_IRQ_MASK;
|
||||
val &= ~SPRD_OUTBOX_FIFO_NOT_EMPTY_IRQ;
|
||||
writel(val, priv->outbox_base + SPRD_MBOX_IRQ_MSK);
|
||||
|
||||
/* Enable supplementary outbox as the fundamental one */
|
||||
if (priv->supp_base) {
|
||||
writel(0x0, priv->supp_base + SPRD_MBOX_FIFO_RST);
|
||||
val = readl(priv->supp_base + SPRD_MBOX_IRQ_MSK);
|
||||
val &= ~SPRD_OUTBOX_FIFO_NOT_EMPTY_IRQ;
|
||||
writel(val, priv->supp_base + SPRD_MBOX_IRQ_MSK);
|
||||
}
|
||||
}
|
||||
|
|
@ -295,7 +332,7 @@ static int sprd_mbox_probe(struct platform_device *pdev)
|
|||
struct device *dev = &pdev->dev;
|
||||
struct sprd_mbox_priv *priv;
|
||||
int ret, inbox_irq, outbox_irq, supp_irq;
|
||||
unsigned long id, supp;
|
||||
unsigned long id;
|
||||
struct clk *clk;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
|
|
@ -305,6 +342,10 @@ static int sprd_mbox_probe(struct platform_device *pdev)
|
|||
priv->dev = dev;
|
||||
mutex_init(&priv->lock);
|
||||
|
||||
priv->info = of_device_get_match_data(dev);
|
||||
if (!priv->info)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Unisoc mailbox uses an inbox to send messages to the target
|
||||
* core, and uses (an) outbox(es) to receive messages from other
|
||||
|
|
@ -362,12 +403,12 @@ static int sprd_mbox_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
supp = (unsigned long) of_device_get_match_data(dev);
|
||||
if (!supp) {
|
||||
if (!priv->info->supp_id) {
|
||||
dev_err(dev, "no supplementary outbox specified\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
priv->supp_base = priv->outbox_base + (SPRD_OUTBOX_BASE_SPAN * supp);
|
||||
priv->supp_base = priv->outbox_base +
|
||||
(SPRD_OUTBOX_BASE_SPAN * priv->info->supp_id);
|
||||
}
|
||||
|
||||
/* Get the default outbox FIFO depth */
|
||||
|
|
@ -375,11 +416,15 @@ static int sprd_mbox_probe(struct platform_device *pdev)
|
|||
readl(priv->outbox_base + SPRD_MBOX_FIFO_DEPTH) + 1;
|
||||
priv->mbox.dev = dev;
|
||||
priv->mbox.chans = &priv->chan[0];
|
||||
priv->mbox.num_chans = SPRD_MBOX_CHAN_MAX;
|
||||
priv->mbox.ops = &sprd_mbox_ops;
|
||||
priv->mbox.txdone_irq = true;
|
||||
|
||||
for (id = 0; id < SPRD_MBOX_CHAN_MAX; id++)
|
||||
if (priv->info->version == SPRD_MBOX_R2)
|
||||
priv->mbox.num_chans = SPRD_MBOX_R2_CHAN_MAX;
|
||||
else
|
||||
priv->mbox.num_chans = SPRD_MBOX_R1_CHAN_MAX;
|
||||
|
||||
for (id = 0; id < priv->mbox.num_chans; id++)
|
||||
priv->chan[id].con_priv = (void *)id;
|
||||
|
||||
ret = devm_mbox_controller_register(dev, &priv->mbox);
|
||||
|
|
@ -391,10 +436,24 @@ static int sprd_mbox_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct sprd_mbox_info sc9860_mbox_info = {
|
||||
.version = SPRD_MBOX_R1,
|
||||
};
|
||||
|
||||
static const struct sprd_mbox_info sc9863a_mbox_info = {
|
||||
.version = SPRD_MBOX_R1,
|
||||
.supp_id = 7,
|
||||
};
|
||||
|
||||
static const struct sprd_mbox_info ums9230_mbox_info = {
|
||||
.version = SPRD_MBOX_R2,
|
||||
.supp_id = 6,
|
||||
};
|
||||
|
||||
static const struct of_device_id sprd_mbox_of_match[] = {
|
||||
{ .compatible = "sprd,sc9860-mailbox" },
|
||||
{ .compatible = "sprd,sc9863a-mailbox",
|
||||
.data = (void *)SPRD_SUPP_INBOX_ID_SC9863A },
|
||||
{ .compatible = "sprd,sc9860-mailbox", .data = &sc9860_mbox_info },
|
||||
{ .compatible = "sprd,sc9863a-mailbox", .data = &sc9863a_mbox_info },
|
||||
{ .compatible = "sprd,ums9230-mailbox", .data = &ums9230_mbox_info },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sprd_mbox_of_match);
|
||||
|
|
|
|||
|
|
@ -904,7 +904,7 @@ static void zynqmp_ipi_free_mboxes(struct zynqmp_ipi_pdata *pdata)
|
|||
static int zynqmp_ipi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *nc, *np = pdev->dev.of_node;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct zynqmp_ipi_pdata *pdata;
|
||||
struct of_phandle_args out_irq;
|
||||
struct zynqmp_ipi_mbox *mbox;
|
||||
|
|
@ -940,13 +940,12 @@ static int zynqmp_ipi_probe(struct platform_device *pdev)
|
|||
pdata->num_mboxes = num_mboxes;
|
||||
|
||||
mbox = pdata->ipi_mboxes;
|
||||
for_each_available_child_of_node(np, nc) {
|
||||
for_each_available_child_of_node_scoped(np, nc) {
|
||||
mbox->pdata = pdata;
|
||||
mbox->setup_ipi_fn = ipi_fn;
|
||||
|
||||
ret = zynqmp_ipi_mbox_probe(mbox, nc);
|
||||
if (ret) {
|
||||
of_node_put(nc);
|
||||
dev_err(dev, "failed to probe subdev.\n");
|
||||
ret = -EINVAL;
|
||||
goto free_mbox_dev;
|
||||
|
|
|
|||
|
|
@ -17,35 +17,6 @@ struct pcc_mbox_chan {
|
|||
u32 latency;
|
||||
u32 max_access_rate;
|
||||
u16 min_turnaround_time;
|
||||
|
||||
/* Set to true to indicate that the mailbox should manage
|
||||
* writing the dat to the shared buffer. This differs from
|
||||
* the case where the drivesr are writing to the buffer and
|
||||
* using send_data only to ring the doorbell. If this flag
|
||||
* is set, then the void * data parameter of send_data must
|
||||
* point to a kernel-memory buffer formatted in accordance with
|
||||
* the PCC specification.
|
||||
*
|
||||
* The active buffer management will include reading the
|
||||
* notify_on_completion flag, and will then
|
||||
* call mbox_chan_txdone when the acknowledgment interrupt is
|
||||
* received.
|
||||
*/
|
||||
bool manage_writes;
|
||||
|
||||
/* Optional callback that allows the driver
|
||||
* to allocate the memory used for receiving
|
||||
* messages. The return value is the location
|
||||
* inside the buffer where the mailbox should write the data.
|
||||
*/
|
||||
void *(*rx_alloc)(struct mbox_client *cl, int size);
|
||||
};
|
||||
|
||||
struct pcc_header {
|
||||
u32 signature;
|
||||
u32 flags;
|
||||
u32 length;
|
||||
u32 command;
|
||||
};
|
||||
|
||||
/* Generic Communications Channel Shared Memory Region */
|
||||
|
|
|
|||
32
include/linux/mailbox/mtk-vcp-mailbox.h
Normal file
32
include/linux/mailbox/mtk-vcp-mailbox.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
|
||||
/*
|
||||
* Copyright (c) 2025 MediaTek Inc.
|
||||
*/
|
||||
|
||||
#ifndef __MTK_VCP_MAILBOX_H__
|
||||
#define __MTK_VCP_MAILBOX_H__
|
||||
|
||||
#define MTK_VCP_MBOX_SLOT_MAX_SIZE 0x100 /* mbox max slot size */
|
||||
|
||||
/**
|
||||
* struct mtk_ipi_info - mailbox message info for mtk-vcp-mailbox
|
||||
* @msg: The share buffer between IPC and mailbox driver
|
||||
* @len: Message length
|
||||
* @id: This is for identification purposes and not actually used
|
||||
* by the mailbox hardware.
|
||||
* @index: The signal number of the mailbox message.
|
||||
* @slot_ofs: Data slot offset.
|
||||
* @irq_status: Captures incoming signals for the RX path.
|
||||
*
|
||||
* It is used between IPC with mailbox driver.
|
||||
*/
|
||||
struct mtk_ipi_info {
|
||||
void *msg;
|
||||
u32 len;
|
||||
u32 id;
|
||||
u32 index;
|
||||
u32 slot_ofs;
|
||||
u32 irq_status;
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue