Unverified Commit 0af9de0e authored by Mark Brown's avatar Mark Brown
Browse files

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
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -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

+1 −0
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
// 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 −0
Original line number Diff line number Diff line
/* 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 */
+2 −0
Original line number Diff line number Diff line
@@ -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.
Loading