mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-13 23:34:05 +08:00
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
This commit is contained in:
commit
0af9de0ea8
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
157
drivers/firmware/mtk-adsp-ipc.c
Normal file
157
drivers/firmware/mtk-adsp-ipc.c
Normal file
@ -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");
|
65
include/linux/firmware/mediatek/mtk-adsp-ipc.h
Normal file
65
include/linux/firmware/mediatek/mtk-adsp-ipc.h
Normal file
@ -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 */
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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,
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user