[Sound-open-firmware] [PATCH v9 0/3] firmware: mtk: add adsp ipc protocol for SOF
This patch provides mediatek adsp ipc support for SOF. ADSP IPC protocol offers (send/recv) interfaces using mediatek-mailbox APIs.
This patch was tested and confirmed to work with SOF fw on MT8195 cherry board and MT8186 krabby board.
changes since v8: - fix patchset 2 and 3. move "depends on MTK_ADSP_IPC" from SND_SOC_SOF_MTK_COMMON to SND_SOC_SOF_MT8195/MT8186 to prevent generating wrong config.
changes since v7: - rebase to linux-next/next-22020504 - use EXPORT_SYMBOL_GPL instead of EXPORT_SYMBOL in mtk-adsp-ipc.c - move mtk-adsp-ipc.c out from driver/firmware/mediatek - add user of mtk-adsp-ipc.h in patchset 2 and 3.
changes since v6: - rebase to matthias.bgg/linux.git, v5.18-next/soc - Prefer "GPL" over "GPL v2" for MODULE_LICENSE
changes since v5: - fix WARNING: modpost: missing MODULE_LICENSE() in drivers/mailbox /mtk-adsp-mailbox.o. Add MODULE_LICENSE in the last line. - Due to WARNING: Missing or malformed SPDX-License-Identifier tag in line 1 in checkpatch, we don't remove SPDX-License in line 1.
changes since v4: - add error message for wrong mbox chan
changes since v3: - rebase on v5.16-rc8 - update reviewers
changes since v2: - add out tag for two memory free phases
changes since v1: - add comments for mtk_adsp_ipc_send and mtk_adsp_ipc_recv - remove useless MODULE_LICENSE - change label name to out_free
Allen-KH Cheng (1): ASoC: SOF: mediatek: Add ipc support for mt8195
TingHan Shen (1): firmware: mediatek: add adsp ipc protocol interface
Tinghan Shen (1): ASoC: SOF: mediatek: Add mt8186 ipc support
drivers/firmware/Kconfig | 9 + drivers/firmware/Makefile | 1 + drivers/firmware/mtk-adsp-ipc.c | 157 ++++++++++++++++++ .../linux/firmware/mediatek/mtk-adsp-ipc.h | 65 ++++++++ sound/soc/sof/mediatek/Kconfig | 2 + sound/soc/sof/mediatek/adsp_helper.h | 12 +- sound/soc/sof/mediatek/mt8186/mt8186-loader.c | 5 + sound/soc/sof/mediatek/mt8186/mt8186.c | 141 ++++++++++++++++ sound/soc/sof/mediatek/mt8195/mt8195.c | 138 ++++++++++++++- 9 files changed, 519 insertions(+), 11 deletions(-) create mode 100644 drivers/firmware/mtk-adsp-ipc.c create mode 100644 include/linux/firmware/mediatek/mtk-adsp-ipc.h
From: TingHan Shen tinghan.shen@mediatek.com
Some of mediatek processors contain the Tensilica HiFix DSP for audio processing.
The communication between Host CPU and DSP firmware is taking place using a shared memory area for message passing.
ADSP IPC protocol offers (send/recv) interfaces using mediatek-mailbox APIs.
We use two mbox channels to implement a request-reply protocol.
Signed-off-by: Allen-KH Cheng allen-kh.cheng@mediatek.com Signed-off-by: TingHan Shen tinghan.shen@mediatek.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Curtis Malainey cujomalainey@chromium.org Reviewed-by: Tzung-Bi Shih tzungbi@google.com Reviewed-by: YC Hung yc.hung@mediatek.com Reviewed-by: AngeloGioacchino Del Regno angelogioacchino.delregno@collabora.com --- drivers/firmware/Kconfig | 9 + drivers/firmware/Makefile | 1 + drivers/firmware/mtk-adsp-ipc.c | 157 ++++++++++++++++++ .../linux/firmware/mediatek/mtk-adsp-ipc.h | 65 ++++++++ 4 files changed, 232 insertions(+) create mode 100644 drivers/firmware/mtk-adsp-ipc.c create mode 100644 include/linux/firmware/mediatek/mtk-adsp-ipc.h
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index d65964996e8d..b59e3041fd62 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -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
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 4e58cb474a68..1be0e8295222 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -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 index 000000000000..cb255a99170c --- /dev/null +++ b/drivers/firmware/mtk-adsp-ipc.c @@ -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 index 000000000000..28fd313340b8 --- /dev/null +++ b/include/linux/firmware/mediatek/mtk-adsp-ipc.h @@ -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 */
From: Allen-KH Cheng Allen-KH.Cheng@mediatek.com
This patch adds mt8195 IPC support by using mailbox.
On mt8195 resource, there are two mboxes used to handle ipc request and reply. We create a mtk-adsp-ipc client device to request mbox controllers.
Signed-off-by: Allen-KH Cheng Allen-KH.Cheng@mediatek.com Reported-by: kernel test robot lkp@intel.com --- sound/soc/sof/mediatek/Kconfig | 1 + sound/soc/sof/mediatek/adsp_helper.h | 12 +-- sound/soc/sof/mediatek/mt8195/mt8195.c | 138 ++++++++++++++++++++++++- 3 files changed, 140 insertions(+), 11 deletions(-)
diff --git a/sound/soc/sof/mediatek/Kconfig b/sound/soc/sof/mediatek/Kconfig index f79e76a6f3c6..f1fa15c41891 100644 --- a/sound/soc/sof/mediatek/Kconfig +++ b/sound/soc/sof/mediatek/Kconfig @@ -33,6 +33,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. diff --git a/sound/soc/sof/mediatek/adsp_helper.h b/sound/soc/sof/mediatek/adsp_helper.h index f269a2b6c26a..4ab998756bbc 100644 --- a/sound/soc/sof/mediatek/adsp_helper.h +++ b/sound/soc/sof/mediatek/adsp_helper.h @@ -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); diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index ba13e4540f7a..f4b24afb6f75 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -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> @@ -27,6 +28,99 @@ #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,
mt8186 DSP uses two hardware mailbox IP to communicate with AP. One mailbox is used for requests coming from AP, and the other one is for requests from DSP.
Signed-off-by: Allen-KH Cheng Allen-KH.Cheng@mediatek.com Signed-off-by: Tinghan Shen tinghan.shen@mediatek.com --- sound/soc/sof/mediatek/Kconfig | 1 + sound/soc/sof/mediatek/mt8186/mt8186-loader.c | 5 + sound/soc/sof/mediatek/mt8186/mt8186.c | 141 ++++++++++++++++++ 3 files changed, 147 insertions(+)
diff --git a/sound/soc/sof/mediatek/Kconfig b/sound/soc/sof/mediatek/Kconfig index f1fa15c41891..a149dd1b3f44 100644 --- a/sound/soc/sof/mediatek/Kconfig +++ b/sound/soc/sof/mediatek/Kconfig @@ -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. diff --git a/sound/soc/sof/mediatek/mt8186/mt8186-loader.c b/sound/soc/sof/mediatek/mt8186/mt8186-loader.c index 548b12c33d8a..946e6c43204f 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186-loader.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186-loader.c @@ -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); diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index 6d574fd4492e..3333a0634e29 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -27,6 +27,99 @@ #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,
On Thu, 12 May 2022 16:22:12 +0800, Tinghan Shen wrote:
This patch provides mediatek adsp ipc support for SOF. ADSP IPC protocol offers (send/recv) interfaces using mediatek-mailbox APIs.
This patch was tested and confirmed to work with SOF fw on MT8195 cherry board and MT8186 krabby board.
[...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
Thanks!
[1/3] firmware: mediatek: Add adsp ipc protocol interface commit: 9db69df4bdd37eb1f65b6931ee067fb15b9a4d5c [2/3] ASoC: SOF: mediatek: Add ipc support for mt8195 commit: aea9350108ed1627f8610c93de44578162b3ee91 [3/3] ASoC: SOF: mediatek: Add mt8186 ipc support commit: e0100bfd383c7d994d2e957e85ca56a5fe5a3f43
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
participants (2)
-
Mark Brown
-
Tinghan Shen