From 60de2d2dc284e0dd1c2c897d08625bde24ef3454 Mon Sep 17 00:00:00 2001 From: Pekka Pessi Date: Wed, 2 Mar 2022 16:04:24 +0100 Subject: [PATCH 01/19] mailbox: tegra-hsp: Flush whole channel The txdone can re-fill the mailbox. Keep polling the mailbox during the flush until all the messages have been delivered. This fixes an issue with the Tegra Combined UART (TCU) where output can get truncated under high traffic load. Signed-off-by: Pekka Pessi Tested-by: Jon Hunter Fixes: 91b1b1c3da8a ("mailbox: tegra-hsp: Add support for shared mailboxes") Cc: stable@vger.kernel.org Signed-off-by: Thierry Reding Reviewed-by: Jon Hunter Signed-off-by: Jassi Brar --- drivers/mailbox/tegra-hsp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c index acd0675da681e..78f7265039c66 100644 --- a/drivers/mailbox/tegra-hsp.c +++ b/drivers/mailbox/tegra-hsp.c @@ -412,6 +412,11 @@ static int tegra_hsp_mailbox_flush(struct mbox_chan *chan, value = tegra_hsp_channel_readl(ch, HSP_SM_SHRD_MBOX); if ((value & HSP_SM_SHRD_MBOX_FULL) == 0) { mbox_chan_txdone(chan, 0); + + /* Wait until channel is empty */ + if (chan->active_req != NULL) + continue; + return 0; } From bcc8d70f912df5b3ad315155bcc0208b699d24d2 Mon Sep 17 00:00:00 2001 From: Adam Skladowski Date: Mon, 7 Mar 2022 20:17:22 +0100 Subject: [PATCH 02/19] dt-bindings: mailbox: Add compatible for the MSM8976 Add the mailbox compatible for the MSM8976 SoC. Signed-off-by: Adam Skladowski Acked-by: Krzysztof Kozlowski Signed-off-by: Jassi Brar --- .../devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml b/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml index 01e9d9155c836..3b5ba7ecc19d9 100644 --- a/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml +++ b/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml @@ -21,6 +21,7 @@ properties: - qcom,msm8916-apcs-kpss-global - qcom,msm8939-apcs-kpss-global - qcom,msm8953-apcs-kpss-global + - qcom,msm8976-apcs-kpss-global - qcom,msm8994-apcs-kpss-global - qcom,msm8996-apcs-hmss-global - qcom,msm8998-apcs-hmss-global From 5c0fab31caddac96be18877d10e0b9b24ff8fb32 Mon Sep 17 00:00:00 2001 From: Adam Skladowski Date: Mon, 7 Mar 2022 20:17:23 +0100 Subject: [PATCH 03/19] mailbox: qcom-apcs-ipc: Add compatible for MSM8976 SoC MSM8976 APCS block is similar to one found in MSM8994. Signed-off-by: Adam Skladowski Signed-off-by: Jassi Brar --- drivers/mailbox/qcom-apcs-ipc-mailbox.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mailbox/qcom-apcs-ipc-mailbox.c b/drivers/mailbox/qcom-apcs-ipc-mailbox.c index 9325d2abc745b..80a54d81412e3 100644 --- a/drivers/mailbox/qcom-apcs-ipc-mailbox.c +++ b/drivers/mailbox/qcom-apcs-ipc-mailbox.c @@ -146,6 +146,7 @@ static const struct of_device_id qcom_apcs_ipc_of_match[] = { { .compatible = "qcom,msm8916-apcs-kpss-global", .data = &msm8916_apcs_data }, { .compatible = "qcom,msm8939-apcs-kpss-global", .data = &msm8916_apcs_data }, { .compatible = "qcom,msm8953-apcs-kpss-global", .data = &msm8994_apcs_data }, + { .compatible = "qcom,msm8976-apcs-kpss-global", .data = &msm8994_apcs_data }, { .compatible = "qcom,msm8994-apcs-kpss-global", .data = &msm8994_apcs_data }, { .compatible = "qcom,msm8996-apcs-hmss-global", .data = &msm8996_apcs_data }, { .compatible = "qcom,msm8998-apcs-hmss-global", .data = &msm8994_apcs_data }, From afa092e1e8824363d3174fef329c034445c111d5 Mon Sep 17 00:00:00 2001 From: Allen-KH Cheng Date: Fri, 25 Feb 2022 21:24:26 +0800 Subject: [PATCH 04/19] dt-bindings: mailbox: mtk,adsp-mbox: add mtk adsp-mbox document This patch adds document for mediatek adsp mbox Signed-off-by: Allen-KH Cheng Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Rob Herring Signed-off-by: Jassi Brar --- .../bindings/mailbox/mtk,adsp-mbox.yaml | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 Documentation/devicetree/bindings/mailbox/mtk,adsp-mbox.yaml diff --git a/Documentation/devicetree/bindings/mailbox/mtk,adsp-mbox.yaml b/Documentation/devicetree/bindings/mailbox/mtk,adsp-mbox.yaml new file mode 100644 index 0000000000000..fe454a1fba17a --- /dev/null +++ b/Documentation/devicetree/bindings/mailbox/mtk,adsp-mbox.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mailbox/mtk,adsp-mbox.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mediatek ADSP mailbox + +maintainers: + - Allen-KH Cheng + +description: | + The MTK ADSP mailbox Inter-Processor Communication (IPC) enables the SoC + to ommunicate with ADSP by passing messages through two mailbox channels. + The MTK ADSP mailbox IPC also provides the ability for one processor to + signal the other processor using interrupts. + +properties: + compatible: + items: + - const: mediatek,mt8195-adsp-mbox + + "#mbox-cells": + const: 0 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - "#mbox-cells" + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include + #include + + adsp_mailbox0:mailbox@10816000 { + compatible = "mediatek,mt8195-adsp-mbox"; + #mbox-cells = <0>; + reg = <0x10816000 0x1000>; + interrupts = ; + }; From af2dfa96c52d042df5deb29fb6e32d3ff4d76a61 Mon Sep 17 00:00:00 2001 From: Allen-KH Cheng Date: Fri, 25 Feb 2022 21:24:27 +0800 Subject: [PATCH 05/19] mailbox: mediatek: add support for adsp mailbox controller This patch is to for MediaTek ADSP IPC mailbox controller driver It is used to send short messages between processors with adsp Signed-off-by: Allen-KH Cheng Reviewed-by: Tzung-Bi Shih Reviewed-by: YC Hung Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Jassi Brar --- drivers/mailbox/Kconfig | 9 ++ drivers/mailbox/Makefile | 2 + drivers/mailbox/mtk-adsp-mailbox.c | 176 +++++++++++++++++++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 drivers/mailbox/mtk-adsp-mailbox.c diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index d9cd3606040e7..05d6fae800e37 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -238,6 +238,15 @@ config STM32_IPCC with hardware for Inter-Processor Communication Controller (IPCC) between processors. Say Y here if you want to have this support. +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. + 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. + config MTK_CMDQ_MBOX tristate "MediaTek CMDQ Mailbox Support" depends on ARCH_MEDIATEK || COMPILE_TEST diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index 338cc05e5431f..fc93761171113 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -49,6 +49,8 @@ obj-$(CONFIG_TEGRA_HSP_MBOX) += tegra-hsp.o obj-$(CONFIG_STM32_IPCC) += stm32-ipcc.o +obj-$(CONFIG_MTK_ADSP_MBOX) += mtk-adsp-mailbox.o + obj-$(CONFIG_MTK_CMDQ_MBOX) += mtk-cmdq-mailbox.o obj-$(CONFIG_ZYNQMP_IPI_MBOX) += zynqmp-ipi-mailbox.o diff --git a/drivers/mailbox/mtk-adsp-mailbox.c b/drivers/mailbox/mtk-adsp-mailbox.c new file mode 100644 index 0000000000000..5e7378090c7bc --- /dev/null +++ b/drivers/mailbox/mtk-adsp-mailbox.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 MediaTek Corporation. All rights reserved. + * Author: Allen-KH Cheng + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct mtk_adsp_mbox_priv { + struct device *dev; + struct mbox_controller mbox; + void __iomem *va_mboxreg; + const struct mtk_adsp_mbox_cfg *cfg; +}; + +struct mtk_adsp_mbox_cfg { + u32 set_in; + u32 set_out; + u32 clr_in; + u32 clr_out; +}; + +static inline struct mtk_adsp_mbox_priv *get_mtk_adsp_mbox_priv(struct mbox_controller *mbox) +{ + return container_of(mbox, struct mtk_adsp_mbox_priv, mbox); +} + +static irqreturn_t mtk_adsp_mbox_irq(int irq, void *data) +{ + struct mbox_chan *chan = data; + struct mtk_adsp_mbox_priv *priv = get_mtk_adsp_mbox_priv(chan->mbox); + u32 op = readl(priv->va_mboxreg + priv->cfg->set_out); + + writel(op, priv->va_mboxreg + priv->cfg->clr_out); + + return IRQ_WAKE_THREAD; +} + +static irqreturn_t mtk_adsp_mbox_isr(int irq, void *data) +{ + struct mbox_chan *chan = data; + + mbox_chan_received_data(chan, NULL); + + return IRQ_HANDLED; +} + +static struct mbox_chan *mtk_adsp_mbox_xlate(struct mbox_controller *mbox, + const struct of_phandle_args *sp) +{ + return mbox->chans; +} + +static int mtk_adsp_mbox_startup(struct mbox_chan *chan) +{ + struct mtk_adsp_mbox_priv *priv = get_mtk_adsp_mbox_priv(chan->mbox); + + /* Clear ADSP mbox command */ + writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_in); + writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_out); + + return 0; +} + +static void mtk_adsp_mbox_shutdown(struct mbox_chan *chan) +{ + struct mtk_adsp_mbox_priv *priv = get_mtk_adsp_mbox_priv(chan->mbox); + + /* Clear ADSP mbox command */ + writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_in); + writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_out); +} + +static int mtk_adsp_mbox_send_data(struct mbox_chan *chan, void *data) +{ + struct mtk_adsp_mbox_priv *priv = get_mtk_adsp_mbox_priv(chan->mbox); + u32 *msg = data; + + writel(*msg, priv->va_mboxreg + priv->cfg->set_in); + + return 0; +} + +static bool mtk_adsp_mbox_last_tx_done(struct mbox_chan *chan) +{ + struct mtk_adsp_mbox_priv *priv = get_mtk_adsp_mbox_priv(chan->mbox); + + return readl(priv->va_mboxreg + priv->cfg->set_in) == 0; +} + +static const struct mbox_chan_ops mtk_adsp_mbox_chan_ops = { + .send_data = mtk_adsp_mbox_send_data, + .startup = mtk_adsp_mbox_startup, + .shutdown = mtk_adsp_mbox_shutdown, + .last_tx_done = mtk_adsp_mbox_last_tx_done, +}; + +static int mtk_adsp_mbox_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mtk_adsp_mbox_priv *priv; + const struct mtk_adsp_mbox_cfg *cfg; + struct mbox_controller *mbox; + int ret, irq; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + mbox = &priv->mbox; + mbox->dev = dev; + mbox->ops = &mtk_adsp_mbox_chan_ops; + mbox->txdone_irq = false; + mbox->txdone_poll = true; + mbox->of_xlate = mtk_adsp_mbox_xlate; + mbox->num_chans = 1; + mbox->chans = devm_kzalloc(dev, sizeof(*mbox->chans), GFP_KERNEL); + if (!mbox->chans) + return -ENOMEM; + + priv->va_mboxreg = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->va_mboxreg)) + return PTR_ERR(priv->va_mboxreg); + + cfg = of_device_get_match_data(dev); + if (!cfg) + return -EINVAL; + priv->cfg = cfg; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = devm_request_threaded_irq(dev, irq, mtk_adsp_mbox_irq, + mtk_adsp_mbox_isr, IRQF_TRIGGER_NONE, + dev_name(dev), mbox->chans); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, priv); + + return devm_mbox_controller_register(dev, &priv->mbox); +} + +static const struct mtk_adsp_mbox_cfg mt8195_adsp_mbox_cfg = { + .set_in = 0x00, + .set_out = 0x1c, + .clr_in = 0x04, + .clr_out = 0x20, +}; + +static const struct of_device_id mtk_adsp_mbox_of_match[] = { + { .compatible = "mediatek,mt8195-adsp-mbox", .data = &mt8195_adsp_mbox_cfg }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtk_adsp_mbox_of_match); + +static struct platform_driver mtk_adsp_mbox_driver = { + .probe = mtk_adsp_mbox_probe, + .driver = { + .name = "mtk_adsp_mbox", + .of_match_table = mtk_adsp_mbox_of_match, + }, +}; +module_platform_driver(mtk_adsp_mbox_driver); + +MODULE_AUTHOR("Allen-KH Cheng "); +MODULE_DESCRIPTION("MTK ADSP Mailbox Controller"); +MODULE_LICENSE("GPL v2"); From 892cb524ae8a27bf5e42f711318371acd9a9f74a Mon Sep 17 00:00:00 2001 From: Robin Gong Date: Mon, 7 Feb 2022 09:52:06 +0800 Subject: [PATCH 06/19] mailbox: imx: fix wakeup failure from freeze mode Since IRQF_NO_SUSPEND used for imx mailbox driver, that means this irq can't be used for wakeup source so that can't wakeup from freeze mode. Add pm_system_wakeup() to wakeup from freeze mode. Fixes: b7b2796b9b31e("mailbox: imx: ONLY IPC MU needs IRQF_NO_SUSPEND flag") Reviewed-by: Jacky Bai Reviewed-by: Peng Fan Signed-off-by: Robin Gong Signed-off-by: Peng Fan Signed-off-by: Jassi Brar --- drivers/mailbox/imx-mailbox.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index 544de2db64531..8b1399e5d7bf7 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #define IMX_MU_CHANS 16 @@ -76,6 +77,7 @@ struct imx_mu_priv { const struct imx_mu_dcfg *dcfg; struct clk *clk; int irq; + bool suspend; u32 xcr[4]; @@ -334,6 +336,9 @@ static irqreturn_t imx_mu_isr(int irq, void *p) return IRQ_NONE; } + if (priv->suspend) + pm_system_wakeup(); + return IRQ_HANDLED; } @@ -702,6 +707,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; + return 0; } @@ -723,6 +730,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; + return 0; } From 8219efd08a0aa1d7944bdb66d84ba57549258968 Mon Sep 17 00:00:00 2001 From: Robin Gong Date: Mon, 7 Feb 2022 09:52:07 +0800 Subject: [PATCH 07/19] mailbox: imx: fix crash in resume on i.mx8ulp check 'priv->clk' before 'imx_mu_read()' otherwise crash happens on i.mx8ulp, since clock not enabled. Fixes: 4f0b776ef5831 ("mailbox: imx-mailbox: support i.MX8ULP MU") Reviewed-by: Jacky Bai Signed-off-by: Robin Gong Signed-off-by: Peng Fan Signed-off-by: Jassi Brar --- drivers/mailbox/imx-mailbox.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index 8b1399e5d7bf7..a0c252415c868 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -725,7 +725,7 @@ static int __maybe_unused imx_mu_resume_noirq(struct device *dev) * send failed, may lead to system freeze. This issue * is observed by testing freeze mode suspend. */ - if (!imx_mu_read(priv, priv->dcfg->xCR[0]) && !priv->clk) { + if (!priv->clk && !imx_mu_read(priv, priv->dcfg->xCR[0])) { for (i = 0; i < IMX_MU_xCR_MAX; i++) imx_mu_write(priv, priv->xcr[i], priv->dcfg->xCR[i]); } From 81a9d3b9301c9bb835d8ef595b2456084573db1b Mon Sep 17 00:00:00 2001 From: Ranjani Vaidyanathan Date: Mon, 7 Feb 2022 09:52:08 +0800 Subject: [PATCH 08/19] mailbox: imx: enlarge timeout while reading/writing messages to SCFW Mailbox driver needs to wait and read all the words in response to a SCFW API call, else the protocol gets messed up and results in kernel hang. When the responses are longer than 3 words its possible that SCFW will take some time to fill up the rest of the words in the MU, a timeout of 100us is arbritrary and too short. While waiting for Linux to consume the first 3 words of the response SCFW can be busy doing other stuff and hence Linux needs to wait for the rest of the words. Similar restriction applies when writing messages that are longer than 3 words. This patch increases the timeout to 5secs while waiting for response or writing long messages to SCFW. Signed-off-by: Ranjani Vaidyanathan Signed-off-by: Peng Fan Signed-off-by: Jassi Brar --- drivers/mailbox/imx-mailbox.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index a0c252415c868..a29f8006ad0de 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -218,7 +218,7 @@ static int imx_mu_specific_tx(struct imx_mu_priv *priv, struct imx_mu_con_priv * ret = readl_poll_timeout(priv->base + priv->dcfg->xSR[IMX_MU_TSR], xsr, xsr & IMX_MU_xSR_TEn(priv->dcfg->type, i % num_tr), - 0, 100); + 0, 5 * USEC_PER_SEC); if (ret) { dev_err(priv->dev, "Send data index: %d timeout\n", i); return ret; @@ -263,7 +263,8 @@ static int imx_mu_specific_rx(struct imx_mu_priv *priv, struct imx_mu_con_priv * for (i = 1; i < size; i++) { ret = readl_poll_timeout(priv->base + priv->dcfg->xSR[IMX_MU_RSR], xsr, - xsr & IMX_MU_xSR_RFn(priv->dcfg->type, i % 4), 0, 100); + xsr & IMX_MU_xSR_RFn(priv->dcfg->type, i % 4), 0, + 5 * USEC_PER_SEC); if (ret) { dev_err(priv->dev, "timeout read idx %d\n", i); return ret; From 960dcc1574c7432ad4ff42e8b153f098bdfd5c8d Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 7 Feb 2022 09:52:09 +0800 Subject: [PATCH 09/19] dt-bindings: mailbox: imx-mu: add i.MX8 SECO MU support Similar to i.MX8QM/QXP SCU, i.MX8 SECO MU is dedicated for communication between SECO and Cortex-A cores from hardware design, it could not be reused for other purpose. To use SECO MU more effectivly, add "fsl,imx8-mu-seco" compatile to support fast IPC. Acked-by: Rob Herring Signed-off-by: Peng Fan Signed-off-by: Jassi Brar --- Documentation/devicetree/bindings/mailbox/fsl,mu.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mailbox/fsl,mu.yaml b/Documentation/devicetree/bindings/mailbox/fsl,mu.yaml index a337bcd80c4a5..f865b806ae6a3 100644 --- a/Documentation/devicetree/bindings/mailbox/fsl,mu.yaml +++ b/Documentation/devicetree/bindings/mailbox/fsl,mu.yaml @@ -28,6 +28,7 @@ properties: - const: fsl,imx7ulp-mu - const: fsl,imx8ulp-mu - const: fsl,imx8-mu-scu + - const: fsl,imx8-mu-seco - const: fsl,imx8ulp-mu-s4 - items: - enum: From 315d2e5624183248514294899a26cb0fb3c20a46 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 7 Feb 2022 09:52:10 +0800 Subject: [PATCH 10/19] mailbox: imx: introduce rxdb callback Add a rxdb callback to prepare for i.MX8 SECO MU rxdb which has a different logic. Signed-off-by: Peng Fan Signed-off-by: Jassi Brar --- drivers/mailbox/imx-mailbox.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index a29f8006ad0de..399e12671bade 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -93,6 +93,7 @@ enum imx_mu_type { struct imx_mu_dcfg { int (*tx)(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp, void *data); int (*rx)(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp); + int (*rxdb)(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp); void (*init)(struct imx_mu_priv *priv); enum imx_mu_type type; u32 xTR; /* Transmit Register0 */ @@ -179,6 +180,16 @@ static int imx_mu_generic_rx(struct imx_mu_priv *priv, return 0; } +static int imx_mu_generic_rxdb(struct imx_mu_priv *priv, + struct imx_mu_con_priv *cp) +{ + imx_mu_write(priv, IMX_MU_xSR_GIPn(priv->dcfg->type, cp->idx), + priv->dcfg->xSR[IMX_MU_GSR]); + mbox_chan_received_data(cp->chan, NULL); + + return 0; +} + static int imx_mu_specific_tx(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp, void *data) { u32 *arg = data; @@ -329,9 +340,7 @@ static irqreturn_t imx_mu_isr(int irq, void *p) priv->dcfg->rx(priv, cp); } else if ((val == IMX_MU_xSR_GIPn(priv->dcfg->type, cp->idx)) && (cp->type == IMX_MU_TYPE_RXDB)) { - imx_mu_write(priv, IMX_MU_xSR_GIPn(priv->dcfg->type, cp->idx), - priv->dcfg->xSR[IMX_MU_GSR]); - mbox_chan_received_data(chan, NULL); + priv->dcfg->rxdb(priv, cp); } else { dev_warn_ratelimited(priv->dev, "Not handled interrupt\n"); return IRQ_NONE; @@ -639,6 +648,7 @@ static int imx_mu_remove(struct platform_device *pdev) static const struct imx_mu_dcfg imx_mu_cfg_imx6sx = { .tx = imx_mu_generic_tx, .rx = imx_mu_generic_rx, + .rxdb = imx_mu_generic_rxdb, .init = imx_mu_init_generic, .xTR = 0x0, .xRR = 0x10, @@ -649,6 +659,7 @@ static const struct imx_mu_dcfg imx_mu_cfg_imx6sx = { static const struct imx_mu_dcfg imx_mu_cfg_imx7ulp = { .tx = imx_mu_generic_tx, .rx = imx_mu_generic_rx, + .rxdb = imx_mu_generic_rxdb, .init = imx_mu_init_generic, .xTR = 0x20, .xRR = 0x40, @@ -659,7 +670,9 @@ static const struct imx_mu_dcfg imx_mu_cfg_imx7ulp = { static const struct imx_mu_dcfg imx_mu_cfg_imx8ulp = { .tx = imx_mu_generic_tx, .rx = imx_mu_generic_rx, + .rxdb = imx_mu_generic_rxdb, .init = imx_mu_init_generic, + .rxdb = imx_mu_generic_rxdb, .type = IMX_MU_V2, .xTR = 0x200, .xRR = 0x280, @@ -682,6 +695,7 @@ static const struct imx_mu_dcfg imx_mu_cfg_imx8_scu = { .tx = imx_mu_specific_tx, .rx = imx_mu_specific_rx, .init = imx_mu_init_specific, + .rxdb = imx_mu_generic_rxdb, .xTR = 0x0, .xRR = 0x10, .xSR = {0x20, 0x20, 0x20, 0x20}, From 11dac1d3fa422abc841dcd4f5222a79398b3cf98 Mon Sep 17 00:00:00 2001 From: Franck LENORMAND Date: Mon, 7 Feb 2022 09:52:11 +0800 Subject: [PATCH 11/19] mailbox: imx: add i.MX8 SECO MU support i.MX8/8X SECO firmware IPC is an implementation of passing messages. But current imx-mailbox driver only support one word message, i.MX8/8X linux side firmware has to request four TX, four RX and a TXDB to support IPC to SECO firmware. This is low efficent and more interrupts triggered compared with one TX and one RX. To make SECO MU work, - parse the size of msg. - Only enable TR0/RR0 interrupt for transmit/receive message. - For TX/RX, only support one TX channel and one RX channel - For RX, support receive msg of any size, limited by hardcoded value of 30. Signed-off-by: Franck LENORMAND Signed-off-by: Peng Fan Signed-off-by: Jassi Brar --- drivers/mailbox/imx-mailbox.c | 213 +++++++++++++++++++++++++++++++++- 1 file changed, 212 insertions(+), 1 deletion(-) diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index 399e12671bade..cd011ca5707ec 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,9 @@ #define IMX_MU_S4_CHANS 2 #define IMX_MU_CHAN_NAME_SIZE 20 +#define IMX_MU_SECO_TX_TOUT (msecs_to_jiffies(3000)) +#define IMX_MU_SECO_RX_TOUT (msecs_to_jiffies(3000)) + enum imx_mu_chan_type { IMX_MU_TYPE_TX, /* Tx */ IMX_MU_TYPE_RX, /* Rx */ @@ -48,7 +52,7 @@ enum imx_mu_xsr { struct imx_sc_rpc_msg_max { struct imx_sc_rpc_msg hdr; - u32 data[7]; + u32 data[30]; }; struct imx_s4_rpc_msg_max { @@ -131,6 +135,55 @@ static u32 imx_mu_read(struct imx_mu_priv *priv, u32 offs) return ioread32(priv->base + offs); } +static int imx_mu_tx_waiting_write(struct imx_mu_priv *priv, u32 val, u32 idx) +{ + u64 timeout_time = get_jiffies_64() + IMX_MU_SECO_TX_TOUT; + u32 status; + u32 can_write; + + dev_dbg(priv->dev, "Trying to write %.8x to idx %d\n", val, idx); + + do { + status = imx_mu_read(priv, priv->dcfg->xSR[IMX_MU_TSR]); + can_write = status & IMX_MU_xSR_TEn(priv->dcfg->type, idx % 4); + } while (!can_write && time_is_after_jiffies64(timeout_time)); + + if (!can_write) { + dev_err(priv->dev, "timeout trying to write %.8x at %d(%.8x)\n", + val, idx, status); + return -ETIME; + } + + imx_mu_write(priv, val, priv->dcfg->xTR + (idx % 4) * 4); + + return 0; +} + +static int imx_mu_rx_waiting_read(struct imx_mu_priv *priv, u32 *val, u32 idx) +{ + u64 timeout_time = get_jiffies_64() + IMX_MU_SECO_RX_TOUT; + u32 status; + u32 can_read; + + dev_dbg(priv->dev, "Trying to read from idx %d\n", idx); + + do { + status = imx_mu_read(priv, priv->dcfg->xSR[IMX_MU_RSR]); + can_read = status & IMX_MU_xSR_RFn(priv->dcfg->type, idx % 4); + } while (!can_read && time_is_after_jiffies64(timeout_time)); + + if (!can_read) { + dev_err(priv->dev, "timeout trying to read idx %d (%.8x)\n", + idx, status); + return -ETIME; + } + + *val = imx_mu_read(priv, priv->dcfg->xRR + (idx % 4) * 4); + dev_dbg(priv->dev, "Read %.8x\n", *val); + + return 0; +} + static u32 imx_mu_xcr_rmw(struct imx_mu_priv *priv, enum imx_mu_xcr type, u32 set, u32 clr) { unsigned long flags; @@ -289,6 +342,125 @@ static int imx_mu_specific_rx(struct imx_mu_priv *priv, struct imx_mu_con_priv * return 0; } +static int imx_mu_seco_tx(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp, + void *data) +{ + struct imx_sc_rpc_msg_max *msg = data; + u32 *arg = data; + u32 byte_size; + int err; + int i; + + dev_dbg(priv->dev, "Sending message\n"); + + switch (cp->type) { + case IMX_MU_TYPE_TXDB: + byte_size = msg->hdr.size * sizeof(u32); + if (byte_size > sizeof(*msg)) { + /* + * The real message size can be different to + * struct imx_sc_rpc_msg_max size + */ + dev_err(priv->dev, + "Exceed max msg size (%zu) on TX, got: %i\n", + sizeof(*msg), byte_size); + return -EINVAL; + } + + print_hex_dump_debug("from client ", DUMP_PREFIX_OFFSET, 4, 4, + data, byte_size, false); + + /* Send first word */ + dev_dbg(priv->dev, "Sending header\n"); + imx_mu_write(priv, *arg++, priv->dcfg->xTR); + + /* Send signaling */ + dev_dbg(priv->dev, "Sending signaling\n"); + imx_mu_xcr_rmw(priv, IMX_MU_GCR, + IMX_MU_xCR_GIRn(priv->dcfg->type, cp->idx), 0); + + /* Send words to fill the mailbox */ + for (i = 1; i < 4 && i < msg->hdr.size; i++) { + dev_dbg(priv->dev, "Sending word %d\n", i); + imx_mu_write(priv, *arg++, + priv->dcfg->xTR + (i % 4) * 4); + } + + /* Send rest of message waiting for remote read */ + for (; i < msg->hdr.size; i++) { + dev_dbg(priv->dev, "Sending word %d\n", i); + err = imx_mu_tx_waiting_write(priv, *arg++, i); + if (err) { + dev_err(priv->dev, "Timeout tx %d\n", i); + return err; + } + } + + /* Simulate hack for mbox framework */ + tasklet_schedule(&cp->txdb_tasklet); + + break; + default: + dev_warn_ratelimited(priv->dev, + "Send data on wrong channel type: %d\n", + cp->type); + return -EINVAL; + } + + return 0; +} + +static int imx_mu_seco_rxdb(struct imx_mu_priv *priv, struct imx_mu_con_priv *cp) +{ + struct imx_sc_rpc_msg_max msg; + u32 *data = (u32 *)&msg; + u32 byte_size; + int err = 0; + int i; + + dev_dbg(priv->dev, "Receiving message\n"); + + /* Read header */ + dev_dbg(priv->dev, "Receiving header\n"); + *data++ = imx_mu_read(priv, priv->dcfg->xRR); + byte_size = msg.hdr.size * sizeof(u32); + if (byte_size > sizeof(msg)) { + dev_err(priv->dev, "Exceed max msg size (%zu) on RX, got: %i\n", + sizeof(msg), byte_size); + err = -EINVAL; + goto error; + } + + /* Read message waiting they are written */ + for (i = 1; i < msg.hdr.size; i++) { + dev_dbg(priv->dev, "Receiving word %d\n", i); + err = imx_mu_rx_waiting_read(priv, data++, i); + if (err) { + dev_err(priv->dev, "Timeout rx %d\n", i); + goto error; + } + } + + /* Clear GIP */ + imx_mu_write(priv, IMX_MU_xSR_GIPn(priv->dcfg->type, cp->idx), + priv->dcfg->xSR[IMX_MU_GSR]); + + print_hex_dump_debug("to client ", DUMP_PREFIX_OFFSET, 4, 4, + &msg, byte_size, false); + + /* send data to client */ + dev_dbg(priv->dev, "Sending message to client\n"); + mbox_chan_received_data(cp->chan, (void *)&msg); + + goto exit; + +error: + mbox_chan_received_data(cp->chan, ERR_PTR(err)); + +exit: + return err; +} + static void imx_mu_txdb_tasklet(unsigned long data) { struct imx_mu_con_priv *cp = (struct imx_mu_con_priv *)data; @@ -494,6 +666,27 @@ static struct mbox_chan * imx_mu_xlate(struct mbox_controller *mbox, return &mbox->chans[chan]; } +static struct mbox_chan *imx_mu_seco_xlate(struct mbox_controller *mbox, + const struct of_phandle_args *sp) +{ + u32 type; + + if (sp->args_count < 1) { + dev_err(mbox->dev, "Invalid argument count %d\n", sp->args_count); + return ERR_PTR(-EINVAL); + } + + type = sp->args[0]; /* channel type */ + + /* Only supports TXDB and RXDB */ + if (type == IMX_MU_TYPE_TX || type == IMX_MU_TYPE_RX) { + dev_err(mbox->dev, "Invalid type: %d\n", type); + return ERR_PTR(-EINVAL); + } + + return imx_mu_xlate(mbox, sp); +} + static void imx_mu_init_generic(struct imx_mu_priv *priv) { unsigned int i; @@ -544,6 +737,12 @@ static void imx_mu_init_specific(struct imx_mu_priv *priv) imx_mu_write(priv, 0, priv->dcfg->xCR[i]); } +static void imx_mu_init_seco(struct imx_mu_priv *priv) +{ + imx_mu_init_generic(priv); + priv->mbox.of_xlate = imx_mu_seco_xlate; +} + static int imx_mu_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -702,12 +901,24 @@ static const struct imx_mu_dcfg imx_mu_cfg_imx8_scu = { .xCR = {0x24, 0x24, 0x24, 0x24}, }; +static const struct imx_mu_dcfg imx_mu_cfg_imx8_seco = { + .tx = imx_mu_seco_tx, + .rx = imx_mu_generic_rx, + .rxdb = imx_mu_seco_rxdb, + .init = imx_mu_init_seco, + .xTR = 0x0, + .xRR = 0x10, + .xSR = {0x20, 0x20, 0x20, 0x20}, + .xCR = {0x24, 0x24, 0x24, 0x24}, +}; + static const struct of_device_id imx_mu_dt_ids[] = { { .compatible = "fsl,imx7ulp-mu", .data = &imx_mu_cfg_imx7ulp }, { .compatible = "fsl,imx6sx-mu", .data = &imx_mu_cfg_imx6sx }, { .compatible = "fsl,imx8ulp-mu", .data = &imx_mu_cfg_imx8ulp }, { .compatible = "fsl,imx8ulp-mu-s4", .data = &imx_mu_cfg_imx8ulp_s4 }, { .compatible = "fsl,imx8-mu-scu", .data = &imx_mu_cfg_imx8_scu }, + { .compatible = "fsl,imx8-mu-seco", .data = &imx_mu_cfg_imx8_seco }, { }, }; MODULE_DEVICE_TABLE(of, imx_mu_dt_ids); From 6149a543adc7d7113dd47fc05eda973eefee5bf4 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 9 Mar 2022 18:03:41 +0800 Subject: [PATCH 12/19] dt-bindings: mailbox: imx-mu: add i.MX93 MU Add bindings for i.MX93 MU which derived from i.MX8ULP Reviewed-by: Krzysztof Kozlowski Acked-by: Rob Herring Signed-off-by: Peng Fan Signed-off-by: Jassi Brar --- Documentation/devicetree/bindings/mailbox/fsl,mu.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/mailbox/fsl,mu.yaml b/Documentation/devicetree/bindings/mailbox/fsl,mu.yaml index f865b806ae6a3..6d056d5e16bfa 100644 --- a/Documentation/devicetree/bindings/mailbox/fsl,mu.yaml +++ b/Documentation/devicetree/bindings/mailbox/fsl,mu.yaml @@ -30,6 +30,9 @@ properties: - const: fsl,imx8-mu-scu - const: fsl,imx8-mu-seco - const: fsl,imx8ulp-mu-s4 + - items: + - const: fsl,imx93-mu + - const: fsl,imx8ulp-mu - items: - enum: - fsl,imx7s-mu From 241aba6c1ebd2c326a371b8af84b1f096efd0506 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 9 Mar 2022 18:03:42 +0800 Subject: [PATCH 13/19] dt-bindings: mailbox: imx-mu: add i.MX93 S4 MU support Similar to i.MX8ULP S4 MU, i.MX93 MU is dedicated for communication between Sentinel and Cortex-A cores from hardware design, it could not be reused for other purpose. However i.MX93 S4 MU use separate tx/rx interrupt, so update interrupts and add interrupt-names property. Reviewed-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Signed-off-by: Peng Fan Signed-off-by: Jassi Brar --- .../devicetree/bindings/mailbox/fsl,mu.yaml | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mailbox/fsl,mu.yaml b/Documentation/devicetree/bindings/mailbox/fsl,mu.yaml index 6d056d5e16bfa..7a86e7926dd29 100644 --- a/Documentation/devicetree/bindings/mailbox/fsl,mu.yaml +++ b/Documentation/devicetree/bindings/mailbox/fsl,mu.yaml @@ -29,6 +29,7 @@ properties: - const: fsl,imx8ulp-mu - const: fsl,imx8-mu-scu - const: fsl,imx8-mu-seco + - const: fsl,imx93-mu-s4 - const: fsl,imx8ulp-mu-s4 - items: - const: fsl,imx93-mu @@ -55,7 +56,14 @@ properties: maxItems: 1 interrupts: - maxItems: 1 + minItems: 1 + maxItems: 2 + + interrupt-names: + minItems: 1 + items: + - const: tx + - const: rx "#mbox-cells": description: | @@ -90,6 +98,27 @@ required: - interrupts - "#mbox-cells" +allOf: + - if: + properties: + compatible: + enum: + - fsl,imx93-mu-s4 + then: + properties: + interrupt-names: + minItems: 2 + interrupts: + minItems: 2 + + else: + properties: + interrupts: + maxItems: 1 + not: + required: + - interrupt-names + additionalProperties: false examples: From cfd162f604bfccfe0b0953fbf0adfcb80ed75cce Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 9 Mar 2022 18:03:43 +0800 Subject: [PATCH 14/19] mailbox: imx: extend irq to an array To i.MX93 S401 MU, there are two interrupts: rx full and tx empty. So extend irq to an array to prepare i.MX93 S401 MU support. Signed-off-by: Peng Fan Signed-off-by: Jassi Brar --- drivers/mailbox/imx-mailbox.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index cd011ca5707ec..03699843a6fd3 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -80,7 +80,7 @@ struct imx_mu_priv { struct imx_mu_con_priv con_priv[IMX_MU_CHANS]; const struct imx_mu_dcfg *dcfg; struct clk *clk; - int irq; + int irq[IMX_MU_CHANS]; bool suspend; u32 xcr[4]; @@ -551,11 +551,11 @@ static int imx_mu_startup(struct mbox_chan *chan) if (!priv->dev->pm_domain) irq_flag |= IRQF_NO_SUSPEND; - ret = request_irq(priv->irq, imx_mu_isr, irq_flag, + ret = request_irq(priv->irq[0], imx_mu_isr, irq_flag, cp->irq_desc, chan); if (ret) { dev_err(priv->dev, - "Unable to acquire IRQ %d\n", priv->irq); + "Unable to acquire IRQ %d\n", priv->irq[0]); return ret; } @@ -598,7 +598,7 @@ static void imx_mu_shutdown(struct mbox_chan *chan) break; } - free_irq(priv->irq, chan); + free_irq(priv->irq[0], chan); pm_runtime_put_sync(priv->dev); } @@ -762,9 +762,9 @@ static int imx_mu_probe(struct platform_device *pdev) if (IS_ERR(priv->base)) return PTR_ERR(priv->base); - priv->irq = platform_get_irq(pdev, 0); - if (priv->irq < 0) - return priv->irq; + priv->irq[0] = platform_get_irq(pdev, 0); + if (priv->irq[0] < 0) + return priv->irq[0]; dcfg = of_device_get_match_data(dev); if (!dcfg) From a5cb407a7af4d825bbf8c299db155dc58848ecc5 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 9 Mar 2022 18:03:44 +0800 Subject: [PATCH 15/19] mailbox: imx: support dual interrupts i.MX93 S401 MU support two interrupts: tx empty and rx full. - Introduce a new flag IMX_MU_V2_IRQ for the dual interrupt case - Update Copyright Signed-off-by: Peng Fan Signed-off-by: Jassi Brar --- drivers/mailbox/imx-mailbox.c | 45 +++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index 03699843a6fd3..24977d66bfb94 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2018 Pengutronix, Oleksij Rempel + * Copyright 2022 NXP, Peng Fan */ #include @@ -28,11 +29,12 @@ #define IMX_MU_SECO_TX_TOUT (msecs_to_jiffies(3000)) #define IMX_MU_SECO_RX_TOUT (msecs_to_jiffies(3000)) +/* Please not change TX & RX */ enum imx_mu_chan_type { - IMX_MU_TYPE_TX, /* Tx */ - IMX_MU_TYPE_RX, /* Rx */ - IMX_MU_TYPE_TXDB, /* Tx doorbell */ - IMX_MU_TYPE_RXDB, /* Rx doorbell */ + IMX_MU_TYPE_TX = 0, /* Tx */ + IMX_MU_TYPE_RX = 1, /* Rx */ + IMX_MU_TYPE_TXDB = 2, /* Tx doorbell */ + IMX_MU_TYPE_RXDB = 3, /* Rx doorbell */ }; enum imx_mu_xcr { @@ -92,6 +94,7 @@ enum imx_mu_type { IMX_MU_V1, IMX_MU_V2 = BIT(1), IMX_MU_V2_S4 = BIT(15), + IMX_MU_V2_IRQ = BIT(16), }; struct imx_mu_dcfg { @@ -536,7 +539,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 = IRQF_SHARED; + unsigned long irq_flag = 0; int ret; pm_runtime_get_sync(priv->dev); @@ -551,11 +554,12 @@ static int imx_mu_startup(struct mbox_chan *chan) if (!priv->dev->pm_domain) irq_flag |= IRQF_NO_SUSPEND; - ret = request_irq(priv->irq[0], imx_mu_isr, irq_flag, - cp->irq_desc, 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); if (ret) { - dev_err(priv->dev, - "Unable to acquire IRQ %d\n", priv->irq[0]); + dev_err(priv->dev, "Unable to acquire IRQ %d\n", priv->irq[cp->type]); return ret; } @@ -598,7 +602,7 @@ static void imx_mu_shutdown(struct mbox_chan *chan) break; } - free_irq(priv->irq[0], chan); + free_irq(priv->irq[cp->type], chan); pm_runtime_put_sync(priv->dev); } @@ -749,7 +753,7 @@ static int imx_mu_probe(struct platform_device *pdev) struct device_node *np = dev->of_node; struct imx_mu_priv *priv; const struct imx_mu_dcfg *dcfg; - int ret; + int i, ret; u32 size; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -762,14 +766,25 @@ static int imx_mu_probe(struct platform_device *pdev) if (IS_ERR(priv->base)) return PTR_ERR(priv->base); - priv->irq[0] = platform_get_irq(pdev, 0); - if (priv->irq[0] < 0) - return priv->irq[0]; - dcfg = of_device_get_match_data(dev); if (!dcfg) return -EINVAL; priv->dcfg = dcfg; + if (priv->dcfg->type & IMX_MU_V2_IRQ) { + priv->irq[IMX_MU_TYPE_TX] = platform_get_irq_byname(pdev, "tx"); + if (priv->irq[IMX_MU_TYPE_TX] < 0) + return priv->irq[IMX_MU_TYPE_TX]; + priv->irq[IMX_MU_TYPE_RX] = platform_get_irq_byname(pdev, "rx"); + if (priv->irq[IMX_MU_TYPE_RX] < 0) + return priv->irq[IMX_MU_TYPE_RX]; + } else { + ret = platform_get_irq(pdev, 0); + if (ret < 0) + return ret; + + for (i = 0; i < IMX_MU_CHANS; i++) + priv->irq[i] = ret; + } if (priv->dcfg->type & IMX_MU_V2_S4) size = sizeof(struct imx_s4_rpc_msg_max); From 0184cc2026a0176dc24b63f62ca290bf155420b9 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 9 Mar 2022 18:03:45 +0800 Subject: [PATCH 16/19] mailbox: imx: support i.MX93 S401 MU Add i.MX93 S401 MU cfg Signed-off-by: Peng Fan Signed-off-by: Jassi Brar --- drivers/mailbox/imx-mailbox.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index 24977d66bfb94..e88f544a15482 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -905,6 +905,17 @@ static const struct imx_mu_dcfg imx_mu_cfg_imx8ulp_s4 = { .xCR = {0x110, 0x114, 0x120, 0x128}, }; +static const struct imx_mu_dcfg imx_mu_cfg_imx93_s4 = { + .tx = imx_mu_specific_tx, + .rx = imx_mu_specific_rx, + .init = imx_mu_init_specific, + .type = IMX_MU_V2 | IMX_MU_V2_S4 | IMX_MU_V2_IRQ, + .xTR = 0x200, + .xRR = 0x280, + .xSR = {0xC, 0x118, 0x124, 0x12C}, + .xCR = {0x110, 0x114, 0x120, 0x128}, +}; + static const struct imx_mu_dcfg imx_mu_cfg_imx8_scu = { .tx = imx_mu_specific_tx, .rx = imx_mu_specific_rx, @@ -932,6 +943,7 @@ static const struct of_device_id imx_mu_dt_ids[] = { { .compatible = "fsl,imx6sx-mu", .data = &imx_mu_cfg_imx6sx }, { .compatible = "fsl,imx8ulp-mu", .data = &imx_mu_cfg_imx8ulp }, { .compatible = "fsl,imx8ulp-mu-s4", .data = &imx_mu_cfg_imx8ulp_s4 }, + { .compatible = "fsl,imx93-mu-s4", .data = &imx_mu_cfg_imx93_s4 }, { .compatible = "fsl,imx8-mu-scu", .data = &imx_mu_cfg_imx8_scu }, { .compatible = "fsl,imx8-mu-seco", .data = &imx_mu_cfg_imx8_seco }, { }, From cb62b8f7346338eeefa6d46160200879dc345246 Mon Sep 17 00:00:00 2001 From: Dave Gerlach Date: Wed, 9 Feb 2022 22:16:30 -0600 Subject: [PATCH 17/19] mailbox: ti-msgmgr: Refactor message read during interrupt handler Refactor the portion of code that actually reads received messages from a queue into its own function, ti_msgmgr_queue_rx_data, that is called by the interrupt handler instead of reading directly from the handler. Signed-off-by: Dave Gerlach Signed-off-by: Jassi Brar --- drivers/mailbox/ti-msgmgr.c | 88 +++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 39 deletions(-) diff --git a/drivers/mailbox/ti-msgmgr.c b/drivers/mailbox/ti-msgmgr.c index efb43b0385960..f860cd0c907a3 100644 --- a/drivers/mailbox/ti-msgmgr.c +++ b/drivers/mailbox/ti-msgmgr.c @@ -190,6 +190,53 @@ static inline bool ti_msgmgr_queue_is_error(const struct ti_msgmgr_desc *d, return val ? true : false; } +static int ti_msgmgr_queue_rx_data(struct mbox_chan *chan, struct ti_queue_inst *qinst, + const struct ti_msgmgr_desc *desc) +{ + int num_words; + struct ti_msgmgr_message message; + void __iomem *data_reg; + u32 *word_data; + + /* + * I have no idea about the protocol being used to communicate with the + * remote producer - 0 could be valid data, so I wont make a judgement + * of how many bytes I should be reading. Let the client figure this + * out.. I just read the full message and pass it on.. + */ + message.len = desc->max_message_size; + message.buf = (u8 *)qinst->rx_buff; + + /* + * NOTE about register access involved here: + * the hardware block is implemented with 32bit access operations and no + * support for data splitting. We don't want the hardware to misbehave + * with sub 32bit access - For example: if the last register read is + * split into byte wise access, it can result in the queue getting + * stuck or indeterminate behavior. An out of order read operation may + * result in weird data results as well. + * Hence, we do not use memcpy_fromio or __ioread32_copy here, instead + * we depend on readl for the purpose. + * + * Also note that the final register read automatically marks the + * queue message as read. + */ + for (data_reg = qinst->queue_buff_start, word_data = qinst->rx_buff, + num_words = (desc->max_message_size / sizeof(u32)); + num_words; num_words--, data_reg += sizeof(u32), word_data++) + *word_data = readl(data_reg); + + /* + * Last register read automatically clears the IRQ if only 1 message + * is pending - so send the data up the stack.. + * NOTE: Client is expected to be as optimal as possible, since + * we invoke the handler in IRQ context. + */ + mbox_chan_received_data(chan, (void *)&message); + + return 0; +} + /** * ti_msgmgr_queue_rx_interrupt() - Interrupt handler for receive Queue * @irq: Interrupt number @@ -206,10 +253,7 @@ static irqreturn_t ti_msgmgr_queue_rx_interrupt(int irq, void *p) struct ti_msgmgr_inst *inst = dev_get_drvdata(dev); struct ti_queue_inst *qinst = chan->con_priv; const struct ti_msgmgr_desc *desc; - int msg_count, num_words; - struct ti_msgmgr_message message; - void __iomem *data_reg; - u32 *word_data; + int msg_count; if (WARN_ON(!inst)) { dev_err(dev, "no platform drv data??\n"); @@ -237,41 +281,7 @@ static irqreturn_t ti_msgmgr_queue_rx_interrupt(int irq, void *p) return IRQ_NONE; } - /* - * I have no idea about the protocol being used to communicate with the - * remote producer - 0 could be valid data, so I won't make a judgement - * of how many bytes I should be reading. Let the client figure this - * out.. I just read the full message and pass it on.. - */ - message.len = desc->max_message_size; - message.buf = (u8 *)qinst->rx_buff; - - /* - * NOTE about register access involved here: - * the hardware block is implemented with 32bit access operations and no - * support for data splitting. We don't want the hardware to misbehave - * with sub 32bit access - For example: if the last register read is - * split into byte wise access, it can result in the queue getting - * stuck or indeterminate behavior. An out of order read operation may - * result in weird data results as well. - * Hence, we do not use memcpy_fromio or __ioread32_copy here, instead - * we depend on readl for the purpose. - * - * Also note that the final register read automatically marks the - * queue message as read. - */ - for (data_reg = qinst->queue_buff_start, word_data = qinst->rx_buff, - num_words = (desc->max_message_size / sizeof(u32)); - num_words; num_words--, data_reg += sizeof(u32), word_data++) - *word_data = readl(data_reg); - - /* - * Last register read automatically clears the IRQ if only 1 message - * is pending - so send the data up the stack.. - * NOTE: Client is expected to be as optimal as possible, since - * we invoke the handler in IRQ context. - */ - mbox_chan_received_data(chan, (void *)&message); + ti_msgmgr_queue_rx_data(chan, qinst, desc); return IRQ_HANDLED; } From df227dc8a68d81b7fe3416eca16d1f21d0b537f0 Mon Sep 17 00:00:00 2001 From: Dave Gerlach Date: Wed, 9 Feb 2022 22:16:31 -0600 Subject: [PATCH 18/19] mailbox: ti-msgmgr: Operate mailbox in polled mode during system suspend During the system suspend path we must set all queues to operate in polled mode as it is possible for any protocol built using this mailbox, such as TISCI, to require communication during the no irq phase of suspend, and we cannot rely on interrupts there. Polled mode is implemented by allowing the mailbox user to define an RX channel as part of the message that is sent which is what gets polled for a response. If polled mode is enabled, this will immediately be polled for a response at the end of the mailbox send_data op before returning success for the data send or timing out if no response is received. Finally, to ensure polled mode is always enabled during system suspend, iterate through all queues to set RX queues to polled mode during system suspend and disable polled mode for all in the resume handler. Signed-off-by: Dave Gerlach Signed-off-by: Jassi Brar --- drivers/mailbox/ti-msgmgr.c | 93 +++++++++++++++++++++++++++++++- include/linux/soc/ti/ti-msgmgr.h | 8 ++- 2 files changed, 98 insertions(+), 3 deletions(-) diff --git a/drivers/mailbox/ti-msgmgr.c b/drivers/mailbox/ti-msgmgr.c index f860cd0c907a3..ddac423ac1a91 100644 --- a/drivers/mailbox/ti-msgmgr.c +++ b/drivers/mailbox/ti-msgmgr.c @@ -2,7 +2,7 @@ /* * Texas Instruments' Message Manager Driver * - * Copyright (C) 2015-2017 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2015-2022 Texas Instruments Incorporated - https://www.ti.com/ * Nishanth Menon */ @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -100,6 +101,7 @@ struct ti_msgmgr_desc { * @queue_ctrl: Queue Control register * @chan: Mailbox channel * @rx_buff: Receive buffer pointer allocated at probe, max_message_size + * @polled_rx_mode: Use polling for rx instead of interrupts */ struct ti_queue_inst { char name[30]; @@ -113,6 +115,7 @@ struct ti_queue_inst { void __iomem *queue_ctrl; struct mbox_chan *chan; u32 *rx_buff; + bool polled_rx_mode; }; /** @@ -237,6 +240,26 @@ static int ti_msgmgr_queue_rx_data(struct mbox_chan *chan, struct ti_queue_inst return 0; } +static int ti_msgmgr_queue_rx_poll_timeout(struct mbox_chan *chan, int timeout_us) +{ + struct device *dev = chan->mbox->dev; + struct ti_msgmgr_inst *inst = dev_get_drvdata(dev); + struct ti_queue_inst *qinst = chan->con_priv; + const struct ti_msgmgr_desc *desc = inst->desc; + int msg_count; + int ret; + + ret = readl_poll_timeout_atomic(qinst->queue_state, msg_count, + (msg_count & desc->status_cnt_mask), + 10, timeout_us); + if (ret != 0) + return ret; + + ti_msgmgr_queue_rx_data(chan, qinst, desc); + + return 0; +} + /** * ti_msgmgr_queue_rx_interrupt() - Interrupt handler for receive Queue * @irq: Interrupt number @@ -346,6 +369,17 @@ static bool ti_msgmgr_last_tx_done(struct mbox_chan *chan) return msg_count ? false : true; } +static bool ti_msgmgr_chan_has_polled_queue_rx(struct mbox_chan *chan) +{ + struct ti_queue_inst *qinst; + + if (!chan) + return false; + + qinst = chan->con_priv; + return qinst->polled_rx_mode; +} + /** * ti_msgmgr_send_data() - Send data * @chan: Channel Pointer @@ -363,6 +397,7 @@ static int ti_msgmgr_send_data(struct mbox_chan *chan, void *data) struct ti_msgmgr_message *message = data; void __iomem *data_reg; u32 *word_data; + int ret = 0; if (WARN_ON(!inst)) { dev_err(dev, "no platform drv data??\n"); @@ -404,7 +439,12 @@ static int ti_msgmgr_send_data(struct mbox_chan *chan, void *data) if (data_reg <= qinst->queue_buff_end) writel(0, qinst->queue_buff_end); - return 0; + /* If we are in polled mode, wait for a response before proceeding */ + if (ti_msgmgr_chan_has_polled_queue_rx(message->chan_rx)) + ret = ti_msgmgr_queue_rx_poll_timeout(message->chan_rx, + message->timeout_rx_ms * 1000); + + return ret; } /** @@ -652,6 +692,54 @@ static int ti_msgmgr_queue_setup(int idx, struct device *dev, return 0; } +static int ti_msgmgr_queue_rx_set_polled_mode(struct ti_queue_inst *qinst, bool enable) +{ + if (enable) { + disable_irq(qinst->irq); + qinst->polled_rx_mode = true; + } else { + enable_irq(qinst->irq); + qinst->polled_rx_mode = false; + } + + return 0; +} + +static int ti_msgmgr_suspend(struct device *dev) +{ + struct ti_msgmgr_inst *inst = dev_get_drvdata(dev); + struct ti_queue_inst *qinst; + int i; + + /* + * We must switch operation to polled mode now as drivers and the genpd + * layer may make late TI SCI calls to change clock and device states + * from the noirq phase of suspend. + */ + for (qinst = inst->qinsts, i = 0; i < inst->num_valid_queues; qinst++, i++) { + if (!qinst->is_tx) + ti_msgmgr_queue_rx_set_polled_mode(qinst, true); + } + + return 0; +} + +static int ti_msgmgr_resume(struct device *dev) +{ + struct ti_msgmgr_inst *inst = dev_get_drvdata(dev); + struct ti_queue_inst *qinst; + int i; + + for (qinst = inst->qinsts, i = 0; i < inst->num_valid_queues; qinst++, i++) { + if (!qinst->is_tx) + ti_msgmgr_queue_rx_set_polled_mode(qinst, false); + } + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(ti_msgmgr_pm_ops, ti_msgmgr_suspend, ti_msgmgr_resume); + /* Queue operations */ static const struct mbox_chan_ops ti_msgmgr_chan_ops = { .startup = ti_msgmgr_queue_startup, @@ -839,6 +927,7 @@ static struct platform_driver ti_msgmgr_driver = { .driver = { .name = "ti-msgmgr", .of_match_table = of_match_ptr(ti_msgmgr_of_match), + .pm = &ti_msgmgr_pm_ops, }, }; module_platform_driver(ti_msgmgr_driver); diff --git a/include/linux/soc/ti/ti-msgmgr.h b/include/linux/soc/ti/ti-msgmgr.h index 1f6e76d423cf5..69a8d7682c4b5 100644 --- a/include/linux/soc/ti/ti-msgmgr.h +++ b/include/linux/soc/ti/ti-msgmgr.h @@ -1,7 +1,7 @@ /* * Texas Instruments' Message Manager * - * Copyright (C) 2015-2016 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2015-2022 Texas Instruments Incorporated - https://www.ti.com/ * Nishanth Menon * * This program is free software; you can redistribute it and/or modify @@ -17,10 +17,14 @@ #ifndef TI_MSGMGR_H #define TI_MSGMGR_H +struct mbox_chan; + /** * struct ti_msgmgr_message - Message Manager structure * @len: Length of data in the Buffer * @buf: Buffer pointer + * @chan_rx: Expected channel for response, must be provided to use polled rx + * @timeout_rx_ms: Timeout value to use if polling for response * * This is the structure for data used in mbox_send_message * the length of data buffer used depends on the SoC integration @@ -30,6 +34,8 @@ struct ti_msgmgr_message { size_t len; u8 *buf; + struct mbox_chan *chan_rx; + int timeout_rx_ms; }; #endif /* TI_MSGMGR_H */ From 1b0d0f7c12d57763fe27200d0569c863f11d2b8a Mon Sep 17 00:00:00 2001 From: Rex-BC Chen Date: Wed, 23 Feb 2022 11:01:37 +0800 Subject: [PATCH 19/19] dt-bindings: mailbox: add definition for mt8186 Add definition of compatible and dt-binding header for mt8186. Signed-off-by: Rex-BC Chen Signed-off-by: Jassi Brar --- Documentation/devicetree/bindings/mailbox/mtk-gce.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/mailbox/mtk-gce.txt b/Documentation/devicetree/bindings/mailbox/mtk-gce.txt index 98fe37e8b17b9..c2aeba63bd47d 100644 --- a/Documentation/devicetree/bindings/mailbox/mtk-gce.txt +++ b/Documentation/devicetree/bindings/mailbox/mtk-gce.txt @@ -10,7 +10,8 @@ mailbox.txt for generic information about mailbox device-tree bindings. Required properties: - compatible: can be "mediatek,mt8173-gce", "mediatek,mt8183-gce", - "mediatek,mt8192-gce", "mediatek,mt8195-gce" or "mediatek,mt6779-gce". + "mediatek,mt8186-gce", "mediatek,mt8192-gce", "mediatek,mt8195-gce" or + "mediatek,mt6779-gce". - reg: Address range of the GCE unit - interrupts: The interrupt signal from the GCE block - clock: Clocks according to the common clock binding @@ -40,8 +41,9 @@ Optional properties for a client mutex node: defined in 'dt-bindings/gce/-gce.h'. Some vaules of properties are defined in 'dt-bindings/gce/mt8173-gce.h', -'dt-bindings/gce/mt8183-gce.h', 'dt-bindings/gce/mt8192-gce.h', -'dt-bindings/gce/mt8195-gce.h' or 'dt-bindings/gce/mt6779-gce.h'. +'dt-bindings/gce/mt8183-gce.h', 'dt-bindings/gce/mt8186-gce.h' +'dt-bindings/gce/mt8192-gce.h', 'dt-bindings/gce/mt8195-gce.h' or +'dt-bindings/gce/mt6779-gce.h'. Such as sub-system ids, thread priority, event ids. Example: