ASoC: fsl_sai: Add support for i.MX8MM, MP, ULP
authorMark Brown <broonie@kernel.org>
Mon, 16 May 2022 18:50:53 +0000 (19:50 +0100)
committerMark Brown <broonie@kernel.org>
Mon, 16 May 2022 18:50:53 +0000 (19:50 +0100)
Merge series from Shengjiu Wang <shengjiu.wang@nxp.com>:

ASoC: fsl_sai: Add support for i.MX8MM, MP, ULP platforms

16 files changed:
drivers/firmware/Kconfig
drivers/firmware/Makefile
drivers/firmware/mtk-adsp-ipc.c [new file with mode: 0644]
include/linux/firmware/mediatek/mtk-adsp-ipc.h [new file with mode: 0644]
include/sound/soc.h
sound/soc/amd/vangogh/acp5x-mach.c
sound/soc/codecs/rt5645.c
sound/soc/generic/audio-graph-card2.c
sound/soc/soc-component.c
sound/soc/soc-core.c
sound/soc/sof/mediatek/Kconfig
sound/soc/sof/mediatek/adsp_helper.h
sound/soc/sof/mediatek/mt8186/mt8186-loader.c
sound/soc/sof/mediatek/mt8186/mt8186.c
sound/soc/sof/mediatek/mt8195/mt8195.c
sound/soc/ti/j721e-evm.c

index e5cfb01353d88743f1255656425ce711a8f995a5..f7bc8306631b148e8840f1b6222a01525916172e 100644 (file)
@@ -203,6 +203,15 @@ config INTEL_STRATIX10_RSU
 
          Say Y here if you want Intel RSU support.
 
+config MTK_ADSP_IPC
+       tristate "MTK ADSP IPC Protocol driver"
+       depends on MTK_ADSP_MBOX
+       help
+         Say yes here to add support for the MediaTek ADSP IPC
+         between host AP (Linux) and the firmware running on ADSP.
+         ADSP exists on some mtk processors.
+         Client might use shared memory to exchange information with ADSP.
+
 config QCOM_SCM
        tristate
 
index 4e58cb474a68d0feab430c906b495029d2d1662a..1be0e82952225426e79ed1991878a853a94a37fd 100644 (file)
@@ -15,6 +15,7 @@ obj-$(CONFIG_INTEL_STRATIX10_RSU)     += stratix10-rsu.o
 obj-$(CONFIG_ISCSI_IBFT_FIND)  += iscsi_ibft_find.o
 obj-$(CONFIG_ISCSI_IBFT)       += iscsi_ibft.o
 obj-$(CONFIG_FIRMWARE_MEMMAP)  += memmap.o
+obj-$(CONFIG_MTK_ADSP_IPC)     += mtk-adsp-ipc.o
 obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
 obj-$(CONFIG_FW_CFG_SYSFS)     += qemu_fw_cfg.o
 obj-$(CONFIG_QCOM_SCM)         += qcom-scm.o
diff --git a/drivers/firmware/mtk-adsp-ipc.c b/drivers/firmware/mtk-adsp-ipc.c
new file mode 100644 (file)
index 0000000..cb255a9
--- /dev/null
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 MediaTek Corporation. All rights reserved.
+ * Author: Allen-KH Cheng <allen-kh.cheng@mediatek.com>
+ */
+
+#include <linux/firmware/mediatek/mtk-adsp-ipc.h>
+#include <linux/kernel.h>
+#include <linux/mailbox_client.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/*
+ * mtk_adsp_ipc_send - send ipc cmd to MTK ADSP
+ *
+ * @ipc: ADSP IPC handle
+ * @idx: index of the mailbox channel
+ * @msg: IPC cmd (reply or request)
+ *
+ * Returns zero for success from mbox_send_message
+ * negative value for error
+ */
+int mtk_adsp_ipc_send(struct mtk_adsp_ipc *ipc, unsigned int idx, uint32_t msg)
+{
+       struct mtk_adsp_chan *adsp_chan;
+       int ret;
+
+       if (idx >= MTK_ADSP_MBOX_NUM)
+               return -EINVAL;
+
+       adsp_chan = &ipc->chans[idx];
+       ret = mbox_send_message(adsp_chan->ch, &msg);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_adsp_ipc_send);
+
+/*
+ * mtk_adsp_ipc_recv - recv callback used by MTK ADSP mailbox
+ *
+ * @c: mbox client
+ * @msg: message received
+ *
+ * Users of ADSP IPC will need to privde handle_reply and handle_request
+ * callbacks.
+ */
+static void mtk_adsp_ipc_recv(struct mbox_client *c, void *msg)
+{
+       struct mtk_adsp_chan *chan = container_of(c, struct mtk_adsp_chan, cl);
+       struct device *dev = c->dev;
+
+       switch (chan->idx) {
+       case MTK_ADSP_MBOX_REPLY:
+               chan->ipc->ops->handle_reply(chan->ipc);
+               break;
+       case MTK_ADSP_MBOX_REQUEST:
+               chan->ipc->ops->handle_request(chan->ipc);
+               break;
+       default:
+               dev_err(dev, "wrong mbox chan %d\n", chan->idx);
+               break;
+       }
+}
+
+static int mtk_adsp_ipc_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct mtk_adsp_ipc *adsp_ipc;
+       struct mtk_adsp_chan *adsp_chan;
+       struct mbox_client *cl;
+       char *chan_name;
+       int ret;
+       int i, j;
+
+       device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
+
+       adsp_ipc = devm_kzalloc(dev, sizeof(*adsp_ipc), GFP_KERNEL);
+       if (!adsp_ipc)
+               return -ENOMEM;
+
+       for (i = 0; i < MTK_ADSP_MBOX_NUM; i++) {
+               chan_name = kasprintf(GFP_KERNEL, "mbox%d", i);
+               if (!chan_name) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+
+               adsp_chan = &adsp_ipc->chans[i];
+               cl = &adsp_chan->cl;
+               cl->dev = dev->parent;
+               cl->tx_block = false;
+               cl->knows_txdone = false;
+               cl->tx_prepare = NULL;
+               cl->rx_callback = mtk_adsp_ipc_recv;
+
+               adsp_chan->ipc = adsp_ipc;
+               adsp_chan->idx = i;
+               adsp_chan->ch = mbox_request_channel_byname(cl, chan_name);
+               if (IS_ERR(adsp_chan->ch)) {
+                       ret = PTR_ERR(adsp_chan->ch);
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(dev, "Failed to request mbox chan %d ret %d\n",
+                                       i, ret);
+                       goto out_free;
+               }
+
+               dev_dbg(dev, "request mbox chan %s\n", chan_name);
+               kfree(chan_name);
+       }
+
+       adsp_ipc->dev = dev;
+       dev_set_drvdata(dev, adsp_ipc);
+       dev_dbg(dev, "MTK ADSP IPC initialized\n");
+
+       return 0;
+
+out_free:
+       kfree(chan_name);
+out:
+       for (j = 0; j < i; j++) {
+               adsp_chan = &adsp_ipc->chans[j];
+               mbox_free_channel(adsp_chan->ch);
+       }
+
+       return ret;
+}
+
+static int mtk_adsp_ipc_remove(struct platform_device *pdev)
+{
+       struct mtk_adsp_ipc *adsp_ipc = dev_get_drvdata(&pdev->dev);
+       struct mtk_adsp_chan *adsp_chan;
+       int i;
+
+       for (i = 0; i < MTK_ADSP_MBOX_NUM; i++) {
+               adsp_chan = &adsp_ipc->chans[i];
+               mbox_free_channel(adsp_chan->ch);
+       }
+
+       return 0;
+}
+
+static struct platform_driver mtk_adsp_ipc_driver = {
+       .driver = {
+               .name = "mtk-adsp-ipc",
+       },
+       .probe = mtk_adsp_ipc_probe,
+       .remove = mtk_adsp_ipc_remove,
+};
+builtin_platform_driver(mtk_adsp_ipc_driver);
+
+MODULE_AUTHOR("Allen-KH Cheng <allen-kh.cheng@mediatek.com>");
+MODULE_DESCRIPTION("MTK ADSP IPC Driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/firmware/mediatek/mtk-adsp-ipc.h b/include/linux/firmware/mediatek/mtk-adsp-ipc.h
new file mode 100644 (file)
index 0000000..28fd313
--- /dev/null
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#ifndef MTK_ADSP_IPC_H
+#define MTK_ADSP_IPC_H
+
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/mailbox_controller.h>
+#include <linux/mailbox_client.h>
+
+#define MTK_ADSP_IPC_REQ 0
+#define MTK_ADSP_IPC_RSP 1
+#define MTK_ADSP_IPC_OP_REQ 0x1
+#define MTK_ADSP_IPC_OP_RSP 0x2
+
+enum {
+       MTK_ADSP_MBOX_REPLY,
+       MTK_ADSP_MBOX_REQUEST,
+       MTK_ADSP_MBOX_NUM,
+};
+
+struct mtk_adsp_ipc;
+
+struct mtk_adsp_ipc_ops {
+       void (*handle_reply)(struct mtk_adsp_ipc *ipc);
+       void (*handle_request)(struct mtk_adsp_ipc *ipc);
+};
+
+struct mtk_adsp_chan {
+       struct mtk_adsp_ipc *ipc;
+       struct mbox_client cl;
+       struct mbox_chan *ch;
+       char *name;
+       int idx;
+};
+
+struct mtk_adsp_ipc {
+       struct mtk_adsp_chan chans[MTK_ADSP_MBOX_NUM];
+       struct device *dev;
+       struct mtk_adsp_ipc_ops *ops;
+       void *private_data;
+};
+
+static inline void mtk_adsp_ipc_set_data(struct mtk_adsp_ipc *ipc, void *data)
+{
+       if (!ipc)
+               return;
+
+       ipc->private_data = data;
+}
+
+static inline void *mtk_adsp_ipc_get_data(struct mtk_adsp_ipc *ipc)
+{
+       if (!ipc)
+               return NULL;
+
+       return ipc->private_data;
+}
+
+int mtk_adsp_ipc_send(struct mtk_adsp_ipc *ipc, unsigned int idx, uint32_t op);
+
+#endif /* MTK_ADSP_IPC_H */
index f906e5a708308cc6063caa9e6bded433498b0e16..f20f5f890794ab8b051b8cb7c5c7a16ce0b6afce 100644 (file)
@@ -1259,7 +1259,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
                                   const char *propname);
 int snd_soc_of_parse_aux_devs(struct snd_soc_card *card, const char *propname);
 
-unsigned int snd_soc_daifmt_clock_provider_fliped(unsigned int dai_fmt);
+unsigned int snd_soc_daifmt_clock_provider_flipped(unsigned int dai_fmt);
 unsigned int snd_soc_daifmt_clock_provider_from_bitmap(unsigned int bit_frame);
 
 unsigned int snd_soc_daifmt_parse_format(struct device_node *np, const char *prefix);
index d8b25622f911174d7052458a1bbb63d729bf4608..727de46860b19329991088568ca6b4e5c0923aec 100644 (file)
 #include <linux/clk.h>
 #include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
-#include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
-#include <linux/io.h>
 #include <linux/acpi.h>
 #include <linux/dmi.h>
 
index ccdea234a3ba01135001d129293eb6c656e82817..507aba8de3cc9dd348ef4f70b353ff2983e12cc3 100644 (file)
@@ -4153,9 +4153,14 @@ static int rt5645_i2c_remove(struct i2c_client *i2c)
        if (i2c->irq)
                free_irq(i2c->irq, rt5645);
 
+       /*
+        * Since the rt5645_btn_check_callback() can queue jack_detect_work,
+        * the timer need to be delted first
+        */
+       del_timer_sync(&rt5645->btn_check_timer);
+
        cancel_delayed_work_sync(&rt5645->jack_detect_work);
        cancel_delayed_work_sync(&rt5645->rcclock_work);
-       del_timer_sync(&rt5645->btn_check_timer);
 
        regulator_bulk_disable(ARRAY_SIZE(rt5645->supplies), rt5645->supplies);
 
index 2b5d20f02f8f8de0924e93ce400402e93c2d0fec..77ac4051b827652e8cc4bfb5ddb49b0e361466eb 100644 (file)
@@ -711,7 +711,7 @@ static void graph_link_init(struct asoc_simple_priv *priv,
         */
        daiclk = snd_soc_daifmt_clock_provider_from_bitmap(bit_frame);
        if (is_cpu_node)
-               daiclk = snd_soc_daifmt_clock_provider_fliped(daiclk);
+               daiclk = snd_soc_daifmt_clock_provider_flipped(daiclk);
 
        dai_link->dai_fmt       = daifmt | daiclk;
        dai_link->init          = asoc_simple_dai_init;
index c0664f94990c8eb5e2408908d9538dbbbef6c6b1..e12f8244242b9afd96bc3c85da56d5b293896a8d 100644 (file)
@@ -932,6 +932,20 @@ int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream)
        return 0;
 }
 
+static bool snd_soc_component_is_codec_on_rtd(struct snd_soc_pcm_runtime *rtd,
+                                             struct snd_soc_component *component)
+{
+       struct snd_soc_dai *dai;
+       int i;
+
+       for_each_rtd_codec_dais(rtd, i, dai) {
+               if (dai->component == component)
+                       return true;
+       }
+
+       return false;
+}
+
 void snd_soc_pcm_component_delay(struct snd_pcm_substream *substream,
                                 snd_pcm_sframes_t *cpu_delay,
                                 snd_pcm_sframes_t *codec_delay)
@@ -953,7 +967,7 @@ void snd_soc_pcm_component_delay(struct snd_pcm_substream *substream,
 
                delay = component->driver->delay(component, substream);
 
-               if (snd_soc_component_is_codec(component))
+               if (snd_soc_component_is_codec_on_rtd(rtd, component))
                        *codec_delay = max(*codec_delay, delay);
                else
                        *cpu_delay = max(*cpu_delay, delay);
index d68e64b73eea741403ee6d15c10e85faa3566054..9574f86dd4de29946f2a7e791d84ec750ae514b8 100644 (file)
@@ -1230,7 +1230,7 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
        /*
         * Flip the polarity for the "CPU" end of a CODEC<->CODEC link
         */
-       inv_dai_fmt = snd_soc_daifmt_clock_provider_fliped(dai_fmt);
+       inv_dai_fmt = snd_soc_daifmt_clock_provider_flipped(dai_fmt);
 
        for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
                unsigned int fmt = dai_fmt;
@@ -2497,7 +2497,7 @@ static int snd_soc_register_dais(struct snd_soc_component *component,
 
        for (i = 0; i < count; i++) {
                dai = snd_soc_register_dai(component, dai_drv + i, count == 1 &&
-                                          !snd_soc_component_is_codec(component));
+                                          !component->driver->non_legacy_dai_naming);
                if (dai == NULL) {
                        ret = -ENOMEM;
                        goto err;
@@ -3035,7 +3035,7 @@ int snd_soc_of_parse_aux_devs(struct snd_soc_card *card, const char *propname)
 }
 EXPORT_SYMBOL_GPL(snd_soc_of_parse_aux_devs);
 
-unsigned int snd_soc_daifmt_clock_provider_fliped(unsigned int dai_fmt)
+unsigned int snd_soc_daifmt_clock_provider_flipped(unsigned int dai_fmt)
 {
        unsigned int inv_dai_fmt = dai_fmt & ~SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK;
 
@@ -3056,7 +3056,7 @@ unsigned int snd_soc_daifmt_clock_provider_fliped(unsigned int dai_fmt)
 
        return inv_dai_fmt;
 }
-EXPORT_SYMBOL_GPL(snd_soc_daifmt_clock_provider_fliped);
+EXPORT_SYMBOL_GPL(snd_soc_daifmt_clock_provider_flipped);
 
 unsigned int snd_soc_daifmt_clock_provider_from_bitmap(unsigned int bit_frame)
 {
index f79e76a6f3c616039d348f25af2e3d2ea8189e6a..a149dd1b3f44c558af27066945bba56619846238 100644 (file)
@@ -24,6 +24,7 @@ config SND_SOC_SOF_MTK_COMMON
 config SND_SOC_SOF_MT8186
        tristate "SOF support for MT8186 audio DSP"
        select SND_SOC_SOF_MTK_COMMON
+       depends on MTK_ADSP_IPC
        help
          This adds support for Sound Open Firmware for Mediatek platforms
          using the mt8186 processors.
@@ -33,6 +34,7 @@ config SND_SOC_SOF_MT8186
 config SND_SOC_SOF_MT8195
        tristate "SOF support for MT8195 audio DSP"
        select SND_SOC_SOF_MTK_COMMON
+       depends on MTK_ADSP_IPC
        help
          This adds support for Sound Open Firmware for Mediatek platforms
          using the mt8195 processors.
index f269a2b6c26a097e15fe0ad35e7da3215c8c8a7d..4ab998756bbc053050f25e291d5c358dee6093d8 100644 (file)
@@ -7,24 +7,22 @@
 #ifndef __MTK_ADSP_HELPER_H__
 #define __MTK_ADSP_HELPER_H__
 
+#include <linux/firmware/mediatek/mtk-adsp-ipc.h>
+
 /*
  * Global important adsp data structure.
  */
-#define DSP_MBOX_NUM   3
-
 struct mtk_adsp_chip_info {
        phys_addr_t pa_sram;
        phys_addr_t pa_dram; /* adsp dram physical base */
        phys_addr_t pa_shared_dram; /* adsp dram physical base */
        phys_addr_t pa_cfgreg;
-       phys_addr_t pa_mboxreg[DSP_MBOX_NUM];
        u32 sramsize;
        u32 dramsize;
        u32 cfgregsize;
        void __iomem *va_sram; /* corresponding to pa_sram */
        void __iomem *va_dram; /* corresponding to pa_dram */
        void __iomem *va_cfgreg;
-       void __iomem *va_mboxreg[DSP_MBOX_NUM];
        void __iomem *shared_sram; /* part of  va_sram */
        void __iomem *shared_dram; /* part of  va_dram */
        phys_addr_t adsp_bootup_addr;
@@ -42,10 +40,8 @@ struct mtk_adsp_chip_info {
 struct adsp_priv {
        struct device *dev;
        struct snd_sof_dev *sdev;
-
-       /* DSP IPC handler */
-       struct mbox_controller *adsp_mbox;
-
+       struct mtk_adsp_ipc *dsp_ipc;
+       struct platform_device *ipc_dev;
        struct mtk_adsp_chip_info *adsp;
        struct clk **clk;
        u32 (*ap2adsp_addr)(u32 addr, void *data);
index 548b12c33d8a783260a448131ef55d6d4777c5c3..946e6c43204f1c454bf380a83325748c66e3dfa4 100644 (file)
@@ -17,6 +17,11 @@ void mt8186_sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr)
        snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, ADSP_HIFI_IO_CONFIG,
                                RUNSTALL, RUNSTALL);
 
+       /* enable mbox 0 & 1 IRQ */
+       snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, ADSP_MBOX_IRQ_EN,
+                               DSP_MBOX0_IRQ_EN | DSP_MBOX1_IRQ_EN,
+                               DSP_MBOX0_IRQ_EN | DSP_MBOX1_IRQ_EN);
+
        /* set core boot address */
        snd_sof_dsp_write(sdev, DSP_SECREG_BAR, ADSP_ALTVEC_C0, boot_addr);
        snd_sof_dsp_write(sdev, DSP_SECREG_BAR, ADSP_ALTVECSEL, ADSP_ALTVECSEL_C0);
index 6d574fd4492e6570364792c90c25d455e34c7fb8..3333a0634e29dc34d2c002ea6630015f549149d2 100644 (file)
 #include "mt8186.h"
 #include "mt8186-clk.h"
 
+static int mt8186_get_mailbox_offset(struct snd_sof_dev *sdev)
+{
+       return MBOX_OFFSET;
+}
+
+static int mt8186_get_window_offset(struct snd_sof_dev *sdev, u32 id)
+{
+       return MBOX_OFFSET;
+}
+
+static int mt8186_send_msg(struct snd_sof_dev *sdev,
+                          struct snd_sof_ipc_msg *msg)
+{
+       struct adsp_priv *priv = sdev->pdata->hw_pdata;
+
+       sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
+                         msg->msg_size);
+
+       return mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_REQ, MTK_ADSP_IPC_OP_REQ);
+}
+
+static void mt8186_get_reply(struct snd_sof_dev *sdev)
+{
+       struct snd_sof_ipc_msg *msg = sdev->msg;
+       struct sof_ipc_reply reply;
+       int ret = 0;
+
+       if (!msg) {
+               dev_warn(sdev->dev, "unexpected ipc interrupt\n");
+               return;
+       }
+
+       /* get reply */
+       sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply));
+       if (reply.error < 0) {
+               memcpy(msg->reply_data, &reply, sizeof(reply));
+               ret = reply.error;
+       } else {
+               /* reply has correct size? */
+               if (reply.hdr.size != msg->reply_size) {
+                       dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n",
+                               msg->reply_size, reply.hdr.size);
+                       ret = -EINVAL;
+               }
+
+               /* read the message */
+               if (msg->reply_size > 0)
+                       sof_mailbox_read(sdev, sdev->host_box.offset,
+                                        msg->reply_data, msg->reply_size);
+       }
+
+       msg->reply_error = ret;
+}
+
+static void mt8186_dsp_handle_reply(struct mtk_adsp_ipc *ipc)
+{
+       struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->sdev->ipc_lock, flags);
+       mt8186_get_reply(priv->sdev);
+       snd_sof_ipc_reply(priv->sdev, 0);
+       spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags);
+}
+
+static void mt8186_dsp_handle_request(struct mtk_adsp_ipc *ipc)
+{
+       struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc);
+       u32 p; /* panic code */
+       int ret;
+
+       /* Read the message from the debug box. */
+       sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4,
+                        &p, sizeof(p));
+
+       /* Check to see if the message is a panic code 0x0dead*** */
+       if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) {
+               snd_sof_dsp_panic(priv->sdev, p, true);
+       } else {
+               snd_sof_ipc_msgs_rx(priv->sdev);
+
+               /* tell DSP cmd is done */
+               ret = mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_RSP, MTK_ADSP_IPC_OP_RSP);
+               if (ret)
+                       dev_err(priv->dev, "request send ipc failed");
+       }
+}
+
+static struct mtk_adsp_ipc_ops dsp_ops = {
+       .handle_reply           = mt8186_dsp_handle_reply,
+       .handle_request         = mt8186_dsp_handle_request,
+};
+
 static int platform_parse_resource(struct platform_device *pdev, void *data)
 {
        struct resource *mmio;
@@ -271,6 +364,9 @@ static int mt8186_dsp_probe(struct snd_sof_dev *sdev)
        sdev->mmio_bar = SOF_FW_BLK_TYPE_SRAM;
        sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM;
 
+       /* set default mailbox offset for FW ready message */
+       sdev->dsp_box.offset = mt8186_get_mailbox_offset(sdev);
+
        ret = adsp_memory_remap_init(sdev, priv->adsp);
        if (ret) {
                dev_err(sdev->dev, "adsp_memory_remap_init fail!\n");
@@ -292,11 +388,41 @@ static int mt8186_dsp_probe(struct snd_sof_dev *sdev)
 
        adsp_sram_power_on(sdev);
 
+       priv->ipc_dev = platform_device_register_data(&pdev->dev, "mtk-adsp-ipc",
+                                                     PLATFORM_DEVID_NONE,
+                                                     pdev, sizeof(*pdev));
+       if (IS_ERR(priv->ipc_dev)) {
+               ret = IS_ERR(priv->ipc_dev);
+               dev_err(sdev->dev, "failed to create mtk-adsp-ipc device\n");
+               goto err_adsp_off;
+       }
+
+       priv->dsp_ipc = dev_get_drvdata(&priv->ipc_dev->dev);
+       if (!priv->dsp_ipc) {
+               ret = -EPROBE_DEFER;
+               dev_err(sdev->dev, "failed to get drvdata\n");
+               goto exit_pdev_unregister;
+       }
+
+       mtk_adsp_ipc_set_data(priv->dsp_ipc, priv);
+       priv->dsp_ipc->ops = &dsp_ops;
+
        return 0;
+
+exit_pdev_unregister:
+       platform_device_unregister(priv->ipc_dev);
+err_adsp_off:
+       adsp_sram_power_off(sdev);
+       mt8186_adsp_clock_off(sdev);
+
+       return ret;
 }
 
 static int mt8186_dsp_remove(struct snd_sof_dev *sdev)
 {
+       struct adsp_priv *priv = sdev->pdata->hw_pdata;
+
+       platform_device_unregister(priv->ipc_dev);
        mt8186_sof_hifixdsp_shutdown(sdev);
        adsp_sram_power_off(sdev);
        mt8186_adsp_clock_off(sdev);
@@ -334,6 +460,14 @@ static int mt8186_get_bar_index(struct snd_sof_dev *sdev, u32 type)
        return type;
 }
 
+static int mt8186_ipc_msg_data(struct snd_sof_dev *sdev,
+                              struct snd_pcm_substream *substream,
+                              void *p, size_t sz)
+{
+       sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz);
+       return 0;
+}
+
 /* mt8186 ops */
 static struct snd_sof_dsp_ops sof_mt8186_ops = {
        /* probe and remove */
@@ -353,6 +487,13 @@ static struct snd_sof_dsp_ops sof_mt8186_ops = {
        .write64        = sof_io_write64,
        .read64         = sof_io_read64,
 
+       /* ipc */
+       .send_msg               = mt8186_send_msg,
+       .get_mailbox_offset     = mt8186_get_mailbox_offset,
+       .get_window_offset      = mt8186_get_window_offset,
+       .ipc_msg_data           = mt8186_ipc_msg_data,
+       .set_stream_data_offset = sof_set_stream_data_offset,
+
        /* misc */
        .get_bar_index  = mt8186_get_bar_index,
 
index ba13e4540f7a80d26bb1a4458b7a4796b66a04e9..f4b24afb6f751177ce94d2511d8a7f9622020297 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/delay.h>
 #include <linux/firmware.h>
 #include <linux/io.h>
+#include <linux/of_platform.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include "mt8195.h"
 #include "mt8195-clk.h"
 
+static int mt8195_get_mailbox_offset(struct snd_sof_dev *sdev)
+{
+       return MBOX_OFFSET;
+}
+
+static int mt8195_get_window_offset(struct snd_sof_dev *sdev, u32 id)
+{
+       return MBOX_OFFSET;
+}
+
+static int mt8195_send_msg(struct snd_sof_dev *sdev,
+                          struct snd_sof_ipc_msg *msg)
+{
+       struct adsp_priv *priv = sdev->pdata->hw_pdata;
+
+       sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
+                         msg->msg_size);
+
+       return mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_REQ, MTK_ADSP_IPC_OP_REQ);
+}
+
+static void mt8195_get_reply(struct snd_sof_dev *sdev)
+{
+       struct snd_sof_ipc_msg *msg = sdev->msg;
+       struct sof_ipc_reply reply;
+       int ret = 0;
+
+       if (!msg) {
+               dev_warn(sdev->dev, "unexpected ipc interrupt\n");
+               return;
+       }
+
+       /* get reply */
+       sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply));
+       if (reply.error < 0) {
+               memcpy(msg->reply_data, &reply, sizeof(reply));
+               ret = reply.error;
+       } else {
+               /* reply has correct size? */
+               if (reply.hdr.size != msg->reply_size) {
+                       dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n",
+                               msg->reply_size, reply.hdr.size);
+                       ret = -EINVAL;
+               }
+
+               /* read the message */
+               if (msg->reply_size > 0)
+                       sof_mailbox_read(sdev, sdev->host_box.offset,
+                                        msg->reply_data, msg->reply_size);
+       }
+
+       msg->reply_error = ret;
+}
+
+static void mt8195_dsp_handle_reply(struct mtk_adsp_ipc *ipc)
+{
+       struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->sdev->ipc_lock, flags);
+       mt8195_get_reply(priv->sdev);
+       snd_sof_ipc_reply(priv->sdev, 0);
+       spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags);
+}
+
+static void mt8195_dsp_handle_request(struct mtk_adsp_ipc *ipc)
+{
+       struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc);
+       u32 p; /* panic code */
+       int ret;
+
+       /* Read the message from the debug box. */
+       sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4,
+                        &p, sizeof(p));
+
+       /* Check to see if the message is a panic code 0x0dead*** */
+       if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) {
+               snd_sof_dsp_panic(priv->sdev, p, true);
+       } else {
+               snd_sof_ipc_msgs_rx(priv->sdev);
+
+               /* tell DSP cmd is done */
+               ret = mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_RSP, MTK_ADSP_IPC_OP_RSP);
+               if (ret)
+                       dev_err(priv->dev, "request send ipc failed");
+       }
+}
+
+static struct mtk_adsp_ipc_ops dsp_ops = {
+       .handle_reply           = mt8195_dsp_handle_reply,
+       .handle_request         = mt8195_dsp_handle_request,
+};
+
 static int platform_parse_resource(struct platform_device *pdev, void *data)
 {
        struct resource *mmio;
@@ -285,15 +379,36 @@ static int mt8195_dsp_probe(struct snd_sof_dev *sdev)
        }
 
        sdev->bar[DSP_REG_BAR] = priv->adsp->va_cfgreg;
