Commit 0af9de0e authored by Mark Brown's avatar Mark Brown

firmware: mtk: add adsp ipc protocol for SOF

Merge series from Tinghan Shen <tinghan.shen@mediatek.com>:

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

--
2.18.0
parents 2def44d3 e0100bfd
...@@ -203,6 +203,15 @@ config INTEL_STRATIX10_RSU ...@@ -203,6 +203,15 @@ config INTEL_STRATIX10_RSU
Say Y here if you want Intel RSU support. 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 config QCOM_SCM
tristate tristate
......
...@@ -15,6 +15,7 @@ obj-$(CONFIG_INTEL_STRATIX10_RSU) += stratix10-rsu.o ...@@ -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_FIND) += iscsi_ibft_find.o
obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o
obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
obj-$(CONFIG_MTK_ADSP_IPC) += mtk-adsp-ipc.o
obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
obj-$(CONFIG_FW_CFG_SYSFS) += qemu_fw_cfg.o obj-$(CONFIG_FW_CFG_SYSFS) += qemu_fw_cfg.o
obj-$(CONFIG_QCOM_SCM) += qcom-scm.o obj-$(CONFIG_QCOM_SCM) += qcom-scm.o
......
// 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");
/* 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 */
...@@ -24,6 +24,7 @@ config SND_SOC_SOF_MTK_COMMON ...@@ -24,6 +24,7 @@ config SND_SOC_SOF_MTK_COMMON
config SND_SOC_SOF_MT8186 config SND_SOC_SOF_MT8186
tristate "SOF support for MT8186 audio DSP" tristate "SOF support for MT8186 audio DSP"
select SND_SOC_SOF_MTK_COMMON select SND_SOC_SOF_MTK_COMMON
depends on MTK_ADSP_IPC
help help
This adds support for Sound Open Firmware for Mediatek platforms This adds support for Sound Open Firmware for Mediatek platforms
using the mt8186 processors. using the mt8186 processors.
...@@ -33,6 +34,7 @@ config SND_SOC_SOF_MT8186 ...@@ -33,6 +34,7 @@ config SND_SOC_SOF_MT8186
config SND_SOC_SOF_MT8195 config SND_SOC_SOF_MT8195
tristate "SOF support for MT8195 audio DSP" tristate "SOF support for MT8195 audio DSP"
select SND_SOC_SOF_MTK_COMMON select SND_SOC_SOF_MTK_COMMON
depends on MTK_ADSP_IPC
help help
This adds support for Sound Open Firmware for Mediatek platforms This adds support for Sound Open Firmware for Mediatek platforms
using the mt8195 processors. using the mt8195 processors.
......
...@@ -7,24 +7,22 @@ ...@@ -7,24 +7,22 @@
#ifndef __MTK_ADSP_HELPER_H__ #ifndef __MTK_ADSP_HELPER_H__
#define __MTK_ADSP_HELPER_H__ #define __MTK_ADSP_HELPER_H__
#include <linux/firmware/mediatek/mtk-adsp-ipc.h>
/* /*
* Global important adsp data structure. * Global important adsp data structure.
*/ */
#define DSP_MBOX_NUM 3
struct mtk_adsp_chip_info { struct mtk_adsp_chip_info {
phys_addr_t pa_sram; phys_addr_t pa_sram;
phys_addr_t pa_dram; /* adsp dram physical base */ phys_addr_t pa_dram; /* adsp dram physical base */
phys_addr_t pa_shared_dram; /* adsp dram physical base */ phys_addr_t pa_shared_dram; /* adsp dram physical base */
phys_addr_t pa_cfgreg; phys_addr_t pa_cfgreg;
phys_addr_t pa_mboxreg[DSP_MBOX_NUM];
u32 sramsize; u32 sramsize;
u32 dramsize; u32 dramsize;
u32 cfgregsize; u32 cfgregsize;
void __iomem *va_sram; /* corresponding to pa_sram */ void __iomem *va_sram; /* corresponding to pa_sram */
void __iomem *va_dram; /* corresponding to pa_dram */ void __iomem *va_dram; /* corresponding to pa_dram */
void __iomem *va_cfgreg; void __iomem *va_cfgreg;
void __iomem *va_mboxreg[DSP_MBOX_NUM];
void __iomem *shared_sram; /* part of va_sram */ void __iomem *shared_sram; /* part of va_sram */
void __iomem *shared_dram; /* part of va_dram */ void __iomem *shared_dram; /* part of va_dram */
phys_addr_t adsp_bootup_addr; phys_addr_t adsp_bootup_addr;
...@@ -42,10 +40,8 @@ struct mtk_adsp_chip_info { ...@@ -42,10 +40,8 @@ struct mtk_adsp_chip_info {
struct adsp_priv { struct adsp_priv {
struct device *dev; struct device *dev;
struct snd_sof_dev *sdev; struct snd_sof_dev *sdev;
struct mtk_adsp_ipc *dsp_ipc;
/* DSP IPC handler */ struct platform_device *ipc_dev;
struct mbox_controller *adsp_mbox;
struct mtk_adsp_chip_info *adsp; struct mtk_adsp_chip_info *adsp;
struct clk **clk; struct clk **clk;
u32 (*ap2adsp_addr)(u32 addr, void *data); u32 (*ap2adsp_addr)(u32 addr, void *data);
......
...@@ -17,6 +17,11 @@ void mt8186_sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr) ...@@ -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, snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, ADSP_HIFI_IO_CONFIG,
RUNSTALL, RUNSTALL); 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 */ /* 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_ALTVEC_C0, boot_addr);
snd_sof_dsp_write(sdev, DSP_SECREG_BAR, ADSP_ALTVECSEL, ADSP_ALTVECSEL_C0); snd_sof_dsp_write(sdev, DSP_SECREG_BAR, ADSP_ALTVECSEL, ADSP_ALTVECSEL_C0);
......
...@@ -27,6 +27,99 @@ ...@@ -27,6 +27,99 @@
#include "mt8186.h" #include "mt8186.h"
#include "mt8186-clk.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) static int platform_parse_resource(struct platform_device *pdev, void *data)
{ {
struct resource *mmio; struct resource *mmio;
...@@ -271,6 +364,9 @@ static int mt8186_dsp_probe(struct snd_sof_dev *sdev) ...@@ -271,6 +364,9 @@ static int mt8186_dsp_probe(struct snd_sof_dev *sdev)
sdev->mmio_bar = SOF_FW_BLK_TYPE_SRAM; sdev->mmio_bar = SOF_FW_BLK_TYPE_SRAM;
sdev->mailbox_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); ret = adsp_memory_remap_init(sdev, priv->adsp);
if (ret) { if (ret) {
dev_err(sdev->dev, "adsp_memory_remap_init fail!\n"); dev_err(sdev->dev, "adsp_memory_remap_init fail!\n");
...@@ -292,11 +388,41 @@ static int mt8186_dsp_probe(struct snd_sof_dev *sdev) ...@@ -292,11 +388,41 @@ static int mt8186_dsp_probe(struct snd_sof_dev *sdev)
adsp_sram_power_on(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; 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) 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); mt8186_sof_hifixdsp_shutdown(sdev);
adsp_sram_power_off(sdev); adsp_sram_power_off(sdev);
mt8186_adsp_clock_off(sdev); mt8186_adsp_clock_off(sdev);
...@@ -334,6 +460,14 @@ static int mt8186_get_bar_index(struct snd_sof_dev *sdev, u32 type) ...@@ -334,6 +460,14 @@ static int mt8186_get_bar_index(struct snd_sof_dev *sdev, u32 type)
return 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 */ /* mt8186 ops */
static struct snd_sof_dsp_ops sof_mt8186_ops = { static struct snd_sof_dsp_ops sof_mt8186_ops = {
/* probe and remove */ /* probe and remove */
...@@ -353,6 +487,13 @@ static struct snd_sof_dsp_ops sof_mt8186_ops = { ...@@ -353,6 +487,13 @@ static struct snd_sof_dsp_ops sof_mt8186_ops = {
.write64 = sof_io_write64, .write64 = sof_io_write64,
.read64 = sof_io_read64, .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 */ /* misc */
.get_bar_index = mt8186_get_bar_index, .get_bar_index = mt8186_get_bar_index,
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/of_platform.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
...@@ -27,6 +28,99 @@ ...@@ -27,6 +28,99 @@
#include "mt8195.h" #include "mt8195.h"
#include "mt8195-clk.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) static int platform_parse_resource(struct platform_device *pdev, void *data)
{ {
struct resource *mmio; struct resource *mmio;
...@@ -285,15 +379,36 @@ static int mt8195_dsp_probe(struct snd_sof_dev *sdev) ...@@ -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_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->mmio_bar = SOF_FW_BLK_TYPE_SRAM;
sdev->mailbox_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; return 0;
exit_pdev_unregister:
platform_device_unregister(priv->ipc_dev);
err_adsp_sram_power_off: err_adsp_sram_power_off:
adsp_sram_power_on(&pdev->dev, false); adsp_sram_power_on(&pdev->dev, false);
exit_clk_disable: exit_clk_disable:
...@@ -310,7 +425,9 @@ static int mt8195_dsp_shutdown(struct snd_sof_dev *sdev) ...@@ -310,7 +425,9 @@ static int mt8195_dsp_shutdown(struct snd_sof_dev *sdev)
static int mt8195_dsp_remove(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 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_sram_power_on(&pdev->dev, false);
adsp_clock_off(sdev); adsp_clock_off(sdev);
...@@ -361,6 +478,14 @@ static int mt8195_get_bar_index(struct snd_sof_dev *sdev, u32 type) ...@@ -361,6 +478,14 @@ static int mt8195_get_bar_index(struct snd_sof_dev *sdev, u32 type)
return 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[] = { static struct snd_soc_dai_driver mt8195_dai[] = {
{ {
.name = "SOF_DL2", .name = "SOF_DL2",
...@@ -412,6 +537,13 @@ static struct snd_sof_dsp_ops sof_mt8195_ops = { ...@@ -412,6 +537,13 @@ static struct snd_sof_dsp_ops sof_mt8195_ops = {
.write64 = sof_io_write64, .write64 = sof_io_write64,
.read64 = sof_io_read64, .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 */ /* misc */
.get_bar_index = mt8195_get_bar_index, .get_bar_index = mt8195_get_bar_index,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment