mirror of https://gitee.com/openkylin/linux.git
Merge series "Add support for SOF on i.MX8M" from Daniel Baluta <daniel.baluta@oss.nxp.com>
Daniel Baluta <daniel.baluta@nxp.com>: From: Daniel Baluta <daniel.baluta@nxp.com> This patch series adds support for SOF on i.MX8M family. First board from this family that has a DSP is i.MX8MP. First 2 patches are trying to fix some compilation issues, the next two are adding the imx8m support and the last one adds the devicetree binding. Changes since v2: - add reviewed by from Rob to DT patch - fix ownership for patch 2 Daniel Baluta (3): ASoC: SOF: imx: Add i.MX8M HW support ASoC: SOF: Add i.MX8MP device descriptor dt-bindings: dsp: fsl: Add fsl,imx8mp-dsp entry Pierre-Louis Bossart (1): ASoC: SOF: imx: fix undefined reference issue YueHaibing (1): ASoC: SOF: imx8: Fix randbuild error .../devicetree/bindings/dsp/fsl,dsp.yaml | 2 + sound/soc/sof/imx/Kconfig | 32 +- sound/soc/sof/imx/Makefile | 2 + sound/soc/sof/imx/imx8m.c | 279 ++++++++++++++++++ sound/soc/sof/sof-of-dev.c | 14 + 5 files changed, 325 insertions(+), 4 deletions(-) create mode 100644 sound/soc/sof/imx/imx8m.c -- 2.17.1
This commit is contained in:
commit
72161e0eea
|
@ -17,6 +17,8 @@ properties:
|
|||
compatible:
|
||||
enum:
|
||||
- fsl,imx8qxp-dsp
|
||||
- fsl,imx8qm-dsp
|
||||
- fsl,imx8mp-dsp
|
||||
|
||||
reg:
|
||||
description: Should contain register location and length
|
||||
|
|
|
@ -351,7 +351,6 @@ struct snd_soc_dai {
|
|||
|
||||
/* bit field */
|
||||
unsigned int probed:1;
|
||||
unsigned int started[SNDRV_PCM_STREAM_LAST + 1];
|
||||
};
|
||||
|
||||
static inline struct snd_soc_pcm_stream *
|
||||
|
|
|
@ -1653,6 +1653,40 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
|
|||
dev_err(&client->dev,
|
||||
"Error %d initializing CHIP_CLK_CTRL\n", ret);
|
||||
|
||||
/* Mute everything to avoid pop from the following power-up */
|
||||
ret = regmap_write(sgtl5000->regmap, SGTL5000_CHIP_ANA_CTRL,
|
||||
SGTL5000_CHIP_ANA_CTRL_DEFAULT);
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"Error %d muting outputs via CHIP_ANA_CTRL\n", ret);
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
/*
|
||||
* If VAG is powered-on (e.g. from previous boot), it would be disabled
|
||||
* by the write to ANA_POWER in later steps of the probe code. This
|
||||
* may create a loud pop even with all outputs muted. The proper way
|
||||
* to circumvent this is disabling the bit first and waiting the proper
|
||||
* cool-down time.
|
||||
*/
|
||||
ret = regmap_read(sgtl5000->regmap, SGTL5000_CHIP_ANA_POWER, &value);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "Failed to read ANA_POWER: %d\n", ret);
|
||||
goto disable_clk;
|
||||
}
|
||||
if (value & SGTL5000_VAG_POWERUP) {
|
||||
ret = regmap_update_bits(sgtl5000->regmap,
|
||||
SGTL5000_CHIP_ANA_POWER,
|
||||
SGTL5000_VAG_POWERUP,
|
||||
0);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "Error %d disabling VAG\n", ret);
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
msleep(SGTL5000_VAG_POWERDOWN_DELAY);
|
||||
}
|
||||
|
||||
/* Follow section 2.2.1.1 of AN3663 */
|
||||
ana_pwr = SGTL5000_ANA_POWER_DEFAULT;
|
||||
if (sgtl5000->num_supplies <= VDDD) {
|
||||
|
|
|
@ -233,6 +233,7 @@
|
|||
/*
|
||||
* SGTL5000_CHIP_ANA_CTRL
|
||||
*/
|
||||
#define SGTL5000_CHIP_ANA_CTRL_DEFAULT 0x0133
|
||||
#define SGTL5000_LINE_OUT_MUTE 0x0100
|
||||
#define SGTL5000_HP_SEL_MASK 0x0040
|
||||
#define SGTL5000_HP_SEL_SHIFT 6
|
||||
|
|
|
@ -902,6 +902,8 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
|
|||
SNDRV_PCM_RATE_16000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
|
@ -917,6 +919,8 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
|
|||
SNDRV_PCM_RATE_16000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
|
@ -931,6 +935,8 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
|
|||
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
|
||||
SNDRV_PCM_RATE_16000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
|
@ -946,6 +952,8 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
|
|||
SNDRV_PCM_RATE_16000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
|
@ -960,6 +968,8 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
|
|||
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
|
||||
SNDRV_PCM_RATE_16000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
|
@ -975,6 +985,8 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
|
|||
SNDRV_PCM_RATE_16000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
|
@ -989,6 +1001,8 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
|
|||
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
|
||||
SNDRV_PCM_RATE_16000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
|
@ -1004,6 +1018,8 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
|
|||
SNDRV_PCM_RATE_16000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE,
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
|
|
|
@ -295,24 +295,17 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai,
|
|||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!dai->started[substream->stream] &&
|
||||
dai->driver->ops->startup)
|
||||
if (dai->driver->ops->startup)
|
||||
ret = dai->driver->ops->startup(substream, dai);
|
||||
|
||||
if (ret == 0)
|
||||
dai->started[substream->stream] = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
if (dai->started[substream->stream] &&
|
||||
dai->driver->ops->shutdown)
|
||||
if (dai->driver->ops->shutdown)
|
||||
dai->driver->ops->shutdown(substream, dai);
|
||||
|
||||
dai->started[substream->stream] = 0;
|
||||
}
|
||||
|
||||
int snd_soc_dai_prepare(struct snd_soc_dai *dai,
|
||||
|
|
|
@ -2911,8 +2911,17 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
|
|||
int i;
|
||||
|
||||
if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
|
||||
playback = rtd->dai_link->dpcm_playback;
|
||||
capture = rtd->dai_link->dpcm_capture;
|
||||
cpu_dai = asoc_rtd_to_cpu(rtd, 0);
|
||||
if (rtd->num_cpus > 1) {
|
||||
dev_err(rtd->dev,
|
||||
"DPCM doesn't support Multi CPU yet\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
playback = rtd->dai_link->dpcm_playback &&
|
||||
snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK);
|
||||
capture = rtd->dai_link->dpcm_capture &&
|
||||
snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_CAPTURE);
|
||||
} else {
|
||||
/* Adapt stream for codec2codec links */
|
||||
int cpu_capture = rtd->dai_link->params ?
|
||||
|
|
|
@ -2652,7 +2652,7 @@ static int soc_valid_header(struct soc_tplg *tplg,
|
|||
}
|
||||
|
||||
/* big endian firmware objects not supported atm */
|
||||
if (hdr->magic == SOC_TPLG_MAGIC_BIG_ENDIAN) {
|
||||
if (le32_to_cpu(hdr->magic) == SOC_TPLG_MAGIC_BIG_ENDIAN) {
|
||||
dev_err(tplg->dev,
|
||||
"ASoC: pass %d big endian not supported header got %x at offset 0x%lx size 0x%zx.\n",
|
||||
tplg->pass, hdr->magic,
|
||||
|
|
|
@ -11,17 +11,41 @@ config SND_SOC_SOF_IMX_TOPLEVEL
|
|||
|
||||
if SND_SOC_SOF_IMX_TOPLEVEL
|
||||
|
||||
config SND_SOC_SOF_IMX_OF
|
||||
def_tristate SND_SOC_SOF_OF
|
||||
select SND_SOC_SOF_IMX8 if SND_SOC_SOF_IMX8_SUPPORT
|
||||
select SND_SOC_SOF_IMX8M if SND_SOC_SOF_IMX8M_SUPPORT
|
||||
help
|
||||
This option is not user-selectable but automagically handled by
|
||||
'select' statements at a higher level
|
||||
|
||||
config SND_SOC_SOF_IMX8_SUPPORT
|
||||
bool "SOF support for i.MX8"
|
||||
depends on IMX_SCU
|
||||
depends on IMX_DSP
|
||||
help
|
||||
This adds support for Sound Open Firmware for NXP i.MX8 platforms
|
||||
Say Y if you have such a device.
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_SOF_IMX8
|
||||
def_tristate SND_SOC_SOF_OF
|
||||
depends on SND_SOC_SOF_IMX8_SUPPORT
|
||||
tristate
|
||||
depends on IMX_SCU
|
||||
select IMX_DSP
|
||||
help
|
||||
This option is not user-selectable but automagically handled by
|
||||
'select' statements at a higher level
|
||||
|
||||
config SND_SOC_SOF_IMX8M_SUPPORT
|
||||
bool "SOF support for i.MX8M"
|
||||
help
|
||||
This adds support for Sound Open Firmware for NXP i.MX8M platforms
|
||||
Say Y if you have such a device.
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_SOF_IMX8M
|
||||
tristate
|
||||
depends on IMX_DSP
|
||||
help
|
||||
This option is not user-selectable but automagically handled by
|
||||
'select' statements at a higher level
|
||||
|
||||
endif ## SND_SOC_SOF_IMX_IMX_TOPLEVEL
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
|
||||
snd-sof-imx8-objs := imx8.o
|
||||
snd-sof-imx8m-objs := imx8m.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_SOF_IMX8) += snd-sof-imx8.o
|
||||
obj-$(CONFIG_SND_SOC_SOF_IMX8M) += snd-sof-imx8m.o
|
||||
|
|
|
@ -0,0 +1,279 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
|
||||
//
|
||||
// Copyright 2020 NXP
|
||||
//
|
||||
// Author: Daniel Baluta <daniel.baluta@nxp.com>
|
||||
//
|
||||
// Hardware interface for audio DSP on i.MX8M
|
||||
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <sound/sof.h>
|
||||
#include <sound/sof/xtensa.h>
|
||||
#include <linux/firmware/imx/dsp.h>
|
||||
|
||||
#include "../ops.h"
|
||||
|
||||
#define MBOX_OFFSET 0x800000
|
||||
#define MBOX_SIZE 0x1000
|
||||
|
||||
struct imx8m_priv {
|
||||
struct device *dev;
|
||||
struct snd_sof_dev *sdev;
|
||||
|
||||
/* DSP IPC handler */
|
||||
struct imx_dsp_ipc *dsp_ipc;
|
||||
struct platform_device *ipc_dev;
|
||||
};
|
||||
|
||||
static void imx8m_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 int imx8m_get_mailbox_offset(struct snd_sof_dev *sdev)
|
||||
{
|
||||
return MBOX_OFFSET;
|
||||
}
|
||||
|
||||
static int imx8m_get_window_offset(struct snd_sof_dev *sdev, u32 id)
|
||||
{
|
||||
return MBOX_OFFSET;
|
||||
}
|
||||
|
||||
static void imx8m_dsp_handle_reply(struct imx_dsp_ipc *ipc)
|
||||
{
|
||||
struct imx8m_priv *priv = imx_dsp_get_data(ipc);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->sdev->ipc_lock, flags);
|
||||
imx8m_get_reply(priv->sdev);
|
||||
snd_sof_ipc_reply(priv->sdev, 0);
|
||||
spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags);
|
||||
}
|
||||
|
||||
static void imx8m_dsp_handle_request(struct imx_dsp_ipc *ipc)
|
||||
{
|
||||
struct imx8m_priv *priv = imx_dsp_get_data(ipc);
|
||||
|
||||
snd_sof_ipc_msgs_rx(priv->sdev);
|
||||
}
|
||||
|
||||
struct imx_dsp_ops imx8m_dsp_ops = {
|
||||
.handle_reply = imx8m_dsp_handle_reply,
|
||||
.handle_request = imx8m_dsp_handle_request,
|
||||
};
|
||||
|
||||
static int imx8m_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
|
||||
{
|
||||
struct imx8m_priv *priv = (struct imx8m_priv *)sdev->private;
|
||||
|
||||
sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
|
||||
msg->msg_size);
|
||||
imx_dsp_ring_doorbell(priv->dsp_ipc, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* DSP control.
|
||||
*/
|
||||
static int imx8m_run(struct snd_sof_dev *sdev)
|
||||
{
|
||||
/* TODO: start DSP using Audio MIX bits */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx8m_probe(struct snd_sof_dev *sdev)
|
||||
{
|
||||
struct platform_device *pdev =
|
||||
container_of(sdev->dev, struct platform_device, dev);
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device_node *res_node;
|
||||
struct resource *mmio;
|
||||
struct imx8m_priv *priv;
|
||||
struct resource res;
|
||||
u32 base, size;
|
||||
int ret = 0;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
sdev->private = priv;
|
||||
priv->dev = sdev->dev;
|
||||
priv->sdev = sdev;
|
||||
|
||||
priv->ipc_dev = platform_device_register_data(sdev->dev, "imx-dsp",
|
||||
PLATFORM_DEVID_NONE,
|
||||
pdev, sizeof(*pdev));
|
||||
if (IS_ERR(priv->ipc_dev))
|
||||
return PTR_ERR(priv->ipc_dev);
|
||||
|
||||
priv->dsp_ipc = dev_get_drvdata(&priv->ipc_dev->dev);
|
||||
if (!priv->dsp_ipc) {
|
||||
/* DSP IPC driver not probed yet, try later */
|
||||
ret = -EPROBE_DEFER;
|
||||
dev_err(sdev->dev, "Failed to get drvdata\n");
|
||||
goto exit_pdev_unregister;
|
||||
}
|
||||
|
||||
imx_dsp_set_data(priv->dsp_ipc, priv);
|
||||
priv->dsp_ipc->ops = &imx8m_dsp_ops;
|
||||
|
||||
/* DSP base */
|
||||
mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (mmio) {
|
||||
base = mmio->start;
|
||||
size = resource_size(mmio);
|
||||
} else {
|
||||
dev_err(sdev->dev, "error: failed to get DSP base at idx 0\n");
|
||||
ret = -EINVAL;
|
||||
goto exit_pdev_unregister;
|
||||
}
|
||||
|
||||
sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev, base, size);
|
||||
if (!sdev->bar[SOF_FW_BLK_TYPE_IRAM]) {
|
||||
dev_err(sdev->dev, "failed to ioremap base 0x%x size 0x%x\n",
|
||||
base, size);
|
||||
ret = -ENODEV;
|
||||
goto exit_pdev_unregister;
|
||||
}
|
||||
sdev->mmio_bar = SOF_FW_BLK_TYPE_IRAM;
|
||||
|
||||
res_node = of_parse_phandle(np, "memory-region", 0);
|
||||
if (!res_node) {
|
||||
dev_err(&pdev->dev, "failed to get memory region node\n");
|
||||
ret = -ENODEV;
|
||||
goto exit_pdev_unregister;
|
||||
}
|
||||
|
||||
ret = of_address_to_resource(res_node, 0, &res);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to get reserved region address\n");
|
||||
goto exit_pdev_unregister;
|
||||
}
|
||||
|
||||
sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, res.start,
|
||||
res.end - res.start +
|
||||
1);
|
||||
if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) {
|
||||
dev_err(sdev->dev, "failed to ioremap mem 0x%x size 0x%x\n",
|
||||
base, size);
|
||||
ret = -ENOMEM;
|
||||
goto exit_pdev_unregister;
|
||||
}
|
||||
sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM;
|
||||
|
||||
/* set default mailbox offset for FW ready message */
|
||||
sdev->dsp_box.offset = MBOX_OFFSET;
|
||||
|
||||
return 0;
|
||||
|
||||
exit_pdev_unregister:
|
||||
platform_device_unregister(priv->ipc_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx8m_remove(struct snd_sof_dev *sdev)
|
||||
{
|
||||
struct imx8m_priv *priv = (struct imx8m_priv *)sdev->private;
|
||||
|
||||
platform_device_unregister(priv->ipc_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* on i.MX8 there is 1 to 1 match between type and BAR idx */
|
||||
static int imx8m_get_bar_index(struct snd_sof_dev *sdev, u32 type)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
static void imx8m_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);
|
||||
}
|
||||
|
||||
static int imx8m_ipc_pcm_params(struct snd_sof_dev *sdev,
|
||||
struct snd_pcm_substream *substream,
|
||||
const struct sof_ipc_pcm_params_reply *reply)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_driver imx8m_dai[] = {
|
||||
{
|
||||
.name = "sai-port",
|
||||
},
|
||||
};
|
||||
|
||||
/* i.MX8 ops */
|
||||
struct snd_sof_dsp_ops sof_imx8m_ops = {
|
||||
/* probe and remove */
|
||||
.probe = imx8m_probe,
|
||||
.remove = imx8m_remove,
|
||||
/* DSP core boot */
|
||||
.run = imx8m_run,
|
||||
|
||||
/* Block IO */
|
||||
.block_read = sof_block_read,
|
||||
.block_write = sof_block_write,
|
||||
|
||||
/* ipc */
|
||||
.send_msg = imx8m_send_msg,
|
||||
.fw_ready = sof_fw_ready,
|
||||
.get_mailbox_offset = imx8m_get_mailbox_offset,
|
||||
.get_window_offset = imx8m_get_window_offset,
|
||||
|
||||
.ipc_msg_data = imx8m_ipc_msg_data,
|
||||
.ipc_pcm_params = imx8m_ipc_pcm_params,
|
||||
|
||||
/* module loading */
|
||||
.load_module = snd_sof_parse_module_memcpy,
|
||||
.get_bar_index = imx8m_get_bar_index,
|
||||
/* firmware loading */
|
||||
.load_firmware = snd_sof_load_firmware_memcpy,
|
||||
|
||||
/* DAI drivers */
|
||||
.drv = imx8m_dai,
|
||||
.num_drv = 1, /* we have only 1 SAI interface on i.MX8M */
|
||||
};
|
||||
EXPORT_SYMBOL(sof_imx8m_ops);
|
||||
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
extern struct snd_sof_dsp_ops sof_imx8_ops;
|
||||
extern struct snd_sof_dsp_ops sof_imx8x_ops;
|
||||
extern struct snd_sof_dsp_ops sof_imx8m_ops;
|
||||
|
||||
/* platform specific devices */
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8)
|
||||
|
@ -34,6 +35,16 @@ static struct sof_dev_desc sof_of_imx8qm_desc = {
|
|||
};
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8M)
|
||||
static struct sof_dev_desc sof_of_imx8mp_desc = {
|
||||
.default_fw_path = "imx/sof",
|
||||
.default_tplg_path = "imx/sof-tplg",
|
||||
.default_fw_filename = "sof-imx8m.ri",
|
||||
.nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
|
||||
.ops = &sof_imx8m_ops,
|
||||
};
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops sof_of_pm = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume)
|
||||
SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume,
|
||||
|
@ -113,6 +124,9 @@ static const struct of_device_id sof_of_ids[] = {
|
|||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8)
|
||||
{ .compatible = "fsl,imx8qxp-dsp", .data = &sof_of_imx8qxp_desc},
|
||||
{ .compatible = "fsl,imx8qm-dsp", .data = &sof_of_imx8qm_desc},
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8M)
|
||||
{ .compatible = "fsl,imx8mp-dsp", .data = &sof_of_imx8mp_desc},
|
||||
#endif
|
||||
{ }
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue