diff --git a/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml b/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml index f40dc9048327..1b4ef0688ca7 100644 --- a/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml +++ b/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml @@ -49,6 +49,7 @@ properties: - qcom,qcs615-apss-shared - qcom,sc7180-apss-shared - qcom,sc8180x-apss-shared + - qcom,shikra-apss-shared - qcom,sm7150-apss-shared - qcom,sm8150-apss-shared - const: qcom,sdm845-apss-shared diff --git a/Documentation/devicetree/bindings/mailbox/qcom,cpucp-mbox.yaml b/Documentation/devicetree/bindings/mailbox/qcom,cpucp-mbox.yaml index 90bfde66cc4a..03359479d926 100644 --- a/Documentation/devicetree/bindings/mailbox/qcom,cpucp-mbox.yaml +++ b/Documentation/devicetree/bindings/mailbox/qcom,cpucp-mbox.yaml @@ -19,7 +19,9 @@ properties: - items: - enum: - qcom,glymur-cpucp-mbox + - qcom,hawi-cpucp-mbox - qcom,kaanapali-cpucp-mbox + - qcom,nord-cpucp-mbox - qcom,sm8750-cpucp-mbox - const: qcom,x1e80100-cpucp-mbox - enum: diff --git a/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml b/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml index f5c584cf2146..3839e1f5f904 100644 --- a/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml +++ b/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml @@ -26,7 +26,9 @@ properties: - enum: - qcom,eliza-ipcc - qcom,glymur-ipcc + - qcom,hawi-ipcc - qcom,kaanapali-ipcc + - qcom,maili-ipcc - qcom,milos-ipcc - qcom,qcs8300-ipcc - qcom,qdu1000-ipcc diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 5bf4155b090a..3062ee352f78 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -341,7 +341,7 @@ config SPRD_MBOX you want to build the Spreatrum mailbox controller driver. config QCOM_CPUCP_MBOX - tristate "Qualcomm Technologies, Inc. CPUCP mailbox driver" + tristate "Qualcomm CPUCP mailbox driver" depends on (ARCH_QCOM || COMPILE_TEST) && 64BIT help Qualcomm Technologies, Inc. CPUSS Control Processor (CPUCP) mailbox @@ -349,7 +349,7 @@ config QCOM_CPUCP_MBOX Y here if you want to build this driver. config QCOM_IPCC - tristate "Qualcomm Technologies, Inc. IPCC driver" + tristate "Qualcomm IPCC driver" depends on ARCH_QCOM || COMPILE_TEST help Qualcomm Technologies, Inc. Inter-Processor Communication Controller diff --git a/drivers/mailbox/exynos-mailbox.c b/drivers/mailbox/exynos-mailbox.c index d2355b128ba4..fa02f18948cf 100644 --- a/drivers/mailbox/exynos-mailbox.c +++ b/drivers/mailbox/exynos-mailbox.c @@ -16,15 +16,8 @@ #include #include -#define EXYNOS_MBOX_MCUCTRL 0x0 /* Mailbox Control Register */ -#define EXYNOS_MBOX_INTCR0 0x24 /* Interrupt Clear Register 0 */ #define EXYNOS_MBOX_INTMR0 0x28 /* Interrupt Mask Register 0 */ -#define EXYNOS_MBOX_INTSR0 0x2c /* Interrupt Status Register 0 */ -#define EXYNOS_MBOX_INTMSR0 0x30 /* Interrupt Mask Status Register 0 */ #define EXYNOS_MBOX_INTGR1 0x40 /* Interrupt Generation Register 1 */ -#define EXYNOS_MBOX_INTMR1 0x48 /* Interrupt Mask Register 1 */ -#define EXYNOS_MBOX_INTSR1 0x4c /* Interrupt Status Register 1 */ -#define EXYNOS_MBOX_INTMSR1 0x50 /* Interrupt Mask Status Register 1 */ #define EXYNOS_MBOX_INTMR0_MASK GENMASK(15, 0) #define EXYNOS_MBOX_INTGR1_MASK GENMASK(15, 0) diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index 246a9a9e3952..40bad2b3e4d1 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -80,13 +80,14 @@ struct imx_mu_con_priv { enum imx_mu_chan_type type; struct mbox_chan *chan; struct work_struct txdb_work; + bool shutdown; }; struct imx_mu_priv { struct device *dev; void __iomem *base; void *msg; - spinlock_t xcr_lock; /* control register lock */ + raw_spinlock_t xcr_lock; /* control register lock */ struct mbox_controller mbox; struct mbox_chan mbox_chans[IMX_MU_CHANS]; @@ -206,19 +207,44 @@ static int imx_mu_rx_waiting_read(struct imx_mu_priv *priv, u32 *val, u32 idx) static u32 imx_mu_xcr_rmw(struct imx_mu_priv *priv, enum imx_mu_xcr type, u32 set, u32 clr) { - unsigned long flags; u32 val; - spin_lock_irqsave(&priv->xcr_lock, flags); + guard(raw_spinlock_irqsave)(&priv->xcr_lock); + val = imx_mu_read(priv, priv->dcfg->xCR[type]); val &= ~clr; val |= set; imx_mu_write(priv, val, priv->dcfg->xCR[type]); - spin_unlock_irqrestore(&priv->xcr_lock, flags); return val; } +static void imx_mu_xcr_clr_shut(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp, + enum imx_mu_xcr type, u32 clr) +{ + u32 val; + + guard(raw_spinlock_irqsave)(&priv->xcr_lock); + cp->shutdown = true; + + val = imx_mu_read(priv, priv->dcfg->xCR[type]); + val &= ~clr; + imx_mu_write(priv, val, priv->dcfg->xCR[type]); +} + +static void imx_mu_xcr_set_act(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp, + enum imx_mu_xcr type, u32 set) +{ + u32 val; + + guard(raw_spinlock_irqsave)(&priv->xcr_lock); + if (!cp->shutdown) { + val = imx_mu_read(priv, priv->dcfg->xCR[type]); + val |= set; + imx_mu_write(priv, val, priv->dcfg->xCR[type]); + } +} + static int imx_mu_generic_tx(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp, void *data) @@ -227,6 +253,7 @@ static int imx_mu_generic_tx(struct imx_mu_priv *priv, u32 val; int ret, count; + ret = 0; switch (cp->type) { case IMX_MU_TYPE_TX: imx_mu_write(priv, *arg, priv->dcfg->xTR + cp->idx * 4); @@ -259,7 +286,7 @@ static int imx_mu_generic_tx(struct imx_mu_priv *priv, return -EINVAL; } - return 0; + return ret; } static int imx_mu_generic_rx(struct imx_mu_priv *priv, @@ -349,7 +376,6 @@ static int imx_mu_specific_rx(struct imx_mu_priv *priv, struct imx_mu_con_priv * data = (u32 *)priv->msg; - imx_mu_xcr_rmw(priv, IMX_MU_RCR, 0, IMX_MU_xCR_RIEn(priv->dcfg->type, 0)); *data++ = imx_mu_read(priv, priv->dcfg->xRR); if (priv->dcfg->type & IMX_MU_V2_S4) { @@ -376,7 +402,6 @@ static int imx_mu_specific_rx(struct imx_mu_priv *priv, struct imx_mu_con_priv * *data++ = imx_mu_read(priv, priv->dcfg->xRR + (i % num_rr) * 4); } - imx_mu_xcr_rmw(priv, IMX_MU_RCR, IMX_MU_xCR_RIEn(priv->dcfg->type, 0), 0); mbox_chan_received_data(cp->chan, (void *)priv->msg); return 0; @@ -508,11 +533,41 @@ static void imx_mu_txdb_work(struct work_struct *t) mbox_chan_txdone(cp->chan, 0); } +static irqreturn_t imx_mu_isr_th(int irq, void *p) +{ + struct mbox_chan *chan = p; + struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox); + struct imx_mu_con_priv *cp = chan->con_priv; + + switch (cp->type) { + case IMX_MU_TYPE_TX: + mbox_chan_txdone(chan, 0); + break; + + case IMX_MU_TYPE_RX: + if (!priv->dcfg->rx(priv, cp)) + imx_mu_xcr_set_act(priv, cp, IMX_MU_RCR, IMX_MU_xCR_RIEn(priv->dcfg->type, cp->idx)); + break; + + case IMX_MU_TYPE_RXDB: + if (!priv->dcfg->rxdb(priv, cp)) + imx_mu_xcr_set_act(priv, cp, IMX_MU_GIER, IMX_MU_xCR_GIEn(priv->dcfg->type, cp->idx)); + break; + + default: + dev_warn_ratelimited(priv->dev, "Unhandled channel type %d\n", + cp->type); + return IRQ_NONE; + } + return IRQ_HANDLED; +} + static irqreturn_t imx_mu_isr(int irq, void *p) { struct mbox_chan *chan = p; struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox); struct imx_mu_con_priv *cp = chan->con_priv; + irqreturn_t ret = IRQ_HANDLED; u32 val, ctrl; switch (cp->type) { @@ -548,13 +603,15 @@ static irqreturn_t imx_mu_isr(int irq, void *p) if ((val == IMX_MU_xSR_TEn(priv->dcfg->type, cp->idx)) && (cp->type == IMX_MU_TYPE_TX)) { imx_mu_xcr_rmw(priv, IMX_MU_TCR, 0, IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx)); - mbox_chan_txdone(chan, 0); + ret = IRQ_WAKE_THREAD; } else if ((val == IMX_MU_xSR_RFn(priv->dcfg->type, cp->idx)) && (cp->type == IMX_MU_TYPE_RX)) { - priv->dcfg->rx(priv, cp); + imx_mu_xcr_rmw(priv, IMX_MU_RCR, 0, IMX_MU_xCR_RIEn(priv->dcfg->type, cp->idx)); + ret = IRQ_WAKE_THREAD; } else if ((val == IMX_MU_xSR_GIPn(priv->dcfg->type, cp->idx)) && (cp->type == IMX_MU_TYPE_RXDB)) { - priv->dcfg->rxdb(priv, cp); + imx_mu_xcr_rmw(priv, IMX_MU_GIER, 0, IMX_MU_xCR_GIEn(priv->dcfg->type, cp->idx)); + ret = IRQ_WAKE_THREAD; } else { dev_warn_ratelimited(priv->dev, "Not handled interrupt\n"); return IRQ_NONE; @@ -563,7 +620,7 @@ static irqreturn_t imx_mu_isr(int irq, void *p) if (priv->suspend) pm_system_wakeup(); - return IRQ_HANDLED; + return ret; } static int imx_mu_send_data(struct mbox_chan *chan, void *data) @@ -578,7 +635,7 @@ static int imx_mu_startup(struct mbox_chan *chan) { struct imx_mu_priv *priv = to_imx_mu_priv(chan->mbox); struct imx_mu_con_priv *cp = chan->con_priv; - unsigned long irq_flag = 0; + unsigned long irq_flag = IRQF_NO_THREAD; int ret; pm_runtime_get_sync(priv->dev); @@ -598,12 +655,14 @@ static int imx_mu_startup(struct mbox_chan *chan) if (!(priv->dcfg->type & IMX_MU_V2_IRQ)) irq_flag |= IRQF_SHARED; - ret = request_irq(priv->irq[cp->type], imx_mu_isr, irq_flag, cp->irq_desc, chan); + ret = request_threaded_irq(priv->irq[cp->type], imx_mu_isr, imx_mu_isr_th, + irq_flag, cp->irq_desc, chan); if (ret) { dev_err(priv->dev, "Unable to acquire IRQ %d\n", priv->irq[cp->type]); return ret; } + cp->shutdown = false; switch (cp->type) { case IMX_MU_TYPE_RX: imx_mu_xcr_rmw(priv, IMX_MU_RCR, IMX_MU_xCR_RIEn(priv->dcfg->type, cp->idx), 0); @@ -638,13 +697,13 @@ static void imx_mu_shutdown(struct mbox_chan *chan) switch (cp->type) { case IMX_MU_TYPE_TX: - imx_mu_xcr_rmw(priv, IMX_MU_TCR, 0, IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx)); + imx_mu_xcr_clr_shut(priv, cp, IMX_MU_TCR, IMX_MU_xCR_TIEn(priv->dcfg->type, cp->idx)); break; case IMX_MU_TYPE_RX: - imx_mu_xcr_rmw(priv, IMX_MU_RCR, 0, IMX_MU_xCR_RIEn(priv->dcfg->type, cp->idx)); + imx_mu_xcr_clr_shut(priv, cp, IMX_MU_RCR, IMX_MU_xCR_RIEn(priv->dcfg->type, cp->idx)); break; case IMX_MU_TYPE_RXDB: - imx_mu_xcr_rmw(priv, IMX_MU_GIER, 0, IMX_MU_xCR_GIEn(priv->dcfg->type, cp->idx)); + imx_mu_xcr_clr_shut(priv, cp, IMX_MU_GIER, IMX_MU_xCR_GIEn(priv->dcfg->type, cp->idx)); break; case IMX_MU_TYPE_RST: imx_mu_xcr_rmw(priv, IMX_MU_CR, IMX_MU_xCR_RST(priv->dcfg->type), 0); @@ -924,7 +983,7 @@ static int imx_mu_probe(struct platform_device *pdev) goto disable_clk; } - spin_lock_init(&priv->xcr_lock); + raw_spin_lock_init(&priv->xcr_lock); priv->mbox.dev = dev; priv->mbox.ops = &imx_mu_ops; @@ -933,38 +992,36 @@ static int imx_mu_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); - ret = devm_mbox_controller_register(dev, &priv->mbox); - if (ret) + ret = devm_pm_runtime_enable(dev); + if (ret < 0) goto disable_clk; - of_platform_populate(dev->of_node, NULL, NULL, dev); - - pm_runtime_enable(dev); - ret = pm_runtime_resume_and_get(dev); if (ret < 0) - goto disable_runtime_pm; + goto disable_clk; ret = pm_runtime_put_sync(dev); if (ret < 0) - goto disable_runtime_pm; + goto disable_clk; clk_disable_unprepare(priv->clk); + ret = devm_mbox_controller_register(dev, &priv->mbox); + if (ret) + goto err_out; + + devm_of_platform_populate(dev); + return 0; -disable_runtime_pm: - pm_runtime_disable(dev); disable_clk: clk_disable_unprepare(priv->clk); +err_out: return ret; } static void imx_mu_remove(struct platform_device *pdev) { - struct imx_mu_priv *priv = platform_get_drvdata(pdev); - - pm_runtime_disable(priv->dev); } static const struct imx_mu_dcfg imx_mu_cfg_imx6sx = { diff --git a/drivers/mailbox/mailbox-mpfs.c b/drivers/mailbox/mailbox-mpfs.c index d5d9effece97..ef40fe2be30d 100644 --- a/drivers/mailbox/mailbox-mpfs.c +++ b/drivers/mailbox/mailbox-mpfs.c @@ -201,7 +201,7 @@ static irqreturn_t mpfs_mbox_inbox_isr(int irq, void *data) struct mbox_chan *chan = data; struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv; - if (mbox->control_scb) + if (mbox->sysreg_scb) regmap_write(mbox->sysreg_scb, MESSAGE_INT_OFFSET, 0); else writel_relaxed(0, mbox->int_reg); diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c index bbc9fd75a95f..efacd24a085d 100644 --- a/drivers/mailbox/mailbox.c +++ b/drivers/mailbox/mailbox.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -16,6 +17,7 @@ #include #include #include +#include #include static LIST_HEAD(mbox_cons); @@ -98,8 +100,10 @@ static void tx_tick(struct mbox_chan *chan, int r) if (chan->cl->tx_done) chan->cl->tx_done(chan->cl, mssg, r); - if (r != -ETIME && chan->cl->tx_block) + if (r != -ETIME && chan->cl->tx_block) { + chan->tx_status = r; complete(&chan->tx_complete); + } } static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer) @@ -258,6 +262,10 @@ EXPORT_SYMBOL_GPL(mbox_chan_tx_slots_available); * over the chan, i.e, tx_done() is made. * This function could be called from atomic context as it simply * queues the data and returns a token against the request. + * In blocking mode, it is caller's responsibility to serialize threads' + * access to a channel if multi-threads are to send messages through the + * same channel, i.e. caller should not call this function until any + * previous call returns. * * Return: Non-negative integer for successful submission (non-blocking mode) * or transmission over chan (blocking mode). @@ -291,6 +299,8 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg) if (ret == 0) { t = -ETIME; tx_tick(chan, t); + } else if (chan->tx_status < 0) { + t = chan->tx_status; } } @@ -327,6 +337,19 @@ int mbox_flush(struct mbox_chan *chan, unsigned long timeout) } EXPORT_SYMBOL_GPL(mbox_flush); +static void mbox_clean_and_put_channel(struct mbox_chan *chan) +{ + /* The queued TX requests are simply aborted, no callbacks are made */ + scoped_guard(spinlock_irqsave, &chan->lock) { + chan->cl = NULL; + chan->active_req = MBOX_NO_MSG; + if (chan->txdone_method == MBOX_TXDONE_BY_ACK) + chan->txdone_method = MBOX_TXDONE_BY_POLL; + } + + module_put(chan->mbox->dev->driver->owner); +} + static int __mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl) { struct device *dev = cl->dev; @@ -350,10 +373,9 @@ static int __mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl) if (chan->mbox->ops->startup) { ret = chan->mbox->ops->startup(chan); - if (ret) { dev_err(dev, "Unable to startup the chan (%d)\n", ret); - mbox_free_channel(chan); + mbox_clean_and_put_channel(chan); return ret; } } @@ -495,15 +517,7 @@ void mbox_free_channel(struct mbox_chan *chan) if (chan->mbox->ops->shutdown) chan->mbox->ops->shutdown(chan); - /* The queued TX requests are simply aborted, no callbacks are made */ - scoped_guard(spinlock_irqsave, &chan->lock) { - chan->cl = NULL; - chan->active_req = MBOX_NO_MSG; - if (chan->txdone_method == MBOX_TXDONE_BY_ACK) - chan->txdone_method = MBOX_TXDONE_BY_POLL; - } - - module_put(chan->mbox->dev->driver->owner); + mbox_clean_and_put_channel(chan); } EXPORT_SYMBOL_GPL(mbox_free_channel); @@ -632,3 +646,66 @@ int devm_mbox_controller_register(struct device *dev, return 0; } EXPORT_SYMBOL_GPL(devm_mbox_controller_register); + +#ifdef CONFIG_DEBUG_FS +static void *mbox_seq_start(struct seq_file *s, loff_t *pos) +{ + mutex_lock(&con_mutex); + return seq_list_start(&mbox_cons, *pos); +} + +static void *mbox_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + return seq_list_next(v, &mbox_cons, pos); +} + +static void mbox_seq_stop(struct seq_file *s, void *v) +{ + mutex_unlock(&con_mutex); +} + +static int mbox_seq_show(struct seq_file *seq, void *v) +{ + const struct mbox_controller *mbox = list_entry(v, struct mbox_controller, node); + + seq_printf(seq, "%s:\n", dev_name(mbox->dev)); + + for (unsigned int i = 0; i < mbox->num_chans; i++) { + struct mbox_chan *chan = &mbox->chans[i]; + + scoped_guard(spinlock_irqsave, &chan->lock) { + if (chan->cl) { + struct device *cl_dev = chan->cl->dev; + + seq_printf(seq, " %3u: %s\n", i, + cl_dev ? dev_name(cl_dev) : "NULL device"); + } + } + } + + return 0; +} + +static const struct seq_operations mbox_sops = { + .start = mbox_seq_start, + .next = mbox_seq_next, + .stop = mbox_seq_stop, + .show = mbox_seq_show, +}; +DEFINE_SEQ_ATTRIBUTE(mbox); + +/* + * subsys_initcall() is used here but controllers may already have been + * registered earlier or will be later. The rationale is that debugfs is + * accessed only late, i.e. from userspace. So, files created here must make no + * assumptions about initcall ordering. + */ +static int __init mbox_init(void) +{ + struct dentry *mbox_debugfs = debugfs_create_dir("mailbox", NULL); + + debugfs_create_file("mailbox_summary", 0444, mbox_debugfs, NULL, &mbox_fops); + return 0; +} +subsys_initcall(mbox_init); +#endif /* DEBUG_FS */ diff --git a/drivers/mailbox/mtk-adsp-mailbox.c b/drivers/mailbox/mtk-adsp-mailbox.c index 91487aa4d7da..8bcecddee0eb 100644 --- a/drivers/mailbox/mtk-adsp-mailbox.c +++ b/drivers/mailbox/mtk-adsp-mailbox.c @@ -19,6 +19,7 @@ struct mtk_adsp_mbox_priv { struct mbox_controller mbox; void __iomem *va_mboxreg; const struct mtk_adsp_mbox_cfg *cfg; + int irq; }; struct mtk_adsp_mbox_cfg { @@ -67,6 +68,8 @@ static int mtk_adsp_mbox_startup(struct mbox_chan *chan) writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_in); writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_out); + enable_irq(priv->irq); + return 0; } @@ -74,6 +77,8 @@ static void mtk_adsp_mbox_shutdown(struct mbox_chan *chan) { struct mtk_adsp_mbox_priv *priv = get_mtk_adsp_mbox_priv(chan->mbox); + disable_irq(priv->irq); + /* Clear ADSP mbox command */ writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_in); writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_out); @@ -139,8 +144,10 @@ static int mtk_adsp_mbox_probe(struct platform_device *pdev) if (irq < 0) return irq; + priv->irq = irq; ret = devm_request_threaded_irq(dev, irq, mtk_adsp_mbox_irq, - mtk_adsp_mbox_isr, IRQF_TRIGGER_NONE, + mtk_adsp_mbox_isr, + IRQF_TRIGGER_NONE | IRQF_NO_AUTOEN, dev_name(dev), mbox->chans); if (ret < 0) return ret; diff --git a/drivers/mailbox/qcom-cpucp-mbox.c b/drivers/mailbox/qcom-cpucp-mbox.c index 44f4ed15f818..862e45e8fbd5 100644 --- a/drivers/mailbox/qcom-cpucp-mbox.c +++ b/drivers/mailbox/qcom-cpucp-mbox.c @@ -12,7 +12,6 @@ #include #include -#define APSS_CPUCP_IPC_CHAN_SUPPORTED 3 #define APSS_CPUCP_MBOX_CMD_OFF 0x4 /* Tx Registers */ @@ -26,6 +25,14 @@ #define APSS_CPUCP_RX_MBOX_EN 0x4c00 #define APSS_CPUCP_RX_MBOX_CMD_MASK GENMASK_ULL(63, 0) +/** + * struct qcom_cpucp_mbox_data - Per-hardware mailbox configuration data + * @num_chans: Number of IPC channels supported by this hardware + */ +struct qcom_cpucp_mbox_data { + int num_chans; +}; + /** * struct qcom_cpucp_mbox - Holder for the mailbox driver * @chans: The mailbox channel @@ -34,7 +41,7 @@ * @rx_base: Base address of the CPUCP rx registers */ struct qcom_cpucp_mbox { - struct mbox_chan chans[APSS_CPUCP_IPC_CHAN_SUPPORTED]; + struct mbox_chan *chans; struct mbox_controller mbox; void __iomem *tx_base; void __iomem *rx_base; @@ -53,7 +60,7 @@ static irqreturn_t qcom_cpucp_mbox_irq_fn(int irq, void *data) status = readq(cpucp->rx_base + APSS_CPUCP_RX_MBOX_STAT); - for_each_set_bit(i, (unsigned long *)&status, APSS_CPUCP_IPC_CHAN_SUPPORTED) { + for_each_set_bit(i, (unsigned long *)&status, cpucp->mbox.num_chans) { u32 val = readl(cpucp->rx_base + APSS_CPUCP_RX_MBOX_CMD(i) + APSS_CPUCP_MBOX_CMD_OFF); struct mbox_chan *chan = &cpucp->chans[i]; unsigned long flags; @@ -112,15 +119,24 @@ static const struct mbox_chan_ops qcom_cpucp_mbox_chan_ops = { static int qcom_cpucp_mbox_probe(struct platform_device *pdev) { + const struct qcom_cpucp_mbox_data *data; struct device *dev = &pdev->dev; struct qcom_cpucp_mbox *cpucp; struct mbox_controller *mbox; int irq, ret; + data = of_device_get_match_data(dev); + if (!data) + return dev_err_probe(dev, -EINVAL, "No match data found\n"); + cpucp = devm_kzalloc(dev, sizeof(*cpucp), GFP_KERNEL); if (!cpucp) return -ENOMEM; + cpucp->chans = devm_kcalloc(dev, data->num_chans, sizeof(*cpucp->chans), GFP_KERNEL); + if (!cpucp->chans) + return -ENOMEM; + cpucp->rx_base = devm_of_iomap(dev, dev->of_node, 0, NULL); if (IS_ERR(cpucp->rx_base)) return PTR_ERR(cpucp->rx_base); @@ -146,7 +162,7 @@ static int qcom_cpucp_mbox_probe(struct platform_device *pdev) mbox = &cpucp->mbox; mbox->dev = dev; - mbox->num_chans = APSS_CPUCP_IPC_CHAN_SUPPORTED; + mbox->num_chans = data->num_chans; mbox->chans = cpucp->chans; mbox->ops = &qcom_cpucp_mbox_chan_ops; @@ -157,8 +173,17 @@ static int qcom_cpucp_mbox_probe(struct platform_device *pdev) return 0; } +static const struct qcom_cpucp_mbox_data qcom_x1e80100_mbox_data = { + .num_chans = 3, +}; + +static const struct qcom_cpucp_mbox_data qcom_nord_mbox_data = { + .num_chans = 16, +}; + static const struct of_device_id qcom_cpucp_mbox_of_match[] = { - { .compatible = "qcom,x1e80100-cpucp-mbox" }, + { .compatible = "qcom,nord-cpucp-mbox", .data = &qcom_nord_mbox_data }, + { .compatible = "qcom,x1e80100-cpucp-mbox", .data = &qcom_x1e80100_mbox_data }, {} }; MODULE_DEVICE_TABLE(of, qcom_cpucp_mbox_of_match); diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h index dc93287a2a01..26a238a6f941 100644 --- a/include/linux/mailbox_controller.h +++ b/include/linux/mailbox_controller.h @@ -120,6 +120,7 @@ struct mbox_controller { * @txdone_method: Way to detect TXDone chosen by the API * @cl: Pointer to the current owner of this channel * @tx_complete: Transmission completion + * @tx_status: Transmission status * @active_req: Currently active request hook * @msg_count: No. of mssg currently queued * @msg_free: Index of next available mssg slot @@ -132,6 +133,7 @@ struct mbox_chan { unsigned txdone_method; struct mbox_client *cl; struct completion tx_complete; + int tx_status; void *active_req; unsigned msg_count, msg_free; void *msg_data[MBOX_TX_QUEUE_LEN];