-       sdev->bar[DSP_MBOX0_BAR] =  priv->adsp->va_mboxreg[0];
-       sdev->bar[DSP_MBOX1_BAR] =  priv->adsp->va_mboxreg[1];
-       sdev->bar[DSP_MBOX2_BAR] =  priv->adsp->va_mboxreg[2];
 
        sdev->mmio_bar = SOF_FW_BLK_TYPE_SRAM;
        sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM;
 
+       /* set default mailbox offset for FW ready message */
+       sdev->dsp_box.offset = mt8195_get_mailbox_offset(sdev);
+
+       priv->ipc_dev = platform_device_register_data(&pdev->dev, "mtk-adsp-ipc",
+                                                     PLATFORM_DEVID_NONE,
+                                                     pdev, sizeof(*pdev));
+       if (IS_ERR(priv->ipc_dev)) {
+               ret = PTR_ERR(priv->ipc_dev);
+               dev_err(sdev->dev, "failed to register mtk-adsp-ipc device\n");
+               goto err_adsp_sram_power_off;
+       }
+
+       priv->dsp_ipc = dev_get_drvdata(&priv->ipc_dev->dev);
+       if (!priv->dsp_ipc) {
+               ret = -EPROBE_DEFER;
+               dev_err(sdev->dev, "failed to get drvdata\n");
+               goto exit_pdev_unregister;
+       }
+
+       mtk_adsp_ipc_set_data(priv->dsp_ipc, priv);
+       priv->dsp_ipc->ops = &dsp_ops;
+
        return 0;
 
+exit_pdev_unregister:
+       platform_device_unregister(priv->ipc_dev);
 err_adsp_sram_power_off:
        adsp_sram_power_on(&pdev->dev, false);
 exit_clk_disable:
@@ -310,7 +425,9 @@ static int mt8195_dsp_shutdown(struct snd_sof_dev *sdev)
 static int mt8195_dsp_remove(struct snd_sof_dev *sdev)
 {
        struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev);
+       struct adsp_priv *priv = sdev->pdata->hw_pdata;
 
+       platform_device_unregister(priv->ipc_dev);
        adsp_sram_power_on(&pdev->dev, false);
        adsp_clock_off(sdev);
 
@@ -361,6 +478,14 @@ static int mt8195_get_bar_index(struct snd_sof_dev *sdev, u32 type)
        return type;
 }
 
+static int mt8195_ipc_msg_data(struct snd_sof_dev *sdev,
+                              struct snd_pcm_substream *substream,
+                              void *p, size_t sz)
+{
+       sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz);
+       return 0;
+}
+
 static struct snd_soc_dai_driver mt8195_dai[] = {
 {
        .name = "SOF_DL2",
@@ -412,6 +537,13 @@ static struct snd_sof_dsp_ops sof_mt8195_ops = {
        .write64        = sof_io_write64,
        .read64         = sof_io_read64,
 
+       /* ipc */
+       .send_msg               = mt8195_send_msg,
+       .get_mailbox_offset     = mt8195_get_mailbox_offset,
+       .get_window_offset      = mt8195_get_window_offset,
+       .ipc_msg_data           = mt8195_ipc_msg_data,
+       .set_stream_data_offset = sof_set_stream_data_offset,
+
        /* misc */
        .get_bar_index  = mt8195_get_bar_index,
 
index 4077e15ec48b73fb12958501d81676988299093a..6a969874c9270152f586e442a09fed7ebeafdc1b 100644 (file)
@@ -630,17 +630,18 @@ static int j721e_soc_probe_cpb(struct j721e_priv *priv, int *link_idx,
        codec_node = of_parse_phandle(node, "ti,cpb-codec", 0);
        if (!codec_node) {
                dev_err(priv->dev, "CPB codec node is not provided\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto put_dai_node;
        }
 
        domain = &priv->audio_domains[J721E_AUDIO_DOMAIN_CPB];
        ret = j721e_get_clocks(priv->dev, &domain->codec, "cpb-codec-scki");
        if (ret)
-               return ret;
+               goto put_codec_node;
 
        ret = j721e_get_clocks(priv->dev, &domain->mcasp, "cpb-mcasp-auxclk");
        if (ret)
-               return ret;
+               goto put_codec_node;
 
        /*
         * Common Processor Board, two links
@@ -650,8 +651,10 @@ static int j721e_soc_probe_cpb(struct j721e_priv *priv, int *link_idx,
        comp_count = 6;
        compnent = devm_kzalloc(priv->dev, comp_count * sizeof(*compnent),
                                GFP_KERNEL);
-       if (!compnent)
-               return -ENOMEM;
+       if (!compnent) {
+               ret = -ENOMEM;
+               goto put_codec_node;
+       }
 
        comp_idx = 0;
        priv->dai_links[*link_idx].cpus = &compnent[comp_idx++];
@@ -702,6 +705,12 @@ static int j721e_soc_probe_cpb(struct j721e_priv *priv, int *link_idx,
        (*conf_idx)++;
 
        return 0;
+
+put_codec_node:
+       of_node_put(codec_node);
+put_dai_node:
+       of_node_put(dai_node);
+       return ret;
 }
 
 static int j721e_soc_probe_ivi(struct j721e_priv *priv, int *link_idx,
@@ -726,23 +735,25 @@ static int j721e_soc_probe_ivi(struct j721e_priv *priv, int *link_idx,
        codeca_node = of_parse_phandle(node, "ti,ivi-codec-a", 0);
        if (!codeca_node) {
                dev_err(priv->dev, "IVI codec-a node is not provided\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto put_dai_node;
        }
 
        codecb_node = of_parse_phandle(node, "ti,ivi-codec-b", 0);
        if (!codecb_node) {
                dev_warn(priv->dev, "IVI codec-b node is not provided\n");
-               return 0;
+               ret = 0;
+               goto put_codeca_node;
        }
 
        domain = &priv->audio_domains[J721E_AUDIO_DOMAIN_IVI];
        ret = j721e_get_clocks(priv->dev, &domain->codec, "ivi-codec-scki");
        if (ret)
-               return ret;
+               goto put_codecb_node;
 
        ret = j721e_get_clocks(priv->dev, &domain->mcasp, "ivi-mcasp-auxclk");
        if (ret)
-               return ret;
+               goto put_codecb_node;
 
        /*
         * IVI extension, two links
@@ -754,8 +765,10 @@ static int j721e_soc_probe_ivi(struct j721e_priv *priv, int *link_idx,
        comp_count = 8;
        compnent = devm_kzalloc(priv->dev, comp_count * sizeof(*compnent),
                                GFP_KERNEL);
-       if (!compnent)
-               return -ENOMEM;
+       if (!compnent) {
+               ret = -ENOMEM;
+               goto put_codecb_node;
+       }
 
        comp_idx = 0;
        priv->dai_links[*link_idx].cpus = &compnent[comp_idx++];
@@ -816,6 +829,15 @@ static int j721e_soc_probe_ivi(struct j721e_priv *priv, int *link_idx,
        (*conf_idx)++;
 
        return 0;
+
+
+put_codecb_node:
+       of_node_put(codecb_node);
+put_codeca_node:
+       of_node_put(codeca_node);
+put_dai_node:
+       of_node_put(dai_node);
+       return ret;
 }
 
 static int j721e_soc_probe(struct platform_device *pdev)