alsa-devel.alsa-project.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/6] Add audio driver base on rpmsg on i.MX platform
@ 2021-03-08 13:22 Shengjiu Wang
  2021-03-08 13:22 ` [PATCH v4 1/6] ASoC: soc-component: Add snd_soc_pcm_component_ack Shengjiu Wang
                   ` (5 more replies)
  0 siblings, 6 replies; 12+ messages in thread
From: Shengjiu Wang @ 2021-03-08 13:22 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, alsa-devel, linux-kernel,
	timur, nicoleotsuka, Xiubo.Lee, festevam, linuxppc-dev, robh+dt,
	devicetree

On Asymmetric multiprocessor, there is Cortex-A core and Cortex-M core,
Linux is running on A core, RTOS is running on M core.
The audio hardware device can be controlled by Cortex-M device,
So audio playback/capture can be handled by M core.

Rpmsg is the interface for sending and receiving msg to and from M
core, that we can create a virtual sound on Cortex-A core side.

A core will tell the Cortex-M core sound format/rate/channel,
where is the data buffer, what is the period size, when to start,
when to stop and when suspend or resume happen, each of this behavior
there is defined rpmsg command.

Especially we designed the low power audio case, that is to
allocate a large buffer and fill the data, then Cortex-A core can go
to sleep mode, Cortex-M core continue to play the sound, when the
buffer is consumed, Cortex-M core will trigger the Cortex-A core to
wakeup to fill data.

changes in v4:
- remove the sound card node, merge the property to cpu dai node
  according to Rob's comments.
- sound card device will be registered by cpu dai driver.
- Fix do_div issue reported by kernel test robot

changes in v3:
- add local refcount for clk enablement in hw_params()
- update the document according Rob's comments

changes in v2:
- update codes and comments according to Mark's comments

Shengjiu Wang (6):
  ASoC: soc-component: Add snd_soc_pcm_component_ack
  ASoC: fsl_rpmsg: Add CPU DAI driver for audio base on rpmsg
  ASoC: dt-bindings: fsl_rpmsg: Add binding doc for rpmsg cpu dai driver
  ASoC: imx-audio-rpmsg: Add rpmsg_driver for audio channel
  ASoC: imx-pcm-rpmsg: Add platform driver for audio base on rpmsg
  ASoC: imx-rpmsg: Add machine driver for audio base on rpmsg

 .../devicetree/bindings/sound/fsl,rpmsg.yaml  | 118 +++
 include/sound/soc-component.h                 |   3 +
 sound/soc/fsl/Kconfig                         |  28 +
 sound/soc/fsl/Makefile                        |   6 +
 sound/soc/fsl/fsl_rpmsg.c                     | 283 ++++++
 sound/soc/fsl/fsl_rpmsg.h                     |  42 +
 sound/soc/fsl/imx-audio-rpmsg.c               | 151 +++
 sound/soc/fsl/imx-pcm-rpmsg.c                 | 919 ++++++++++++++++++
 sound/soc/fsl/imx-pcm-rpmsg.h                 | 512 ++++++++++
 sound/soc/fsl/imx-rpmsg.c                     | 127 +++
 sound/soc/soc-component.c                     |  14 +
 sound/soc/soc-pcm.c                           |   2 +
 12 files changed, 2205 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
 create mode 100644 sound/soc/fsl/fsl_rpmsg.c
 create mode 100644 sound/soc/fsl/fsl_rpmsg.h
 create mode 100644 sound/soc/fsl/imx-audio-rpmsg.c
 create mode 100644 sound/soc/fsl/imx-pcm-rpmsg.c
 create mode 100644 sound/soc/fsl/imx-pcm-rpmsg.h
 create mode 100644 sound/soc/fsl/imx-rpmsg.c

-- 
2.27.0


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v4 1/6] ASoC: soc-component: Add snd_soc_pcm_component_ack
  2021-03-08 13:22 [PATCH v4 0/6] Add audio driver base on rpmsg on i.MX platform Shengjiu Wang
@ 2021-03-08 13:22 ` Shengjiu Wang
  2021-03-08 13:22 ` [PATCH v4 2/6] ASoC: fsl_rpmsg: Add CPU DAI driver for audio base on rpmsg Shengjiu Wang
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Shengjiu Wang @ 2021-03-08 13:22 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, alsa-devel, linux-kernel,
	timur, nicoleotsuka, Xiubo.Lee, festevam, linuxppc-dev, robh+dt,
	devicetree

Add snd_soc_pcm_component_ack back, which can be used to get an
updated buffer pointer in the platform driver.
On Asymmetric multiprocessor, this pointer can be sent to Cortex-M
core for audio processing.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
---
 include/sound/soc-component.h |  3 +++
 sound/soc/soc-component.c     | 14 ++++++++++++++
 sound/soc/soc-pcm.c           |  2 ++
 3 files changed, 19 insertions(+)

diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h
index 7dc75b39287f..722cfab28d29 100644
--- a/include/sound/soc-component.h
+++ b/include/sound/soc-component.h
@@ -146,6 +146,8 @@ struct snd_soc_component_driver {
 	int (*mmap)(struct snd_soc_component *component,
 		    struct snd_pcm_substream *substream,
 		    struct vm_area_struct *vma);
+	int (*ack)(struct snd_soc_component *component,
+		   struct snd_pcm_substream *substream);
 
 	const struct snd_compress_ops *compress_ops;
 
@@ -498,5 +500,6 @@ int snd_soc_pcm_component_pm_runtime_get(struct snd_soc_pcm_runtime *rtd,
 					 void *stream);
 void snd_soc_pcm_component_pm_runtime_put(struct snd_soc_pcm_runtime *rtd,
 					  void *stream, int rollback);
+int snd_soc_pcm_component_ack(struct snd_pcm_substream *substream);
 
 #endif /* __SOC_COMPONENT_H */
diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c
index 8415e9bd2932..3a5e84e16a87 100644
--- a/sound/soc/soc-component.c
+++ b/sound/soc/soc-component.c
@@ -1212,3 +1212,17 @@ void snd_soc_pcm_component_pm_runtime_put(struct snd_soc_pcm_runtime *rtd,
 		soc_component_mark_pop(component, stream, pm);
 	}
 }
+
+int snd_soc_pcm_component_ack(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+	struct snd_soc_component *component;
+	int i;
+
+	/* FIXME: use 1st pointer */
+	for_each_rtd_components(rtd, i, component)
+		if (component->driver->ack)
+			return component->driver->ack(component, substream);
+
+	return 0;
+}
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index ba8ffbf8a5d3..e75b404a9f36 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -2826,6 +2826,8 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 			rtd->ops.page		= snd_soc_pcm_component_page;
 		if (drv->mmap)
 			rtd->ops.mmap		= snd_soc_pcm_component_mmap;
+		if (drv->ack)
+			rtd->ops.ack            = snd_soc_pcm_component_ack;
 	}
 
 	if (playback)
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v4 2/6] ASoC: fsl_rpmsg: Add CPU DAI driver for audio base on rpmsg
  2021-03-08 13:22 [PATCH v4 0/6] Add audio driver base on rpmsg on i.MX platform Shengjiu Wang
  2021-03-08 13:22 ` [PATCH v4 1/6] ASoC: soc-component: Add snd_soc_pcm_component_ack Shengjiu Wang
@ 2021-03-08 13:22 ` Shengjiu Wang
  2021-03-08 22:37   ` kernel test robot
  2021-03-08 13:22 ` [PATCH v4 3/6] ASoC: dt-bindings: fsl_rpmsg: Add binding doc for rpmsg cpu dai driver Shengjiu Wang
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 12+ messages in thread
From: Shengjiu Wang @ 2021-03-08 13:22 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, alsa-devel, linux-kernel,
	timur, nicoleotsuka, Xiubo.Lee, festevam, linuxppc-dev, robh+dt,
	devicetree

This is a cpu dai driver for rpmsg audio use case,
which is mainly used for getting the user's configuration
from devicetree and configure the clocks which is used by
Cortex-M core.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
---
 sound/soc/fsl/Kconfig     |   7 +
 sound/soc/fsl/Makefile    |   2 +
 sound/soc/fsl/fsl_rpmsg.c | 283 ++++++++++++++++++++++++++++++++++++++
 sound/soc/fsl/fsl_rpmsg.h |  42 ++++++
 4 files changed, 334 insertions(+)
 create mode 100644 sound/soc/fsl/fsl_rpmsg.c
 create mode 100644 sound/soc/fsl/fsl_rpmsg.h

diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index d7f30036d434..f833856f6de0 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -115,6 +115,13 @@ config SND_SOC_FSL_AUD2HTX
 config SND_SOC_FSL_UTILS
 	tristate
 
+config SND_SOC_FSL_RPMSG
+	tristate "NXP Audio Base On RPMSG support"
+	help
+	  Say Y if you want to add rpmsg audio support for the Freescale CPUs.
+	  This option is only useful for out-of-tree drivers since
+	  in-tree drivers select it automatically.
+
 config SND_SOC_IMX_PCM_DMA
 	tristate
 	select SND_SOC_GENERIC_DMAENGINE_PCM
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 8c5fa8a859c0..b63802f345cc 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -27,6 +27,7 @@ snd-soc-fsl-mqs-objs := fsl_mqs.o
 snd-soc-fsl-easrc-objs := fsl_easrc.o
 snd-soc-fsl-xcvr-objs := fsl_xcvr.o
 snd-soc-fsl-aud2htx-objs := fsl_aud2htx.o
+snd-soc-fsl-rpmsg-objs := fsl_rpmsg.o
 
 obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o
 obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o
@@ -42,6 +43,7 @@ obj-$(CONFIG_SND_SOC_FSL_EASRC) += snd-soc-fsl-easrc.o
 obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
 obj-$(CONFIG_SND_SOC_FSL_XCVR) += snd-soc-fsl-xcvr.o
 obj-$(CONFIG_SND_SOC_FSL_AUD2HTX) += snd-soc-fsl-aud2htx.o
+obj-$(CONFIG_SND_SOC_FSL_RPMSG) += snd-soc-fsl-rpmsg.o
 
 # MPC5200 Platform Support
 obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
diff --git a/sound/soc/fsl/fsl_rpmsg.c b/sound/soc/fsl/fsl_rpmsg.c
new file mode 100644
index 000000000000..35b3ee376338
--- /dev/null
+++ b/sound/soc/fsl/fsl_rpmsg.c
@@ -0,0 +1,283 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright 2018-2021 NXP
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include <linux/rpmsg.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_params.h>
+
+#include "fsl_rpmsg.h"
+#include "imx-pcm.h"
+
+#define FSL_RPMSG_RATES        (SNDRV_PCM_RATE_8000 | \
+				SNDRV_PCM_RATE_16000 | \
+				SNDRV_PCM_RATE_48000)
+#define FSL_RPMSG_FORMATS	SNDRV_PCM_FMTBIT_S16_LE
+
+static const unsigned int fsl_rpmsg_rates[] = {
+	8000, 11025, 16000, 22050, 44100,
+	32000, 48000, 96000, 88200, 176400, 192000,
+	352800, 384000, 705600, 768000, 1411200, 2822400,
+};
+
+static const struct snd_pcm_hw_constraint_list fsl_rpmsg_rate_constraints = {
+	.count = ARRAY_SIZE(fsl_rpmsg_rates),
+	.list = fsl_rpmsg_rates,
+};
+
+static int fsl_rpmsg_hw_params(struct snd_pcm_substream *substream,
+			       struct snd_pcm_hw_params *params,
+			       struct snd_soc_dai *dai)
+{
+	struct fsl_rpmsg *rpmsg = snd_soc_dai_get_drvdata(dai);
+	struct clk *p = rpmsg->mclk, *pll = 0, *npll = 0;
+	u64 rate = params_rate(params);
+	int ret = 0;
+
+	/* Get current pll parent */
+	while (p && rpmsg->pll8k && rpmsg->pll11k) {
+		struct clk *pp = clk_get_parent(p);
+
+		if (clk_is_match(pp, rpmsg->pll8k) ||
+		    clk_is_match(pp, rpmsg->pll11k)) {
+			pll = pp;
+			break;
+		}
+		p = pp;
+	}
+
+	/* Switch to another pll parent if needed. */
+	if (pll) {
+		npll = (do_div(rate, 8000) ? rpmsg->pll11k : rpmsg->pll8k);
+		if (!clk_is_match(pll, npll)) {
+			ret = clk_set_parent(p, npll);
+			if (ret < 0)
+				dev_warn(dai->dev, "failed to set parent %s: %d\n",
+					 __clk_get_name(npll), ret);
+		}
+	}
+
+	if (!(rpmsg->mclk_streams & BIT(substream->stream))) {
+		ret = clk_prepare_enable(rpmsg->mclk);
+		if (ret) {
+			dev_err(dai->dev, "failed to enable mclk: %d\n", ret);
+			return ret;
+		}
+
+		rpmsg->mclk_streams |= BIT(substream->stream);
+	}
+
+	return ret;
+}
+
+static int fsl_rpmsg_hw_free(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *dai)
+{
+	struct fsl_rpmsg *rpmsg = snd_soc_dai_get_drvdata(dai);
+
+	if (rpmsg->mclk_streams & BIT(substream->stream)) {
+		clk_disable_unprepare(rpmsg->mclk);
+		rpmsg->mclk_streams &= ~BIT(substream->stream);
+	}
+
+	return 0;
+}
+
+static int fsl_rpmsg_startup(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *cpu_dai)
+{
+	int ret;
+
+	ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
+					 SNDRV_PCM_HW_PARAM_RATE,
+					 &fsl_rpmsg_rate_constraints);
+
+	return ret;
+}
+
+static const struct snd_soc_dai_ops fsl_rpmsg_dai_ops = {
+	.startup	= fsl_rpmsg_startup,
+	.hw_params      = fsl_rpmsg_hw_params,
+	.hw_free        = fsl_rpmsg_hw_free,
+};
+
+static struct snd_soc_dai_driver fsl_rpmsg_dai = {
+	.playback = {
+		.stream_name = "CPU-Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_KNOT,
+		.formats = FSL_RPMSG_FORMATS,
+	},
+	.capture = {
+		.stream_name = "CPU-Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_KNOT,
+		.formats = FSL_RPMSG_FORMATS,
+	},
+	.symmetric_rate        = 1,
+	.symmetric_channels    = 1,
+	.symmetric_sample_bits = 1,
+	.ops = &fsl_rpmsg_dai_ops,
+};
+
+static const struct snd_soc_component_driver fsl_component = {
+	.name           = "fsl-rpmsg",
+};
+
+static const struct of_device_id fsl_rpmsg_ids[] = {
+	{ .compatible = "fsl,imx7ulp-rpmsg"},
+	{ .compatible = "fsl,imx8mm-rpmsg"},
+	{ .compatible = "fsl,imx8mn-rpmsg"},
+	{ .compatible = "fsl,imx8mp-rpmsg"},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fsl_rpmsg_ids);
+
+static int fsl_rpmsg_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct fsl_rpmsg *rpmsg;
+	int ret;
+
+	rpmsg = devm_kzalloc(&pdev->dev, sizeof(struct fsl_rpmsg), GFP_KERNEL);
+	if (!rpmsg)
+		return -ENOMEM;
+
+	ret = of_property_read_u32(np, "fsl,audioindex", &rpmsg->audioindex);
+	if (ret)
+		rpmsg->audioindex = 0;
+
+	if (of_property_read_u32(np, "fsl,buffer-size", &rpmsg->buffer_size))
+		rpmsg->buffer_size = IMX_DEFAULT_DMABUF_SIZE;
+
+	if (of_property_read_bool(pdev->dev.of_node, "fsl,enable-lpa"))
+		rpmsg->enable_lpa = 1;
+
+	ret = of_property_read_u32(np, "fsl,version", &rpmsg->version);
+	if (ret)
+		rpmsg->version = API_VERSION_V2;
+
+	/*Get the optional clocks */
+	rpmsg->ipg = devm_clk_get(&pdev->dev, "ipg");
+	if (IS_ERR(rpmsg->ipg))
+		rpmsg->ipg = NULL;
+
+	rpmsg->mclk = devm_clk_get(&pdev->dev, "mclk");
+	if (IS_ERR(rpmsg->mclk))
+		rpmsg->mclk = NULL;
+
+	rpmsg->dma = devm_clk_get(&pdev->dev, "dma");
+	if (IS_ERR(rpmsg->dma))
+		rpmsg->dma = NULL;
+
+	rpmsg->pll8k = devm_clk_get(&pdev->dev, "pll8k");
+	if (IS_ERR(rpmsg->pll8k))
+		rpmsg->pll8k = NULL;
+
+	rpmsg->pll11k = devm_clk_get(&pdev->dev, "pll11k");
+	if (IS_ERR(rpmsg->pll11k))
+		rpmsg->pll11k = NULL;
+
+	platform_set_drvdata(pdev, rpmsg);
+	pm_runtime_enable(&pdev->dev);
+
+	ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
+					      &fsl_rpmsg_dai, 1);
+	if (ret)
+		return ret;
+
+	rpmsg->card_pdev = platform_device_register_data(&pdev->dev,
+							 "imx-audio-rpmsg",
+							 PLATFORM_DEVID_NONE,
+							 NULL,
+							 0);
+	if (IS_ERR(rpmsg->card_pdev)) {
+		dev_err(&pdev->dev, "failed to register rpmsg card\n");
+		ret = PTR_ERR(rpmsg->card_pdev);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int fsl_rpmsg_remove(struct platform_device *pdev)
+{
+	struct fsl_rpmsg *rpmsg = platform_get_drvdata(pdev);
+
+	if (rpmsg->card_pdev)
+		platform_device_unregister(rpmsg->card_pdev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int fsl_rpmsg_runtime_resume(struct device *dev)
+{
+	struct fsl_rpmsg *rpmsg = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_prepare_enable(rpmsg->ipg);
+	if (ret) {
+		dev_err(dev, "failed to enable ipg clock: %d\n", ret);
+		goto ipg_err;
+	}
+
+	ret = clk_prepare_enable(rpmsg->dma);
+	if (ret) {
+		dev_err(dev, "Failed to enable dma clock %d\n", ret);
+		goto dma_err;
+	}
+
+	return 0;
+
+dma_err:
+	clk_disable_unprepare(rpmsg->ipg);
+ipg_err:
+	return ret;
+}
+
+static int fsl_rpmsg_runtime_suspend(struct device *dev)
+{
+	struct fsl_rpmsg *rpmsg = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(rpmsg->dma);
+	clk_disable_unprepare(rpmsg->ipg);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops fsl_rpmsg_pm_ops = {
+	SET_RUNTIME_PM_OPS(fsl_rpmsg_runtime_suspend,
+			   fsl_rpmsg_runtime_resume,
+			   NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
+static struct platform_driver fsl_rpmsg_driver = {
+	.probe  = fsl_rpmsg_probe,
+	.remove = fsl_rpmsg_remove,
+	.driver = {
+		.name = "fsl_rpmsg",
+		.pm = &fsl_rpmsg_pm_ops,
+		.of_match_table = fsl_rpmsg_ids,
+	},
+};
+module_platform_driver(fsl_rpmsg_driver);
+
+MODULE_DESCRIPTION("Freescale SoC Audio PRMSG CPU Interface");
+MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
+MODULE_ALIAS("platform:fsl_rpmsg");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/fsl_rpmsg.h b/sound/soc/fsl/fsl_rpmsg.h
new file mode 100644
index 000000000000..c6dd3dde3293
--- /dev/null
+++ b/sound/soc/fsl/fsl_rpmsg.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2017-2021 NXP
+ */
+
+#ifndef __FSL_RPMSG_H
+#define __FSL_RPMSG_H
+
+#define API_VERSION_V1  1
+#define API_VERSION_V2  2
+
+/*
+ * struct fsl_rpmsg - rpmsg private data
+ *
+ * @ipg: ipg clock for cpu dai (SAI)
+ * @mclk: master clock for cpu dai (SAI)
+ * @dma: clock for dma device
+ * @pll8k: parent clock for multiple of 8kHz frequency
+ * @pll11k: parent clock for multiple of 11kHz frequency
+ * @card_pdev: Platform_device pointer to register a sound card
+ * @mclk_streams: Active streams that are using baudclk
+ * @force_lpa: force enable low power audio routine if condition satisfy
+ * @enable_lpa: enable low power audio routine according to dts setting
+ * @buffer_size: pre allocated dma buffer size
+ * @audioindex: audio instance index
+ * @version: rpmsg image version
+ */
+struct fsl_rpmsg {
+	struct clk *ipg;
+	struct clk *mclk;
+	struct clk *dma;
+	struct clk *pll8k;
+	struct clk *pll11k;
+	struct platform_device *card_pdev;
+	unsigned int mclk_streams;
+	int force_lpa;
+	int enable_lpa;
+	int buffer_size;
+	int audioindex;
+	int version;
+};
+#endif /* __FSL_RPMSG_H */
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v4 3/6] ASoC: dt-bindings: fsl_rpmsg: Add binding doc for rpmsg cpu dai driver
  2021-03-08 13:22 [PATCH v4 0/6] Add audio driver base on rpmsg on i.MX platform Shengjiu Wang
  2021-03-08 13:22 ` [PATCH v4 1/6] ASoC: soc-component: Add snd_soc_pcm_component_ack Shengjiu Wang
  2021-03-08 13:22 ` [PATCH v4 2/6] ASoC: fsl_rpmsg: Add CPU DAI driver for audio base on rpmsg Shengjiu Wang
@ 2021-03-08 13:22 ` Shengjiu Wang
  2021-03-10  2:48   ` Rob Herring
  2021-03-08 13:22 ` [PATCH v4 4/6] ASoC: imx-audio-rpmsg: Add rpmsg_driver for audio channel Shengjiu Wang
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 12+ messages in thread
From: Shengjiu Wang @ 2021-03-08 13:22 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, alsa-devel, linux-kernel,
	timur, nicoleotsuka, Xiubo.Lee, festevam, linuxppc-dev, robh+dt,
	devicetree

fsl_rpmsg cpu dai driver is driver for rpmsg audio, which is mainly used
for getting the user's configuration from device tree and configure the
clocks which is used by Cortex-M core. So in this document define the
needed property.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
---
 .../devicetree/bindings/sound/fsl,rpmsg.yaml  | 118 ++++++++++++++++++
 1 file changed, 118 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml

diff --git a/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
new file mode 100644
index 000000000000..5731c1fbc0a6
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
@@ -0,0 +1,118 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/fsl,rpmsg.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP Audio RPMSG CPU DAI Controller
+
+maintainers:
+  - Shengjiu Wang <shengjiu.wang@nxp.com>
+
+description: |
+  fsl_rpmsg cpu dai driver is virtual driver for rpmsg audio, which doesn't
+  touch hardware. It is mainly used for getting the user's configuration
+  from device tree and configure the clocks which is used by Cortex-M core.
+  So in this document define the needed property.
+
+properties:
+  compatible:
+    enum:
+      - fsl,imx7ulp-rpmsg
+      - fsl,imx8mn-rpmsg
+      - fsl,imx8mm-rpmsg
+      - fsl,imx8mp-rpmsg
+
+  model:
+    $ref: /schemas/types.yaml#/definitions/string
+    description: User specified audio sound card name
+
+  clocks:
+    items:
+      - description: Peripheral clock for register access
+      - description: Master clock
+      - description: DMA clock for DMA register access
+      - description: Parent clock for multiple of 8kHz sample rates
+      - description: Parent clock for multiple of 11kHz sample rates
+    minItems: 5
+
+  clock-names:
+    items:
+      - const: ipg
+      - const: mclk
+      - const: dma
+      - const: pll8k
+      - const: pll11k
+    minItems: 5
+
+  power-domains:
+    maxItems: 1
+
+  fsl,audioindex:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [0, 1]
+    default: 0
+    description: Instance index for sound card in
+                 M core side, which share one rpmsg
+                 channel.
+
+  fsl,version:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [1, 2]
+    default: 2
+    description: The version of M core image, which is
+                 to make driver compatible with different image.
+
+  fsl,buffer-size:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: pre allocate dma buffer size
+
+  fsl,enable-lpa:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description: enable low power audio path.
+
+  fsl,rpmsg-out:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description: |
+      This is a boolean property. If present, the transmitting function
+      will be enabled.
+
+  fsl,rpmsg-in:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description: |
+      This is a boolean property. If present, the receiving function
+      will be enabled.
+
+  fsl,codec-type:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [0, 1, 2]
+    default: 0
+    description: Sometimes the codec is registered by
+                 driver not by the device tree, this items
+                 can be used to distinguish codecs.
+
+  audio-codec:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: The phandle of the audio codec
+
+  memory-region:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: phandle to the reserved memory nodes
+
+required:
+  - compatible
+  - fsl,audioindex
+  - fsl,version
+  - fsl,buffer-size
+
+additionalProperties: false
+
+examples:
+  - |
+    rpmsg_audio: rpmsg_audio {
+        compatible = "fsl,imx8mn-rpmsg";
+        fsl,audioindex = <0> ;
+        fsl,version = <2>;
+        fsl,buffer-size = <0x6000000>;
+        fsl,enable-lpa;
+    };
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v4 4/6] ASoC: imx-audio-rpmsg: Add rpmsg_driver for audio channel
  2021-03-08 13:22 [PATCH v4 0/6] Add audio driver base on rpmsg on i.MX platform Shengjiu Wang
                   ` (2 preceding siblings ...)
  2021-03-08 13:22 ` [PATCH v4 3/6] ASoC: dt-bindings: fsl_rpmsg: Add binding doc for rpmsg cpu dai driver Shengjiu Wang
@ 2021-03-08 13:22 ` Shengjiu Wang
  2021-03-08 13:22 ` [PATCH v4 5/6] ASoC: imx-pcm-rpmsg: Add platform driver for audio base on rpmsg Shengjiu Wang
  2021-03-08 13:22 ` [PATCH v4 6/6] ASoC: imx-rpmsg: Add machine " Shengjiu Wang
  5 siblings, 0 replies; 12+ messages in thread
From: Shengjiu Wang @ 2021-03-08 13:22 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, alsa-devel, linux-kernel,
	timur, nicoleotsuka, Xiubo.Lee, festevam, linuxppc-dev, robh+dt,
	devicetree

This driver is used to accept the message from rpmsg audio
channel, and if this driver is probed, it will help to register
the platform driver, the platform driver will use this
audio channel to send and receive messages to and from Cortex-M
core.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
---
 sound/soc/fsl/Kconfig           |   4 +
 sound/soc/fsl/Makefile          |   1 +
 sound/soc/fsl/imx-audio-rpmsg.c | 151 ++++++++++++++++++++++++++++++++
 3 files changed, 156 insertions(+)
 create mode 100644 sound/soc/fsl/imx-audio-rpmsg.c

diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index f833856f6de0..cc81f6b917be 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -126,6 +126,10 @@ config SND_SOC_IMX_PCM_DMA
 	tristate
 	select SND_SOC_GENERIC_DMAENGINE_PCM
 
+config SND_SOC_IMX_AUDIO_RPMSG
+	tristate
+	depends on RPMSG
+
 config SND_SOC_IMX_AUDMUX
 	tristate "Digital Audio Mux module support"
 	help
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index b63802f345cc..f08f3cd07ff5 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -60,6 +60,7 @@ obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o
 
 obj-$(CONFIG_SND_SOC_IMX_PCM_FIQ) += imx-pcm-fiq.o
 obj-$(CONFIG_SND_SOC_IMX_PCM_DMA) += imx-pcm-dma.o
+obj-$(CONFIG_SND_SOC_IMX_AUDIO_RPMSG) += imx-audio-rpmsg.o
 
 # i.MX Machine Support
 snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
diff --git a/sound/soc/fsl/imx-audio-rpmsg.c b/sound/soc/fsl/imx-audio-rpmsg.c
new file mode 100644
index 000000000000..145edb1492b4
--- /dev/null
+++ b/sound/soc/fsl/imx-audio-rpmsg.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright 2017-2020 NXP
+
+#include <linux/module.h>
+#include <linux/rpmsg.h>
+#include "imx-pcm-rpmsg.h"
+
+/*
+ * struct imx_audio_rpmsg: private data
+ *
+ * @rpmsg_pdev: pointer of platform device
+ */
+struct imx_audio_rpmsg {
+	struct platform_device *rpmsg_pdev;
+};
+
+static int imx_audio_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
+			      void *priv, u32 src)
+{
+	struct imx_audio_rpmsg *rpmsg = dev_get_drvdata(&rpdev->dev);
+	struct rpmsg_info *info = platform_get_drvdata(rpmsg->rpmsg_pdev);
+	struct rpmsg_r_msg *r_msg = (struct rpmsg_r_msg *)data;
+	struct rpmsg_msg *msg;
+	unsigned long flags;
+
+	dev_dbg(&rpdev->dev, "get from%d: cmd:%d. %d\n",
+		src, r_msg->header.cmd, r_msg->param.resp);
+
+	switch (r_msg->header.type) {
+	case MSG_TYPE_C:
+		/* TYPE C is notification from M core */
+		switch (r_msg->header.cmd) {
+		case TX_PERIOD_DONE:
+			spin_lock_irqsave(&info->lock[TX], flags);
+			msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
+
+			/*
+			 * Low power mode: get the buffer pointer from
+			 * receive msg.
+			 */
+			if (r_msg->header.major == 1 &&
+			    r_msg->header.minor == 2)
+				msg->r_msg.param.buffer_tail =
+						r_msg->param.buffer_tail;
+			else
+				msg->r_msg.param.buffer_tail++;
+
+			msg->r_msg.param.buffer_tail %= info->num_period[TX];
+			spin_unlock_irqrestore(&info->lock[TX], flags);
+			info->callback[TX](info->callback_param[TX]);
+			break;
+		case RX_PERIOD_DONE:
+			spin_lock_irqsave(&info->lock[RX], flags);
+			msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
+
+			if (r_msg->header.major == 1 &&
+			    r_msg->header.minor == 2)
+				msg->r_msg.param.buffer_tail =
+						r_msg->param.buffer_tail;
+			else
+				msg->r_msg.param.buffer_tail++;
+
+			msg->r_msg.param.buffer_tail %= info->num_period[1];
+			spin_unlock_irqrestore(&info->lock[RX], flags);
+			info->callback[RX](info->callback_param[RX]);
+			break;
+		default:
+			dev_warn(&rpdev->dev, "unknown msg command\n");
+			break;
+		}
+		break;
+	case MSG_TYPE_B:
+		/* TYPE B is response msg */
+		memcpy(&info->r_msg, r_msg, sizeof(struct rpmsg_r_msg));
+		complete(&info->cmd_complete);
+		break;
+	default:
+		dev_warn(&rpdev->dev, "unknown msg type\n");
+		break;
+	}
+
+	return 0;
+}
+
+static int imx_audio_rpmsg_probe(struct rpmsg_device *rpdev)
+{
+	struct imx_audio_rpmsg *data;
+	int ret = 0;
+
+	dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
+		 rpdev->src, rpdev->dst);
+
+	data = devm_kzalloc(&rpdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	dev_set_drvdata(&rpdev->dev, data);
+
+	/* Register platform driver for rpmsg routine */
+	data->rpmsg_pdev = platform_device_register_data(&rpdev->dev,
+							 IMX_PCM_DRV_NAME,
+							 PLATFORM_DEVID_NONE,
+							 NULL, 0);
+	if (IS_ERR(data->rpmsg_pdev)) {
+		dev_err(&rpdev->dev, "failed to register rpmsg platform.\n");
+		ret = PTR_ERR(data->rpmsg_pdev);
+	}
+
+	return ret;
+}
+
+static void imx_audio_rpmsg_remove(struct rpmsg_device *rpdev)
+{
+	struct imx_audio_rpmsg *data = dev_get_drvdata(&rpdev->dev);
+
+	if (data->rpmsg_pdev)
+		platform_device_unregister(data->rpmsg_pdev);
+
+	dev_info(&rpdev->dev, "audio rpmsg driver is removed\n");
+}
+
+static struct rpmsg_device_id imx_audio_rpmsg_id_table[] = {
+	{ .name	= "rpmsg-audio-channel" },
+	{ },
+};
+
+static struct rpmsg_driver imx_audio_rpmsg_driver = {
+	.drv.name	= "imx_audio_rpmsg",
+	.drv.owner	= THIS_MODULE,
+	.id_table	= imx_audio_rpmsg_id_table,
+	.probe		= imx_audio_rpmsg_probe,
+	.callback	= imx_audio_rpmsg_cb,
+	.remove		= imx_audio_rpmsg_remove,
+};
+
+static int __init imx_audio_rpmsg_init(void)
+{
+	return register_rpmsg_driver(&imx_audio_rpmsg_driver);
+}
+
+static void __exit imx_audio_rpmsg_exit(void)
+{
+	unregister_rpmsg_driver(&imx_audio_rpmsg_driver);
+}
+module_init(imx_audio_rpmsg_init);
+module_exit(imx_audio_rpmsg_exit);
+
+MODULE_DESCRIPTION("Freescale SoC Audio RPMSG interface");
+MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
+MODULE_ALIAS("platform:imx_audio_rpmsg");
+MODULE_LICENSE("GPL v2");
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v4 5/6] ASoC: imx-pcm-rpmsg: Add platform driver for audio base on rpmsg
  2021-03-08 13:22 [PATCH v4 0/6] Add audio driver base on rpmsg on i.MX platform Shengjiu Wang
                   ` (3 preceding siblings ...)
  2021-03-08 13:22 ` [PATCH v4 4/6] ASoC: imx-audio-rpmsg: Add rpmsg_driver for audio channel Shengjiu Wang
@ 2021-03-08 13:22 ` Shengjiu Wang
  2021-03-08 13:22 ` [PATCH v4 6/6] ASoC: imx-rpmsg: Add machine " Shengjiu Wang
  5 siblings, 0 replies; 12+ messages in thread
From: Shengjiu Wang @ 2021-03-08 13:22 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, alsa-devel, linux-kernel,
	timur, nicoleotsuka, Xiubo.Lee, festevam, linuxppc-dev, robh+dt,
	devicetree

Platform driver based on rpmsg is the interface for sending and
receiving rpmsg to and from M core. It will tell the Cortex-M core
sound format/rate/channel, where is the data buffer, where is
the period size, when to start, when to stop and when suspend
or resume happen, each this behavior there is defined rpmsg
command.

Especially we designed the low power audio case, that is to
allocate a large buffer and fill the data, then Cortex-A core can go
to sleep mode, Cortex-M core continue to play the sound, when the
buffer is consumed, Cortex-M core will trigger the Cortex-A core to
wake up.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
---
 sound/soc/fsl/Kconfig         |   5 +
 sound/soc/fsl/Makefile        |   1 +
 sound/soc/fsl/imx-pcm-rpmsg.c | 919 ++++++++++++++++++++++++++++++++++
 sound/soc/fsl/imx-pcm-rpmsg.h | 512 +++++++++++++++++++
 4 files changed, 1437 insertions(+)
 create mode 100644 sound/soc/fsl/imx-pcm-rpmsg.c
 create mode 100644 sound/soc/fsl/imx-pcm-rpmsg.h

diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index cc81f6b917be..3b94882aee99 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -130,6 +130,11 @@ config SND_SOC_IMX_AUDIO_RPMSG
 	tristate
 	depends on RPMSG
 
+config SND_SOC_IMX_PCM_RPMSG
+	tristate
+	depends on SND_SOC_IMX_AUDIO_RPMSG
+	select SND_SOC_GENERIC_DMAENGINE_PCM
+
 config SND_SOC_IMX_AUDMUX
 	tristate "Digital Audio Mux module support"
 	help
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index f08f3cd07ff5..ce4f4324c3a2 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o
 obj-$(CONFIG_SND_SOC_IMX_PCM_FIQ) += imx-pcm-fiq.o
 obj-$(CONFIG_SND_SOC_IMX_PCM_DMA) += imx-pcm-dma.o
 obj-$(CONFIG_SND_SOC_IMX_AUDIO_RPMSG) += imx-audio-rpmsg.o
+obj-$(CONFIG_SND_SOC_IMX_PCM_RPMSG) += imx-pcm-rpmsg.o
 
 # i.MX Machine Support
 snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c
new file mode 100644
index 000000000000..f05d5d489560
--- /dev/null
+++ b/sound/soc/fsl/imx-pcm-rpmsg.c
@@ -0,0 +1,919 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright 2017-2021 NXP
+
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/rpmsg.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/soc.h>
+
+#include "imx-pcm.h"
+#include "fsl_rpmsg.h"
+#include "imx-pcm-rpmsg.h"
+
+static struct snd_pcm_hardware imx_rpmsg_pcm_hardware = {
+	.info = SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		SNDRV_PCM_INFO_MMAP |
+		SNDRV_PCM_INFO_MMAP_VALID |
+		SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
+		SNDRV_PCM_INFO_PAUSE |
+		SNDRV_PCM_INFO_RESUME,
+	.buffer_bytes_max = IMX_DEFAULT_DMABUF_SIZE,
+	.period_bytes_min = 512,
+	.period_bytes_max = 65536,
+	.periods_min = 2,
+	.periods_max = 6000,
+	.fifo_size = 0,
+};
+
+static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg,
+				      struct rpmsg_info *info)
+{
+	struct rpmsg_device *rpdev = info->rpdev;
+	int ret = 0;
+
+	mutex_lock(&info->msg_lock);
+	if (!rpdev) {
+		dev_err(info->dev, "rpmsg channel not ready\n");
+		mutex_unlock(&info->msg_lock);
+		return -EINVAL;
+	}
+
+	dev_dbg(&rpdev->dev, "send cmd %d\n", msg->s_msg.header.cmd);
+
+	if (!(msg->s_msg.header.type == MSG_TYPE_C))
+		reinit_completion(&info->cmd_complete);
+
+	ret = rpmsg_send(rpdev->ept, (void *)&msg->s_msg,
+			 sizeof(struct rpmsg_s_msg));
+	if (ret) {
+		dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
+		mutex_unlock(&info->msg_lock);
+		return ret;
+	}
+
+	/* No receive msg for TYPE_C command */
+	if (msg->s_msg.header.type == MSG_TYPE_C) {
+		mutex_unlock(&info->msg_lock);
+		return 0;
+	}
+
+	/* wait response from rpmsg */
+	ret = wait_for_completion_timeout(&info->cmd_complete,
+					  msecs_to_jiffies(RPMSG_TIMEOUT));
+	if (!ret) {
+		dev_err(&rpdev->dev, "rpmsg_send cmd %d timeout!\n",
+			msg->s_msg.header.cmd);
+		mutex_unlock(&info->msg_lock);
+		return -ETIMEDOUT;
+	}
+
+	memcpy(&msg->r_msg, &info->r_msg, sizeof(struct rpmsg_r_msg));
+	memcpy(&info->msg[msg->r_msg.header.cmd].r_msg,
+	       &msg->r_msg, sizeof(struct rpmsg_r_msg));
+
+	/*
+	 * Reset the buffer pointer to be zero, actully we have
+	 * set the buffer pointer to be zero in imx_rpmsg_terminate_all
+	 * But if there is timer task queued in queue, after it is
+	 * executed the buffer pointer will be changed, so need to
+	 * reset it again with TERMINATE command.
+	 */
+	switch (msg->s_msg.header.cmd) {
+	case TX_TERMINATE:
+		info->msg[TX_POINTER].r_msg.param.buffer_offset = 0;
+		break;
+	case RX_TERMINATE:
+		info->msg[RX_POINTER].r_msg.param.buffer_offset = 0;
+		break;
+	default:
+		break;
+	}
+
+	dev_dbg(&rpdev->dev, "cmd:%d, resp %d\n", msg->s_msg.header.cmd,
+		info->r_msg.param.resp);
+
+	mutex_unlock(&info->msg_lock);
+
+	return 0;
+}
+
+static int imx_rpmsg_insert_workqueue(struct snd_pcm_substream *substream,
+				      struct rpmsg_msg *msg,
+				      struct rpmsg_info *info)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	/*
+	 * Queue the work to workqueue.
+	 * If the queue is full, drop the message.
+	 */
+	spin_lock_irqsave(&info->wq_lock, flags);
+	if (info->work_write_index != info->work_read_index) {
+		int index = info->work_write_index;
+
+		memcpy(&info->work_list[index].msg, msg,
+		       sizeof(struct rpmsg_s_msg));
+
+		queue_work(info->rpmsg_wq, &info->work_list[index].work);
+		info->work_write_index++;
+		info->work_write_index %= WORK_MAX_NUM;
+	} else {
+		info->msg_drop_count[substream->stream]++;
+		ret = -EPIPE;
+	}
+	spin_unlock_irqrestore(&info->wq_lock, flags);
+
+	return ret;
+}
+
+static int imx_rpmsg_pcm_hw_params(struct snd_soc_component *component,
+				   struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params)
+{
+	struct rpmsg_info *info = dev_get_drvdata(component->dev);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct rpmsg_msg *msg;
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		msg = &info->msg[TX_HW_PARAM];
+		msg->s_msg.header.cmd = TX_HW_PARAM;
+	} else {
+		msg = &info->msg[RX_HW_PARAM];
+		msg->s_msg.header.cmd = RX_HW_PARAM;
+	}
+
+	msg->s_msg.param.rate = params_rate(params);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		msg->s_msg.param.format   = RPMSG_S16_LE;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		msg->s_msg.param.format   = RPMSG_S24_LE;
+		break;
+	case SNDRV_PCM_FORMAT_DSD_U16_LE:
+		msg->s_msg.param.format   = SNDRV_PCM_FORMAT_DSD_U16_LE;
+		break;
+	case SNDRV_PCM_FORMAT_DSD_U32_LE:
+		msg->s_msg.param.format   = SNDRV_PCM_FORMAT_DSD_U32_LE;
+		break;
+	default:
+		msg->s_msg.param.format   = RPMSG_S32_LE;
+		break;
+	}
+
+	switch (params_channels(params)) {
+	case 1:
+		msg->s_msg.param.channels = RPMSG_CH_LEFT;
+		break;
+	case 2:
+		msg->s_msg.param.channels = RPMSG_CH_STEREO;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	runtime->dma_bytes = params_buffer_bytes(params);
+
+	info->send_message(msg, info);
+
+	return ret;
+}
+
+static int imx_rpmsg_pcm_hw_free(struct snd_soc_component *component,
+				 struct snd_pcm_substream *substream)
+{
+	snd_pcm_set_runtime_buffer(substream, NULL);
+	return 0;
+}
+
+static snd_pcm_uframes_t imx_rpmsg_pcm_pointer(struct snd_soc_component *component,
+					       struct snd_pcm_substream *substream)
+{
+	struct rpmsg_info *info = dev_get_drvdata(component->dev);
+	struct rpmsg_msg *msg;
+	unsigned int pos = 0;
+	int buffer_tail = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
+	else
+		msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
+
+	buffer_tail = msg->r_msg.param.buffer_tail;
+	pos = buffer_tail * snd_pcm_lib_period_bytes(substream);
+
+	return bytes_to_frames(substream->runtime, pos);
+}
+
+static void imx_rpmsg_timer_callback(struct timer_list *t)
+{
+	struct stream_timer  *stream_timer =
+			from_timer(stream_timer, t, timer);
+	struct snd_pcm_substream *substream = stream_timer->substream;
+	struct rpmsg_info *info = stream_timer->info;
+	struct rpmsg_msg *msg;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
+		msg->s_msg.header.cmd = TX_PERIOD_DONE;
+	} else {
+		msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
+		msg->s_msg.header.cmd = RX_PERIOD_DONE;
+	}
+
+	imx_rpmsg_insert_workqueue(substream, msg, info);
+}
+
+static int imx_rpmsg_pcm_open(struct snd_soc_component *component,
+			      struct snd_pcm_substream *substream)
+{
+	struct rpmsg_info *info = dev_get_drvdata(component->dev);
+	struct rpmsg_msg *msg;
+	int ret = 0;
+	int cmd;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		msg = &info->msg[TX_OPEN];
+		msg->s_msg.header.cmd = TX_OPEN;
+
+		/* reinitialize buffer counter*/
+		cmd = TX_PERIOD_DONE + MSG_TYPE_A_NUM;
+		info->msg[cmd].s_msg.param.buffer_tail = 0;
+		info->msg[cmd].r_msg.param.buffer_tail = 0;
+		info->msg[TX_POINTER].r_msg.param.buffer_offset = 0;
+
+	} else {
+		msg = &info->msg[RX_OPEN];
+		msg->s_msg.header.cmd = RX_OPEN;
+
+		/* reinitialize buffer counter*/
+		cmd = RX_PERIOD_DONE + MSG_TYPE_A_NUM;
+		info->msg[cmd].s_msg.param.buffer_tail = 0;
+		info->msg[cmd].r_msg.param.buffer_tail = 0;
+		info->msg[RX_POINTER].r_msg.param.buffer_offset = 0;
+	}
+
+	info->send_message(msg, info);
+
+	imx_rpmsg_pcm_hardware.period_bytes_max =
+			imx_rpmsg_pcm_hardware.buffer_bytes_max / 2;
+
+	snd_soc_set_runtime_hwparams(substream, &imx_rpmsg_pcm_hardware);
+
+	ret = snd_pcm_hw_constraint_integer(substream->runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		return ret;
+
+	info->msg_drop_count[substream->stream] = 0;
+
+	/* Create timer*/
+	info->stream_timer[substream->stream].info = info;
+	info->stream_timer[substream->stream].substream = substream;
+	timer_setup(&info->stream_timer[substream->stream].timer,
+		    imx_rpmsg_timer_callback, 0);
+	return ret;
+}
+
+static int imx_rpmsg_pcm_close(struct snd_soc_component *component,
+			       struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+	struct rpmsg_info *info = dev_get_drvdata(component->dev);
+	struct rpmsg_msg *msg;
+	int ret = 0;
+
+	/* Flush work in workqueue to make TX_CLOSE is the last message */
+	flush_workqueue(info->rpmsg_wq);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		msg = &info->msg[TX_CLOSE];
+		msg->s_msg.header.cmd = TX_CLOSE;
+	} else {
+		msg = &info->msg[RX_CLOSE];
+		msg->s_msg.header.cmd = RX_CLOSE;
+	}
+
+	info->send_message(msg, info);
+
+	del_timer(&info->stream_timer[substream->stream].timer);
+
+	rtd->dai_link->ignore_suspend = 0;
+
+	if (info->msg_drop_count[substream->stream])
+		dev_warn(rtd->dev, "Msg is dropped!, number is %d\n",
+			 info->msg_drop_count[substream->stream]);
+
+	return ret;
+}
+
+static int imx_rpmsg_pcm_prepare(struct snd_soc_component *component,
+				 struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+	struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
+
+	/*
+	 * NON-MMAP mode, NONBLOCK, Version 2, enable lpa in dts
+	 * four conditions to determine the lpa is enabled.
+	 */
+	if ((runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED ||
+	     runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) &&
+	     rpmsg->version == API_VERSION_V2 &&
+	     rpmsg->enable_lpa) {
+		/*
+		 * Ignore suspend operation in low power mode
+		 * M core will continue playback music on A core suspend.
+		 */
+		rtd->dai_link->ignore_suspend = 1;
+		rpmsg->force_lpa = 1;
+	} else {
+		rpmsg->force_lpa = 0;
+	}
+
+	return 0;
+}
+
+static int imx_rpmsg_pcm_mmap(struct snd_soc_component *component,
+			      struct snd_pcm_substream *substream,
+			      struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	return dma_mmap_wc(substream->pcm->card->dev, vma,
+			   runtime->dma_area,
+			   runtime->dma_addr,
+			   runtime->dma_bytes);
+}
+
+static void imx_rpmsg_pcm_dma_complete(void *arg)
+{
+	struct snd_pcm_substream *substream = arg;
+
+	snd_pcm_period_elapsed(substream);
+}
+
+static int imx_rpmsg_prepare_and_submit(struct snd_soc_component *component,
+					struct snd_pcm_substream *substream)
+{
+	struct rpmsg_info *info = dev_get_drvdata(component->dev);
+	struct rpmsg_msg *msg;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		msg = &info->msg[TX_BUFFER];
+		msg->s_msg.header.cmd = TX_BUFFER;
+	} else {
+		msg = &info->msg[RX_BUFFER];
+		msg->s_msg.header.cmd = RX_BUFFER;
+	}
+
+	/* Send buffer address and buffer size */
+	msg->s_msg.param.buffer_addr = substream->runtime->dma_addr;
+	msg->s_msg.param.buffer_size = snd_pcm_lib_buffer_bytes(substream);
+	msg->s_msg.param.period_size = snd_pcm_lib_period_bytes(substream);
+	msg->s_msg.param.buffer_tail = 0;
+
+	info->num_period[substream->stream] = msg->s_msg.param.buffer_size /
+					      msg->s_msg.param.period_size;
+
+	info->callback[substream->stream] = imx_rpmsg_pcm_dma_complete;
+	info->callback_param[substream->stream] = substream;
+
+	return imx_rpmsg_insert_workqueue(substream, msg, info);
+}
+
+static int imx_rpmsg_async_issue_pending(struct snd_soc_component *component,
+					 struct snd_pcm_substream *substream)
+{
+	struct rpmsg_info *info = dev_get_drvdata(component->dev);
+	struct rpmsg_msg *msg;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		msg = &info->msg[TX_START];
+		msg->s_msg.header.cmd = TX_START;
+	} else {
+		msg = &info->msg[RX_START];
+		msg->s_msg.header.cmd = RX_START;
+	}
+
+	return imx_rpmsg_insert_workqueue(substream, msg, info);
+}
+
+static int imx_rpmsg_restart(struct snd_soc_component *component,
+			     struct snd_pcm_substream *substream)
+{
+	struct rpmsg_info *info = dev_get_drvdata(component->dev);
+	struct rpmsg_msg *msg;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		msg = &info->msg[TX_RESTART];
+		msg->s_msg.header.cmd = TX_RESTART;
+	} else {
+		msg = &info->msg[RX_RESTART];
+		msg->s_msg.header.cmd = RX_RESTART;
+	}
+
+	return imx_rpmsg_insert_workqueue(substream, msg, info);
+}
+
+static int imx_rpmsg_pause(struct snd_soc_component *component,
+			   struct snd_pcm_substream *substream)
+{
+	struct rpmsg_info *info = dev_get_drvdata(component->dev);
+	struct rpmsg_msg *msg;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		msg = &info->msg[TX_PAUSE];
+		msg->s_msg.header.cmd = TX_PAUSE;
+	} else {
+		msg = &info->msg[RX_PAUSE];
+		msg->s_msg.header.cmd = RX_PAUSE;
+	}
+
+	return imx_rpmsg_insert_workqueue(substream, msg, info);
+}
+
+static int imx_rpmsg_terminate_all(struct snd_soc_component *component,
+				   struct snd_pcm_substream *substream)
+{
+	struct rpmsg_info *info = dev_get_drvdata(component->dev);
+	struct rpmsg_msg *msg;
+	int cmd;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		msg = &info->msg[TX_TERMINATE];
+		msg->s_msg.header.cmd = TX_TERMINATE;
+		/* Clear buffer count*/
+		cmd = TX_PERIOD_DONE + MSG_TYPE_A_NUM;
+		info->msg[cmd].s_msg.param.buffer_tail = 0;
+		info->msg[cmd].r_msg.param.buffer_tail = 0;
+		info->msg[TX_POINTER].r_msg.param.buffer_offset = 0;
+	} else {
+		msg = &info->msg[RX_TERMINATE];
+		msg->s_msg.header.cmd = RX_TERMINATE;
+		/* Clear buffer count*/
+		cmd = RX_PERIOD_DONE + MSG_TYPE_A_NUM;
+		info->msg[cmd].s_msg.param.buffer_tail = 0;
+		info->msg[cmd].r_msg.param.buffer_tail = 0;
+		info->msg[RX_POINTER].r_msg.param.buffer_offset = 0;
+	}
+
+	del_timer(&info->stream_timer[substream->stream].timer);
+
+	return imx_rpmsg_insert_workqueue(substream, msg, info);
+}
+
+static int imx_rpmsg_pcm_trigger(struct snd_soc_component *component,
+				 struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+	struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		ret = imx_rpmsg_prepare_and_submit(component, substream);
+		if (ret)
+			return ret;
+		ret = imx_rpmsg_async_issue_pending(component, substream);
+		break;
+	case SNDRV_PCM_TRIGGER_RESUME:
+		if (rpmsg->force_lpa)
+			break;
+		fallthrough;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		ret = imx_rpmsg_restart(component, substream);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		if (!rpmsg->force_lpa) {
+			if (runtime->info & SNDRV_PCM_INFO_PAUSE)
+				ret = imx_rpmsg_pause(component, substream);
+			else
+				ret = imx_rpmsg_terminate_all(component, substream);
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		ret = imx_rpmsg_pause(component, substream);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		ret = imx_rpmsg_terminate_all(component, substream);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+/*
+ * imx_rpmsg_pcm_ack
+ *
+ * Send the period index to M core through rpmsg, but not send
+ * all the period index to M core, reduce some unnessesary msg
+ * to reduce the pressure of rpmsg bandwidth.
+ */
+static int imx_rpmsg_pcm_ack(struct snd_soc_component *component,
+			     struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+	struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
+	struct rpmsg_info *info = dev_get_drvdata(component->dev);
+	snd_pcm_uframes_t period_size = runtime->period_size;
+	snd_pcm_sframes_t avail;
+	struct timer_list *timer;
+	struct rpmsg_msg *msg;
+	unsigned long flags;
+	int buffer_tail = 0;
+	int written_num = 0;
+
+	if (!rpmsg->force_lpa)
+		return 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
+		msg->s_msg.header.cmd = TX_PERIOD_DONE;
+	} else {
+		msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
+		msg->s_msg.header.cmd = RX_PERIOD_DONE;
+	}
+
+	msg->s_msg.header.type = MSG_TYPE_C;
+
+	buffer_tail = (frames_to_bytes(runtime, runtime->control->appl_ptr) %
+		       snd_pcm_lib_buffer_bytes(substream));
+	buffer_tail = buffer_tail / snd_pcm_lib_period_bytes(substream);
+
+	/* There is update for period index */
+	if (buffer_tail != msg->s_msg.param.buffer_tail) {
+		written_num = buffer_tail - msg->s_msg.param.buffer_tail;
+		if (written_num < 0)
+			written_num += runtime->periods;
+
+		msg->s_msg.param.buffer_tail = buffer_tail;
+
+		/* The notification message is updated to latest */
+		spin_lock_irqsave(&info->lock[substream->stream], flags);
+		memcpy(&info->notify[substream->stream], msg,
+		       sizeof(struct rpmsg_s_msg));
+		info->notify_updated[substream->stream] = true;
+		spin_unlock_irqrestore(&info->lock[substream->stream], flags);
+
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			avail = snd_pcm_playback_hw_avail(runtime);
+		else
+			avail = snd_pcm_capture_hw_avail(runtime);
+
+		timer = &info->stream_timer[substream->stream].timer;
+		/*
+		 * If the data in the buffer is less than one period before
+		 * this fill, which means the data may not enough on M
+		 * core side, we need to send message immediately to let
+		 * M core know the pointer is updated.
+		 * if there is more than one period data in the buffer before
+		 * this fill, which means the data is enough on M core side,
+		 * we can delay one period (using timer) to send the message
+		 * for reduce the message number in workqueue, because the
+		 * pointer may be updated by ack function later, we can
+		 * send latest pointer to M core side.
+		 */
+		if ((avail - written_num * period_size) <= period_size) {
+			imx_rpmsg_insert_workqueue(substream, msg, info);
+		} else if (rpmsg->force_lpa && !timer_pending(timer)) {
+			int time_msec;
+
+			time_msec = (int)(runtime->period_size * 1000 / runtime->rate);
+			mod_timer(timer, jiffies + msecs_to_jiffies(time_msec));
+		}
+	}
+
+	return 0;
+}
+
+static int imx_rpmsg_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
+						int stream, int size)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+	buf->area = dma_alloc_wc(pcm->card->dev, size,
+				 &buf->addr, GFP_KERNEL);
+	if (!buf->area)
+		return -ENOMEM;
+
+	buf->bytes = size;
+	return 0;
+}
+
+static void imx_rpmsg_pcm_free_dma_buffers(struct snd_soc_component *component,
+					   struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = SNDRV_PCM_STREAM_PLAYBACK;
+	     stream < SNDRV_PCM_STREAM_LAST; stream++) {
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+
+		dma_free_wc(pcm->card->dev, buf->bytes,
+			    buf->area, buf->addr);
+		buf->area = NULL;
+	}
+}
+
+static int imx_rpmsg_pcm_new(struct snd_soc_component *component,
+			     struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	struct snd_pcm *pcm = rtd->pcm;
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+	struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
+	int ret;
+
+	ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+	if (ret)
+		return ret;
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+		ret = imx_rpmsg_pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+							   rpmsg->buffer_size);
+		if (ret)
+			goto out;
+	}
+
+	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+		ret = imx_rpmsg_pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE,
+							   rpmsg->buffer_size);
+		if (ret)
+			goto out;
+	}
+
+	imx_rpmsg_pcm_hardware.buffer_bytes_max = rpmsg->buffer_size;
+out:
+	/* free preallocated buffers in case of error */
+	if (ret)
+		imx_rpmsg_pcm_free_dma_buffers(component, pcm);
+
+	return ret;
+}
+
+static const struct snd_soc_component_driver imx_rpmsg_soc_component = {
+	.name		= IMX_PCM_DRV_NAME,
+	.pcm_construct	= imx_rpmsg_pcm_new,
+	.pcm_destruct	= imx_rpmsg_pcm_free_dma_buffers,
+	.open		= imx_rpmsg_pcm_open,
+	.close		= imx_rpmsg_pcm_close,
+	.hw_params	= imx_rpmsg_pcm_hw_params,
+	.hw_free	= imx_rpmsg_pcm_hw_free,
+	.trigger	= imx_rpmsg_pcm_trigger,
+	.pointer	= imx_rpmsg_pcm_pointer,
+	.mmap		= imx_rpmsg_pcm_mmap,
+	.ack		= imx_rpmsg_pcm_ack,
+	.prepare	= imx_rpmsg_pcm_prepare,
+};
+
+static void imx_rpmsg_pcm_work(struct work_struct *work)
+{
+	struct work_of_rpmsg *work_of_rpmsg;
+	bool is_notification = false;
+	struct rpmsg_info *info;
+	struct rpmsg_msg msg;
+	unsigned long flags;
+
+	work_of_rpmsg = container_of(work, struct work_of_rpmsg, work);
+	info = work_of_rpmsg->info;
+
+	/*
+	 * Every work in the work queue, first we check if there
+	 * is update for period is filled, because there may be not
+	 * enough data in M core side, need to let M core know
+	 * data is updated immediately.
+	 */
+	spin_lock_irqsave(&info->lock[TX], flags);
+	if (info->notify_updated[TX]) {
+		memcpy(&msg, &info->notify[TX], sizeof(struct rpmsg_s_msg));
+		info->notify_updated[TX] = false;
+		spin_unlock_irqrestore(&info->lock[TX], flags);
+		info->send_message(&msg, info);
+	} else {
+		spin_unlock_irqrestore(&info->lock[TX], flags);
+	}
+
+	spin_lock_irqsave(&info->lock[RX], flags);
+	if (info->notify_updated[RX]) {
+		memcpy(&msg, &info->notify[RX], sizeof(struct rpmsg_s_msg));
+		info->notify_updated[RX] = false;
+		spin_unlock_irqrestore(&info->lock[RX], flags);
+		info->send_message(&msg, info);
+	} else {
+		spin_unlock_irqrestore(&info->lock[RX], flags);
+	}
+
+	/* Skip the notification message for it has been processed above */
+	if (work_of_rpmsg->msg.s_msg.header.type == MSG_TYPE_C &&
+	    (work_of_rpmsg->msg.s_msg.header.cmd == TX_PERIOD_DONE ||
+	     work_of_rpmsg->msg.s_msg.header.cmd == RX_PERIOD_DONE))
+		is_notification = true;
+
+	if (!is_notification)
+		info->send_message(&work_of_rpmsg->msg, info);
+
+	/* update read index */
+	spin_lock_irqsave(&info->wq_lock, flags);
+	info->work_read_index++;
+	info->work_read_index %= WORK_MAX_NUM;
+	spin_unlock_irqrestore(&info->wq_lock, flags);
+}
+
+static int imx_rpmsg_pcm_probe(struct platform_device *pdev)
+{
+	struct snd_soc_component *component;
+	struct rpmsg_info *info;
+	int ret, i;
+
+	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, info);
+
+	info->rpdev = container_of(pdev->dev.parent, struct rpmsg_device, dev);
+	info->dev = &pdev->dev;
+	/* Setup work queue */
+	info->rpmsg_wq = alloc_ordered_workqueue("rpmsg_audio",
+						 WQ_HIGHPRI |
+						 WQ_UNBOUND |
+						 WQ_FREEZABLE);
+	if (!info->rpmsg_wq) {
+		dev_err(&pdev->dev, "workqueue create failed\n");
+		return -ENOMEM;
+	}
+
+	/* Write index initialize 1, make it differ with the read index */
+	info->work_write_index = 1;
+	info->send_message = imx_rpmsg_pcm_send_message;
+
+	for (i = 0; i < WORK_MAX_NUM; i++) {
+		INIT_WORK(&info->work_list[i].work, imx_rpmsg_pcm_work);
+		info->work_list[i].info = info;
+	}
+
+	/* Initialize msg */
+	for (i = 0; i < MSG_MAX_NUM; i++) {
+		info->msg[i].s_msg.header.cate  = IMX_RPMSG_AUDIO;
+		info->msg[i].s_msg.header.major = IMX_RMPSG_MAJOR;
+		info->msg[i].s_msg.header.minor = IMX_RMPSG_MINOR;
+		info->msg[i].s_msg.header.type  = MSG_TYPE_A;
+		info->msg[i].s_msg.param.audioindex = 0;
+	}
+
+	init_completion(&info->cmd_complete);
+	mutex_init(&info->msg_lock);
+	spin_lock_init(&info->lock[TX]);
+	spin_lock_init(&info->lock[RX]);
+	spin_lock_init(&info->wq_lock);
+
+	ret = devm_snd_soc_register_component(&pdev->dev,
+					      &imx_rpmsg_soc_component,
+					      NULL, 0);
+	if (ret)
+		goto fail;
+
+	component = snd_soc_lookup_component(&pdev->dev, IMX_PCM_DRV_NAME);
+	if (!component) {
+		ret = -EINVAL;
+		goto fail;
+	}
+#ifdef CONFIG_DEBUG_FS
+	component->debugfs_prefix = "rpmsg";
+#endif
+
+	return 0;
+
+fail:
+	if (info->rpmsg_wq)
+		destroy_workqueue(info->rpmsg_wq);
+
+	return ret;
+}
+
+static int imx_rpmsg_pcm_remove(struct platform_device *pdev)
+{
+	struct rpmsg_info *info = platform_get_drvdata(pdev);
+
+	if (info->rpmsg_wq)
+		destroy_workqueue(info->rpmsg_wq);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int imx_rpmsg_pcm_runtime_resume(struct device *dev)
+{
+	struct rpmsg_info *info = dev_get_drvdata(dev);
+
+	cpu_latency_qos_add_request(&info->pm_qos_req, 0);
+
+	return 0;
+}
+
+static int imx_rpmsg_pcm_runtime_suspend(struct device *dev)
+{
+	struct rpmsg_info *info = dev_get_drvdata(dev);
+
+	cpu_latency_qos_remove_request(&info->pm_qos_req);
+
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int imx_rpmsg_pcm_suspend(struct device *dev)
+{
+	struct rpmsg_info *info = dev_get_drvdata(dev);
+	struct rpmsg_msg *rpmsg_tx;
+	struct rpmsg_msg *rpmsg_rx;
+
+	rpmsg_tx = &info->msg[TX_SUSPEND];
+	rpmsg_rx = &info->msg[RX_SUSPEND];
+
+	rpmsg_tx->s_msg.header.cmd = TX_SUSPEND;
+	info->send_message(rpmsg_tx, info);
+
+	rpmsg_rx->s_msg.header.cmd = RX_SUSPEND;
+	info->send_message(rpmsg_rx, info);
+
+	return 0;
+}
+
+static int imx_rpmsg_pcm_resume(struct device *dev)
+{
+	struct rpmsg_info *info = dev_get_drvdata(dev);
+	struct rpmsg_msg *rpmsg_tx;
+	struct rpmsg_msg *rpmsg_rx;
+
+	rpmsg_tx = &info->msg[TX_RESUME];
+	rpmsg_rx = &info->msg[RX_RESUME];
+
+	rpmsg_tx->s_msg.header.cmd = TX_RESUME;
+	info->send_message(rpmsg_tx, info);
+
+	rpmsg_rx->s_msg.header.cmd = RX_RESUME;
+	info->send_message(rpmsg_rx, info);
+
+	return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops imx_rpmsg_pcm_pm_ops = {
+	SET_RUNTIME_PM_OPS(imx_rpmsg_pcm_runtime_suspend,
+			   imx_rpmsg_pcm_runtime_resume,
+			   NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(imx_rpmsg_pcm_suspend,
+				imx_rpmsg_pcm_resume)
+};
+
+static struct platform_driver imx_pcm_rpmsg_driver = {
+	.probe  = imx_rpmsg_pcm_probe,
+	.remove	= imx_rpmsg_pcm_remove,
+	.driver = {
+		.name = IMX_PCM_DRV_NAME,
+		.pm = &imx_rpmsg_pcm_pm_ops,
+	},
+};
+module_platform_driver(imx_pcm_rpmsg_driver);
+
+MODULE_DESCRIPTION("Freescale SoC Audio RPMSG PCM interface");
+MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
+MODULE_ALIAS("platform:" IMX_PCM_DRV_NAME);
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/imx-pcm-rpmsg.h b/sound/soc/fsl/imx-pcm-rpmsg.h
new file mode 100644
index 000000000000..308d153920a3
--- /dev/null
+++ b/sound/soc/fsl/imx-pcm-rpmsg.h
@@ -0,0 +1,512 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2017-2021  NXP
+ *
+ ******************************************************************************
+ * Communication stack of audio with rpmsg
+ ******************************************************************************
+ * Packet structure:
+ *   A SRTM message consists of a 10 bytes header followed by 0~N bytes of data
+ *
+ *   +---------------+-------------------------------+
+ *   |               |            Content            |
+ *   +---------------+-------------------------------+
+ *   |  Byte Offset  | 7   6   5   4   3   2   1   0 |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |       0       |           Category            |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |     1 ~ 2     |           Version             |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |       3       |             Type              |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |       4       |           Command             |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |       5       |           Reserved0           |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |       6       |           Reserved1           |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |       7       |           Reserved2           |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |       8       |           Reserved3           |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |       9       |           Reserved4           |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |       10      |            DATA 0             |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   :   :   :   :   :   :   :   :   :   :   :   :   :
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *   |   N + 10 - 1  |            DATA N-1           |
+ *   +---------------+---+---+---+---+---+---+---+---+
+ *
+ *   +----------+------------+------------------------------------------------+
+ *   |  Field   |    Byte    |                                                |
+ *   +----------+------------+------------------------------------------------+
+ *   | Category |     0      | The destination category.                      |
+ *   +----------+------------+------------------------------------------------+
+ *   | Version  |   1 ~ 2    | The category version of the sender of the      |
+ *   |          |            | packet.                                        |
+ *   |          |            | The first byte represent the major version of  |
+ *   |          |            | the packet.The second byte represent the minor |
+ *   |          |            | version of the packet.                         |
+ *   +----------+------------+------------------------------------------------+
+ *   |  Type    |     3      | The message type of current message packet.    |
+ *   +----------+------------+------------------------------------------------+
+ *   | Command  |     4      | The command byte sent to remote processor/SoC. |
+ *   +----------+------------+------------------------------------------------+
+ *   | Reserved |   5 ~ 9    | Reserved field for future extension.           |
+ *   +----------+------------+------------------------------------------------+
+ *   | Data     |     N      | The data payload of the message packet.        |
+ *   +----------+------------+------------------------------------------------+
+ *
+ * Audio control:
+ *   SRTM Audio Control Category Request Command Table:
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   | Category | Version | Type | Command | Data                          | Function              |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x00 |  0x00   | Data[0]: Audio Device Index   | Open a TX Instance.   |
+ *   |          |         |      |         | Data[1]:     format           |                       |
+ *   |          |         |      |         | Data[2]:     channels         |                       |
+ *   |          |         |      |         | Data[3-6]:   samplerate       |                       |
+ *   |          |         |      |         | Data[7-10]:  buffer_addr      |                       |
+ *   |          |         |      |         | Data[11-14]: buffer_size      |                       |
+ *   |          |         |      |         | Data[15-18]: period_size      |                       |
+ *   |          |         |      |         | Data[19-22]: buffer_tail      |                       |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x00 |  0x01   | Data[0]: Audio Device Index   | Start a TX Instance.  |
+ *   |          |         |      |         | Same as above command         |                       |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x00 |  0x02   | Data[0]: Audio Device Index   | Pause a TX Instance.  |
+ *   |          |         |      |         | Same as above command         |                       |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x00 |  0x03   | Data[0]: Audio Device Index   | Resume a TX Instance. |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x00 |  0x04   | Data[0]: Audio Device Index   | Stop a TX Instance.   |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x00 |  0x05   | Data[0]: Audio Device Index   | Close a TX Instance.  |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x00 |  0x06   | Data[0]: Audio Device Index   | Set Parameters for    |
+ *   |          |         |      |         | Data[1]:     format           | a TX Instance.        |
+ *   |          |         |      |         | Data[2]:     channels         |                       |
+ *   |          |         |      |         | Data[3-6]:   samplerate       |                       |
+ *   |          |         |      |         | Data[7-22]:  reserved         |                       |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x00 |  0x07   | Data[0]: Audio Device Index   | Set TX Buffer.        |
+ *   |          |         |      |         | Data[1-6]:   reserved         |                       |
+ *   |          |         |      |         | Data[7-10]:  buffer_addr      |                       |
+ *   |          |         |      |         | Data[11-14]: buffer_size      |                       |
+ *   |          |         |      |         | Data[15-18]: period_size      |                       |
+ *   |          |         |      |         | Data[19-22]: buffer_tail      |                       |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x00 |  0x08   | Data[0]: Audio Device Index   | Suspend a TX Instance |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x00 |  0x09   | Data[0]: Audio Device Index   | Resume a TX Instance. |
+ *   |          |         |      |         | Data[1]:     format           |                       |
+ *   |          |         |      |         | Data[2]:     channels         |                       |
+ *   |          |         |      |         | Data[3-6]:   samplerate       |                       |
+ *   |          |         |      |         | Data[7-10]:  buffer_addr      |                       |
+ *   |          |         |      |         | Data[11-14]: buffer_size      |                       |
+ *   |          |         |      |         | Data[15-18]: period_size      |                       |
+ *   |          |         |      |         | Data[19-22]: buffer_tail      |                       |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x00 |  0x0A   | Data[0]: Audio Device Index   | Open a RX Instance.   |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x00 |  0x0B   | Data[0]: Audio Device Index   | Start a RX Instance.  |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x00 |  0x0C   | Data[0]: Audio Device Index   | Pause a RX Instance.  |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x00 |  0x0D   | Data[0]: Audio Device Index   | Resume a RX Instance. |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x00 |  0x0E   | Data[0]: Audio Device Index   | Stop a RX Instance.   |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x00 |  0x0F   | Data[0]: Audio Device Index   | Close a RX Instance.  |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x00 |  0x10   | Data[0]: Audio Device Index   | Set Parameters for    |
+ *   |          |         |      |         | Data[1]:     format           | a RX Instance.        |
+ *   |          |         |      |         | Data[2]:     channels         |                       |
+ *   |          |         |      |         | Data[3-6]:   samplerate       |                       |
+ *   |          |         |      |         | Data[7-22]:  reserved         |                       |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x00 |  0x11   | Data[0]: Audio Device Index   | Set RX Buffer.        |
+ *   |          |         |      |         | Data[1-6]:   reserved         |                       |
+ *   |          |         |      |         | Data[7-10]:  buffer_addr      |                       |
+ *   |          |         |      |         | Data[11-14]: buffer_size      |                       |
+ *   |          |         |      |         | Data[15-18]: period_size      |                       |
+ *   |          |         |      |         | Data[19-22]: buffer_tail      |                       |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x00 |  0x12   | Data[0]: Audio Device Index   | Suspend a RX Instance.|
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x00 |  0x13   | Data[0]: Audio Device Index   | Resume a RX Instance. |
+ *   |          |         |      |         | Data[1]:     format           |                       |
+ *   |          |         |      |         | Data[2]:     channels         |                       |
+ *   |          |         |      |         | Data[3-6]:   samplerate       |                       |
+ *   |          |         |      |         | Data[7-10]:  buffer_addr      |                       |
+ *   |          |         |      |         | Data[11-14]: buffer_size      |                       |
+ *   |          |         |      |         | Data[15-18]: period_size      |                       |
+ *   |          |         |      |         | Data[19-22]: buffer_tail      |                       |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x00 |  0x14   | Data[0]: Audio Device Index   | Set register value    |
+ *   |          |         |      |         | Data[1-6]:   reserved         | to codec              |
+ *   |          |         |      |         | Data[7-10]:  register         |                       |
+ *   |          |         |      |         | Data[11-14]: value            |                       |
+ *   |          |         |      |         | Data[15-22]: reserved         |                       |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x00 |  0x15   | Data[0]: Audio Device Index   | Get register value    |
+ *   |          |         |      |         | Data[1-6]:   reserved         | from codec            |
+ *   |          |         |      |         | Data[7-10]:  register         |                       |
+ *   |          |         |      |         | Data[11-22]: reserved         |                       |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   Note 1: See <List of Sample Format> for available value of
+ *           Sample Format;
+ *   Note 2: See <List of Audio Channels> for available value of Channels;
+ *   Note 3: Sample Rate of Set Parameters for an Audio TX Instance
+ *           Command and Set Parameters for an Audio RX Instance Command is
+ *           in little-endian format.
+ *
+ *   SRTM Audio Control Category Response Command Table:
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   | Category | Version | Type | Command | Data                          | Function              |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x01 |  0x00   | Data[0]: Audio Device Index   | Reply for Open        |
+ *   |          |         |      |         | Data[1]: Return code          | a TX Instance         |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x01 |  0x01   | Data[0]: Audio Device Index   | Reply for Start       |
+ *   |          |         |      |         | Data[1]: Return code          | a TX Instance         |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x01 |  0x02   | Data[0]: Audio Device Index   | Reply for Pause       |
+ *   |          |         |      |         | Data[1]: Return code          | a TX Instance         |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x01 |  0x03   | Data[0]: Audio Device Index   | Reply for Resume      |
+ *   |          |         |      |         | Data[1]: Return code          | a TX Instance         |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x01 |  0x04   | Data[0]: Audio Device Index   | Reply for Stop        |
+ *   |          |         |      |         | Data[1]: Return code          | a TX Instance         |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x01 |  0x05   | Data[0]: Audio Device Index   | Reply for Close       |
+ *   |          |         |      |         | Data[1]: Return code          | a TX Instance         |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x01 |  0x06   | Data[0]: Audio Device Index   | Reply for Set Param   |
+ *   |          |         |      |         | Data[1]: Return code          | for a TX Instance.    |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x01 |  0x07   | Data[0]: Audio Device Index   | Reply for Set         |
+ *   |          |         |      |         | Data[1]: Return code          | TX Buffer             |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x01 |  0x08   | Data[0]: Audio Device Index   | Reply for Suspend     |
+ *   |          |         |      |         | Data[1]: Return code          | a TX Instance         |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x01 |  0x09   | Data[0]: Audio Device Index   | Reply for Resume      |
+ *   |          |         |      |         | Data[1]: Return code          | a TX Instance         |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x01 |  0x0A   | Data[0]: Audio Device Index   | Reply for Open        |
+ *   |          |         |      |         | Data[1]: Return code          | a TX Instance         |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x01 |  0x0B   | Data[0]: Audio Device Index   | Reply for Start       |
+ *   |          |         |      |         | Data[1]: Return code          | a TX Instance         |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x01 |  0x0C   | Data[0]: Audio Device Index   | Reply for Pause       |
+ *   |          |         |      |         | Data[1]: Return code          | a TX Instance         |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x01 |  0x0D   | Data[0]: Audio Device Index   | Reply for Resume      |
+ *   |          |         |      |         | Data[1]: Return code          | a RX Instance         |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x01 |  0x0E   | Data[0]: Audio Device Index   | Reply for Stop        |
+ *   |          |         |      |         | Data[1]: Return code          | a RX Instance         |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x01 |  0x0F   | Data[0]: Audio Device Index   | Reply for Close       |
+ *   |          |         |      |         | Data[1]: Return code          | a RX Instance         |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x01 |  0x10   | Data[0]: Audio Device Index   | Reply for Set Param   |
+ *   |          |         |      |         | Data[1]: Return code          | for a RX Instance.    |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x01 |  0x11   | Data[0]: Audio Device Index   | Reply for Set         |
+ *   |          |         |      |         | Data[1]: Return code          | RX Buffer             |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x01 |  0x12   | Data[0]: Audio Device Index   | Reply for Suspend     |
+ *   |          |         |      |         | Data[1]: Return code          | a RX Instance         |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x01 |  0x13   | Data[0]: Audio Device Index   | Reply for Resume      |
+ *   |          |         |      |         | Data[1]: Return code          | a RX Instance         |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x01 |  0x14   | Data[0]: Audio Device Index   | Reply for Set codec   |
+ *   |          |         |      |         | Data[1]: Return code          | register value        |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x01 |  0x15   | Data[0]: Audio Device Index   | Reply for Get codec   |
+ *   |          |         |      |         | Data[1]: Return code          | register value        |
+ *   |          |         |      |         | Data[2-6]:   reserved         |                       |
+ *   |          |         |      |         | Data[7-10]:  register         |                       |
+ *   |          |         |      |         | Data[11-14]: value            |                       |
+ *   |          |         |      |         | Data[15-22]: reserved         |                       |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *
+ *   SRTM Audio Control Category Notification Command Table:
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   | Category | Version | Type | Command | Data                          | Function              |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x02 |  0x00   | Data[0]: Audio Device Index   | Notify one TX period  |
+ *   |          |         |      |         |                               | is finished           |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *   |  0x03    | 0x0100  | 0x02 |  0x01   | Data[0]: Audio Device Index   | Notify one RX period  |
+ *   |          |         |      |         |                               | is finished           |
+ *   +----------+---------+------+---------+-------------------------------+-----------------------+
+ *
+ *   List of Sample Format:
+ *   +------------------+-----------------------+
+ *   | Sample Format    |   Description         |
+ *   +------------------+-----------------------+
+ *   |       0x0        | S16_LE                |
+ *   +------------------+-----------------------+
+ *   |       0x1        | S24_LE                |
+ *   +------------------+-----------------------+
+ *
+ *   List of Audio Channels
+ *   +------------------+-----------------------+
+ *   |  Audio Channel   |   Description         |
+ *   +------------------+-----------------------+
+ *   |       0x0        | Left Channel          |
+ *   +------------------+-----------------------+
+ *   |       0x1        | Right Channel         |
+ *   +------------------+---------------- ------+
+ *   |       0x2        | Left & Right Channel  |
+ *   +------------------+-----------------------+
+ *
+ */
+
+#ifndef _IMX_PCM_RPMSG_H
+#define _IMX_PCM_RPMSG_H
+
+#include <linux/pm_qos.h>
+#include <linux/interrupt.h>
+#include <sound/dmaengine_pcm.h>
+
+#define RPMSG_TIMEOUT 1000
+
+/* RPMSG Command (TYPE A)*/
+#define TX_OPEN		0x0
+#define	TX_START	0x1
+#define	TX_PAUSE	0x2
+#define	TX_RESTART	0x3
+#define	TX_TERMINATE	0x4
+#define	TX_CLOSE	0x5
+#define TX_HW_PARAM	0x6
+#define	TX_BUFFER	0x7
+#define	TX_SUSPEND	0x8
+#define	TX_RESUME	0x9
+
+#define	RX_OPEN		0xA
+#define	RX_START	0xB
+#define	RX_PAUSE	0xC
+#define	RX_RESTART	0xD
+#define	RX_TERMINATE	0xE
+#define	RX_CLOSE	0xF
+#define	RX_HW_PARAM	0x10
+#define	RX_BUFFER	0x11
+#define	RX_SUSPEND	0x12
+#define	RX_RESUME	0x13
+#define SET_CODEC_VALUE 0x14
+#define GET_CODEC_VALUE 0x15
+#define	TX_POINTER	0x16
+#define	RX_POINTER	0x17
+/* Total msg numver for type A */
+#define MSG_TYPE_A_NUM  0x18
+
+/* RPMSG Command (TYPE C)*/
+#define	TX_PERIOD_DONE	0x0
+#define	RX_PERIOD_DONE	0x1
+/* Total msg numver for type C */
+#define MSG_TYPE_C_NUM  0x2
+
+#define MSG_MAX_NUM     (MSG_TYPE_A_NUM + MSG_TYPE_C_NUM)
+
+#define MSG_TYPE_A	0x0
+#define MSG_TYPE_B	0x1
+#define MSG_TYPE_C	0x2
+
+#define RESP_NONE		0x0
+#define RESP_NOT_ALLOWED	0x1
+#define	RESP_SUCCESS		0x2
+#define	RESP_FAILED		0x3
+
+#define	RPMSG_S16_LE		0x0
+#define	RPMSG_S24_LE		0x1
+#define	RPMSG_S32_LE		0x2
+#define	RPMSG_DSD_U16_LE	0x3
+#define	RPMSG_DSD_U24_LE	0x4
+#define	RPMSG_DSD_U32_LE	0x5
+
+#define	RPMSG_CH_LEFT		0x0
+#define	RPMSG_CH_RIGHT		0x1
+#define	RPMSG_CH_STEREO		0x2
+
+#define WORK_MAX_NUM    0x30
+
+/* Category define */
+#define IMX_RMPSG_LIFECYCLE     1
+#define IMX_RPMSG_PMIC          2
+#define IMX_RPMSG_AUDIO         3
+#define IMX_RPMSG_KEY           4
+#define IMX_RPMSG_GPIO          5
+#define IMX_RPMSG_RTC           6
+#define IMX_RPMSG_SENSOR        7
+
+/* rpmsg version */
+#define IMX_RMPSG_MAJOR         1
+#define IMX_RMPSG_MINOR         0
+
+#define TX SNDRV_PCM_STREAM_PLAYBACK
+#define RX SNDRV_PCM_STREAM_CAPTURE
+
+/**
+ * struct rpmsg_head: rpmsg header structure
+ *
+ * @cate: category
+ * @major: major version
+ * @minor: minor version
+ * @type: message type (A/B/C)
+ * @cmd: message command
+ * @reserved: reserved space
+ */
+struct rpmsg_head {
+	u8 cate;
+	u8 major;
+	u8 minor;
+	u8 type;
+	u8 cmd;
+	u8 reserved[5];
+} __packed;
+
+/**
+ * struct param_s: sent rpmsg parameter
+ *
+ * @audioindex: audio instance index
+ * @format: audio format
+ * @channels: audio channel number
+ * @rate: sample rate
+ * @buffer_addr: dma buffer physical address or register for SET_CODEC_VALUE
+ * @buffer_size: dma buffer size or register value for SET_CODEC_VALUE
+ * @period_size: period size
+ * @buffer_tail: current period index
+ */
+struct param_s {
+	unsigned char audioindex;
+	unsigned char format;
+	unsigned char channels;
+	unsigned int  rate;
+	unsigned int  buffer_addr;
+	unsigned int  buffer_size;
+	unsigned int  period_size;
+	unsigned int  buffer_tail;
+} __packed;
+
+/**
+ * struct param_s: send rpmsg parameter
+ *
+ * @audioindex: audio instance index
+ * @resp: response value
+ * @reserved1: reserved space
+ * @buffer_offset: the consumed offset of buffer
+ * @reg_addr: register addr of codec
+ * @reg_data: register value of codec
+ * @reserved2: reserved space
+ * @buffer_tail: current period index
+ */
+struct param_r {
+	unsigned char audioindex;
+	unsigned char resp;
+	unsigned char reserved1[1];
+	unsigned int  buffer_offset;
+	unsigned int  reg_addr;
+	unsigned int  reg_data;
+	unsigned char reserved2[4];
+	unsigned int  buffer_tail;
+} __packed;
+
+/* Struct of sent message */
+struct rpmsg_s_msg {
+	struct rpmsg_head header;
+	struct param_s    param;
+};
+
+/* Struct of received message */
+struct rpmsg_r_msg {
+	struct rpmsg_head header;
+	struct param_r    param;
+};
+
+/* Struct of rpmsg */
+struct rpmsg_msg {
+	struct rpmsg_s_msg  s_msg;
+	struct rpmsg_r_msg  r_msg;
+};
+
+/* Struct of rpmsg for workqueue */
+struct work_of_rpmsg {
+	struct rpmsg_info   *info;
+	/* Sent msg for each work */
+	struct rpmsg_msg    msg;
+	struct work_struct  work;
+};
+
+/* Struct of timer */
+struct stream_timer {
+	struct timer_list   timer;
+	struct rpmsg_info   *info;
+	struct snd_pcm_substream *substream;
+};
+
+typedef void (*dma_callback)(void *arg);
+
+/**
+ * struct rpmsg_info: rpmsg audio information
+ *
+ * @rpdev: pointer of rpmsg_device
+ * @dev: pointer for imx_pcm_rpmsg device
+ * @cmd_complete: command is finished
+ * @pm_qos_req: request of pm qos
+ * @r_msg: received rpmsg
+ * @msg: array of rpmsg
+ * @notify: notification msg (type C) for TX & RX
+ * @notify_updated: notification flag for TX & RX
+ * @rpmsg_wq: rpmsg workqueue
+ * @work_list: array of work list for workqueue
+ * @work_write_index: write index of work list
+ * @work_read_index: read index of work list
+ * @msg_drop_count: counter of dropped msg for TX & RX
+ * @num_period: period number for TX & RX
+ * @callback_param: parameter for period elapse callback for TX & RX
+ * @callback: period elapse callback for TX & RX
+ * @send_message: function pointer for send message
+ * @lock: spin lock for TX & RX
+ * @wq_lock: lock for work queue
+ * @msg_lock: lock for send message
+ * @stream_timer: timer for tigger workqueue
+ */
+struct rpmsg_info {
+	struct rpmsg_device      *rpdev;
+	struct device            *dev;
+	struct completion        cmd_complete;
+	struct pm_qos_request    pm_qos_req;
+
+	/* Received msg (global) */
+	struct rpmsg_r_msg       r_msg;
+	struct rpmsg_msg         msg[MSG_MAX_NUM];
+	/* period done */
+	struct rpmsg_msg         notify[2];
+	bool                     notify_updated[2];
+
+	struct workqueue_struct  *rpmsg_wq;
+	struct work_of_rpmsg	 work_list[WORK_MAX_NUM];
+	int                      work_write_index;
+	int                      work_read_index;
+	int                      msg_drop_count[2];
+	int                      num_period[2];
+	void                     *callback_param[2];
+	dma_callback             callback[2];
+	int (*send_message)(struct rpmsg_msg *msg, struct rpmsg_info *info);
+	spinlock_t               lock[2]; /* spin lock for resource protection */
+	spinlock_t               wq_lock; /* spin lock for resource protection */
+	struct mutex             msg_lock; /* mutex for resource protection */
+	struct stream_timer      stream_timer[2];
+};
+
+#define IMX_PCM_DRV_NAME "imx_pcm_rpmsg"
+
+#endif /* IMX_PCM_RPMSG_H */
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v4 6/6] ASoC: imx-rpmsg: Add machine driver for audio base on rpmsg
  2021-03-08 13:22 [PATCH v4 0/6] Add audio driver base on rpmsg on i.MX platform Shengjiu Wang
                   ` (4 preceding siblings ...)
  2021-03-08 13:22 ` [PATCH v4 5/6] ASoC: imx-pcm-rpmsg: Add platform driver for audio base on rpmsg Shengjiu Wang
@ 2021-03-08 13:22 ` Shengjiu Wang
  5 siblings, 0 replies; 12+ messages in thread
From: Shengjiu Wang @ 2021-03-08 13:22 UTC (permalink / raw)
  To: lgirdwood, broonie, perex, tiwai, alsa-devel, linux-kernel,
	timur, nicoleotsuka, Xiubo.Lee, festevam, linuxppc-dev, robh+dt,
	devicetree

The platform device is not registered by device tree or
cpu dai driver, it is registered by the rpmsg channel,
So add a dedicated machine driver to handle this case.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
---
 sound/soc/fsl/Kconfig     |  12 ++++
 sound/soc/fsl/Makefile    |   2 +
 sound/soc/fsl/imx-rpmsg.c | 127 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 141 insertions(+)
 create mode 100644 sound/soc/fsl/imx-rpmsg.c

diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 3b94882aee99..ad69026a7fd1 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -334,6 +334,18 @@ config SND_SOC_IMX_HDMI
 	  Say Y if you want to add support for SoC audio on an i.MX board with
 	  IMX HDMI.
 
+config SND_SOC_IMX_RPMSG
+	tristate "SoC Audio support for i.MX boards with rpmsg"
+	depends on RPMSG
+	select SND_SOC_IMX_PCM_RPMSG
+	select SND_SOC_IMX_AUDIO_RPMSG
+	select SND_SOC_FSL_RPMSG
+	help
+	  SoC Audio support for i.MX boards with rpmsg.
+	  There should be rpmsg devices defined in other core (M core)
+	  Say Y if you want to add support for SoC audio on an i.MX board with
+	  a rpmsg devices.
+
 endif # SND_IMX_SOC
 
 endmenu
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index ce4f4324c3a2..f146ce464acd 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -70,6 +70,7 @@ snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
 snd-soc-imx-spdif-objs := imx-spdif.o
 snd-soc-imx-audmix-objs := imx-audmix.o
 snd-soc-imx-hdmi-objs := imx-hdmi.o
+snd-soc-imx-rpmsg-objs := imx-rpmsg.o
 
 obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
 obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o
@@ -77,3 +78,4 @@ obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
 obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o
 obj-$(CONFIG_SND_SOC_IMX_AUDMIX) += snd-soc-imx-audmix.o
 obj-$(CONFIG_SND_SOC_IMX_HDMI) += snd-soc-imx-hdmi.o
+obj-$(CONFIG_SND_SOC_IMX_RPMSG) += snd-soc-imx-rpmsg.o
diff --git a/sound/soc/fsl/imx-rpmsg.c b/sound/soc/fsl/imx-rpmsg.c
new file mode 100644
index 000000000000..c26531525a7b
--- /dev/null
+++ b/sound/soc/fsl/imx-rpmsg.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright 2017-2020 NXP
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/i2c.h>
+#include <linux/of_gpio.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/control.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include "imx-pcm-rpmsg.h"
+
+struct imx_rpmsg {
+	struct snd_soc_dai_link dai;
+	struct snd_soc_card card;
+};
+
+static int imx_rpmsg_probe(struct platform_device *pdev)
+{
+	struct snd_soc_dai_link_component *dlc;
+	struct device *dev = pdev->dev.parent;
+	/* rpmsg_pdev is the platform device for the rpmsg node that probed us */
+	struct platform_device *rpmsg_pdev = to_platform_device(dev);
+	struct device_node *np = rpmsg_pdev->dev.of_node;
+	struct of_phandle_args args;
+	struct imx_rpmsg *data;
+	int ret = 0;
+
+	dlc = devm_kzalloc(&pdev->dev, 3 * sizeof(*dlc), GFP_KERNEL);
+	if (!dlc)
+		return -ENOMEM;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	ret = of_reserved_mem_device_init_by_idx(&pdev->dev, np, 0);
+	if (ret)
+		dev_warn(&pdev->dev, "no reserved DMA memory\n");
+
+	data->dai.cpus = &dlc[0];
+	data->dai.num_cpus = 1;
+	data->dai.platforms = &dlc[1];
+	data->dai.num_platforms = 1;
+	data->dai.codecs = &dlc[2];
+	data->dai.num_codecs = 1;
+
+	data->dai.name = "rpmsg hifi";
+	data->dai.stream_name = "rpmsg hifi";
+	data->dai.dai_fmt = SND_SOC_DAIFMT_I2S |
+			    SND_SOC_DAIFMT_NB_NF |
+			    SND_SOC_DAIFMT_CBS_CFS;
+
+	/* Optional codec node */
+	ret = of_parse_phandle_with_fixed_args(np, "audio-codec", 0, 0, &args);
+	if (ret) {
+		data->dai.codecs->dai_name = "snd-soc-dummy-dai";
+		data->dai.codecs->name = "snd-soc-dummy";
+	} else {
+		data->dai.codecs->of_node = args.np;
+		ret = snd_soc_get_dai_name(&args, &data->dai.codecs->dai_name);
+		if (ret) {
+			dev_err(&pdev->dev, "Unable to get codec_dai_name\n");
+			goto fail;
+		}
+	}
+
+	data->dai.cpus->dai_name = dev_name(&rpmsg_pdev->dev);
+	data->dai.platforms->name = IMX_PCM_DRV_NAME;
+	data->dai.playback_only = true;
+	data->dai.capture_only = true;
+	data->card.num_links = 1;
+	data->card.dai_link = &data->dai;
+
+	if (of_property_read_bool(np, "fsl,rpmsg-out"))
+		data->dai.capture_only = false;
+
+	if (of_property_read_bool(np, "fsl,rpmsg-in"))
+		data->dai.playback_only = false;
+
+	if (data->dai.playback_only && data->dai.capture_only) {
+		dev_err(&pdev->dev, "no enabled rpmsg DAI link\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	data->card.dev = &pdev->dev;
+	data->card.owner = THIS_MODULE;
+
+	ret = of_property_read_string_index(np, "model", 0, &data->card.name);
+	if (ret)
+		goto fail;
+
+	platform_set_drvdata(pdev, &data->card);
+	snd_soc_card_set_drvdata(&data->card, data);
+	ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+		goto fail;
+	}
+
+fail:
+	return ret;
+}
+
+static struct platform_driver imx_rpmsg_driver = {
+	.driver = {
+		.name = "imx-audio-rpmsg",
+		.owner = THIS_MODULE,
+		.pm = &snd_soc_pm_ops,
+	},
+	.probe = imx_rpmsg_probe,
+};
+module_platform_driver(imx_rpmsg_driver);
+
+MODULE_DESCRIPTION("Freescale SoC Audio RPMSG Machine Driver");
+MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
+MODULE_ALIAS("platform:imx-audio-rpmsg");
+MODULE_LICENSE("GPL v2");
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v4 2/6] ASoC: fsl_rpmsg: Add CPU DAI driver for audio base on rpmsg
  2021-03-08 13:22 ` [PATCH v4 2/6] ASoC: fsl_rpmsg: Add CPU DAI driver for audio base on rpmsg Shengjiu Wang
@ 2021-03-08 22:37   ` kernel test robot
  0 siblings, 0 replies; 12+ messages in thread
From: kernel test robot @ 2021-03-08 22:37 UTC (permalink / raw)
  To: Shengjiu Wang, lgirdwood, broonie, perex, tiwai, alsa-devel,
	linux-kernel, timur, nicoleotsuka, Xiubo.Lee, festevam
  Cc: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 2212 bytes --]

Hi Shengjiu,

I love your patch! Yet something to improve:

[auto build test ERROR on asoc/for-next]
[also build test ERROR on shawnguo/for-next v5.12-rc2]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Shengjiu-Wang/Add-audio-driver-base-on-rpmsg-on-i-MX-platform/20210308-213802
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
config: sh-allmodconfig (attached as .config)
compiler: sh4-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/0cabc4a6bce0db6d63de8cfffbdc5fe53c4ea6f5
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Shengjiu-Wang/Add-audio-driver-base-on-rpmsg-on-i-MX-platform/20210308-213802
        git checkout 0cabc4a6bce0db6d63de8cfffbdc5fe53c4ea6f5
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=sh 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>, old ones prefixed by <<):

>> ERROR: modpost: "__clk_get_name" [sound/soc/fsl/snd-soc-fsl-rpmsg.ko] undefined!
ERROR: modpost: "__delay" [drivers/net/mdio/mdio-cavium.ko] undefined!
ERROR: modpost: "__udivdi3" [fs/btrfs/btrfs.ko] undefined!
ERROR: modpost: "__umoddi3" [fs/btrfs/btrfs.ko] undefined!

Kconfig warnings: (for reference only)
   WARNING: unmet direct dependencies detected for SND_ATMEL_SOC_PDC
   Depends on SOUND && !UML && SND && SND_SOC && SND_ATMEL_SOC && HAS_DMA
   Selected by
   - SND_ATMEL_SOC_SSC && SOUND && !UML && SND && SND_SOC && SND_ATMEL_SOC
   - SND_ATMEL_SOC_SSC_PDC && SOUND && !UML && SND && SND_SOC && SND_ATMEL_SOC && ATMEL_SSC

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 54177 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v4 3/6] ASoC: dt-bindings: fsl_rpmsg: Add binding doc for rpmsg cpu dai driver
  2021-03-08 13:22 ` [PATCH v4 3/6] ASoC: dt-bindings: fsl_rpmsg: Add binding doc for rpmsg cpu dai driver Shengjiu Wang
@ 2021-03-10  2:48   ` Rob Herring
  2021-03-10 13:33     ` Shengjiu Wang
  0 siblings, 1 reply; 12+ messages in thread
From: Rob Herring @ 2021-03-10  2:48 UTC (permalink / raw)
  To: Shengjiu Wang
  Cc: devicetree, alsa-devel, timur, lgirdwood, linuxppc-dev,
	Xiubo.Lee, linux-kernel, tiwai, nicoleotsuka, broonie, festevam

On Mon, Mar 08, 2021 at 09:22:27PM +0800, Shengjiu Wang wrote:
> fsl_rpmsg cpu dai driver is driver for rpmsg audio, which is mainly used

Bindings describe h/w blocks, not drivers.

> for getting the user's configuration from device tree and configure the
> clocks which is used by Cortex-M core. So in this document define the
> needed property.
> 
> Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
> ---
>  .../devicetree/bindings/sound/fsl,rpmsg.yaml  | 118 ++++++++++++++++++
>  1 file changed, 118 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
> 
> diff --git a/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
> new file mode 100644
> index 000000000000..5731c1fbc0a6
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
> @@ -0,0 +1,118 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/sound/fsl,rpmsg.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: NXP Audio RPMSG CPU DAI Controller
> +
> +maintainers:
> +  - Shengjiu Wang <shengjiu.wang@nxp.com>
> +
> +description: |
> +  fsl_rpmsg cpu dai driver is virtual driver for rpmsg audio, which doesn't
> +  touch hardware. It is mainly used for getting the user's configuration
> +  from device tree and configure the clocks which is used by Cortex-M core.
> +  So in this document define the needed property.
> +
> +properties:
> +  compatible:
> +    enum:
> +      - fsl,imx7ulp-rpmsg
> +      - fsl,imx8mn-rpmsg
> +      - fsl,imx8mm-rpmsg
> +      - fsl,imx8mp-rpmsg
> +
> +  model:
> +    $ref: /schemas/types.yaml#/definitions/string
> +    description: User specified audio sound card name
> +
> +  clocks:
> +    items:
> +      - description: Peripheral clock for register access
> +      - description: Master clock
> +      - description: DMA clock for DMA register access
> +      - description: Parent clock for multiple of 8kHz sample rates
> +      - description: Parent clock for multiple of 11kHz sample rates
> +    minItems: 5

If this doesn't touch hardware, what are these clocks for?

You don't need 'minItems' unless it's less than the number of 'items'.

> +
> +  clock-names:
> +    items:
> +      - const: ipg
> +      - const: mclk
> +      - const: dma
> +      - const: pll8k
> +      - const: pll11k
> +    minItems: 5
> +
> +  power-domains:
> +    maxItems: 1
> +
> +  fsl,audioindex:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    enum: [0, 1]
> +    default: 0
> +    description: Instance index for sound card in
> +                 M core side, which share one rpmsg
> +                 channel.

We don't do indexes in DT. What's this numbering tied to?

> +
> +  fsl,version:

version of what?

This seems odd at best.

> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    enum: [1, 2]

You're going to update this with every new firmware version?

> +    default: 2
> +    description: The version of M core image, which is
> +                 to make driver compatible with different image.
> +
> +  fsl,buffer-size:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description: pre allocate dma buffer size

How can you have DMA, this doesn't touch h/w?

> +
> +  fsl,enable-lpa:
> +    $ref: /schemas/types.yaml#/definitions/flag
> +    description: enable low power audio path.
> +
> +  fsl,rpmsg-out:
> +    $ref: /schemas/types.yaml#/definitions/flag
> +    description: |
> +      This is a boolean property. If present, the transmitting function
> +      will be enabled.
> +
> +  fsl,rpmsg-in:
> +    $ref: /schemas/types.yaml#/definitions/flag
> +    description: |
> +      This is a boolean property. If present, the receiving function
> +      will be enabled.
> +
> +  fsl,codec-type:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    enum: [0, 1, 2]
> +    default: 0
> +    description: Sometimes the codec is registered by
> +                 driver not by the device tree, this items
> +                 can be used to distinguish codecs.

How does one decide what value to use?

> +
> +  audio-codec:
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +    description: The phandle of the audio codec

The codec is controlled from the Linux side?

> +
> +  memory-region:
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +    description: phandle to the reserved memory nodes
> +
> +required:
> +  - compatible
> +  - fsl,audioindex
> +  - fsl,version
> +  - fsl,buffer-size
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    rpmsg_audio: rpmsg_audio {
> +        compatible = "fsl,imx8mn-rpmsg";
> +        fsl,audioindex = <0> ;
> +        fsl,version = <2>;
> +        fsl,buffer-size = <0x6000000>;
> +        fsl,enable-lpa;

How does this work? Don't you need somewhere to put the 'rpmsg' data?

> +    };
> -- 
> 2.27.0
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v4 3/6] ASoC: dt-bindings: fsl_rpmsg: Add binding doc for rpmsg cpu dai driver
  2021-03-10  2:48   ` Rob Herring
@ 2021-03-10 13:33     ` Shengjiu Wang
  2021-03-10 21:12       ` Rob Herring
  0 siblings, 1 reply; 12+ messages in thread
From: Shengjiu Wang @ 2021-03-10 13:33 UTC (permalink / raw)
  To: Rob Herring
  Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	alsa-devel, Timur Tabi, Xiubo Li, Fabio Estevam, Shengjiu Wang,
	Takashi Iwai, Liam Girdwood, linux-kernel, Nicolin Chen,
	Mark Brown, linuxppc-dev

Hi Rob

On Wed, Mar 10, 2021 at 10:49 AM Rob Herring <robh@kernel.org> wrote:
>
> On Mon, Mar 08, 2021 at 09:22:27PM +0800, Shengjiu Wang wrote:
> > fsl_rpmsg cpu dai driver is driver for rpmsg audio, which is mainly used
>
> Bindings describe h/w blocks, not drivers.

I will modify the descriptions. but here it is a virtual device.  the
mapping in real h/w is cortex M core, Cortex M core controls the SAI,
DMA interface. What we see from Linux side is a audio service
through rpmsg channel.

>
> > for getting the user's configuration from device tree and configure the
> > clocks which is used by Cortex-M core. So in this document define the
> > needed property.
> >
> > Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
> > ---
> >  .../devicetree/bindings/sound/fsl,rpmsg.yaml  | 118 ++++++++++++++++++
> >  1 file changed, 118 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
> > new file mode 100644
> > index 000000000000..5731c1fbc0a6
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
> > @@ -0,0 +1,118 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/sound/fsl,rpmsg.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: NXP Audio RPMSG CPU DAI Controller
> > +
> > +maintainers:
> > +  - Shengjiu Wang <shengjiu.wang@nxp.com>
> > +
> > +description: |
> > +  fsl_rpmsg cpu dai driver is virtual driver for rpmsg audio, which doesn't
> > +  touch hardware. It is mainly used for getting the user's configuration
> > +  from device tree and configure the clocks which is used by Cortex-M core.
> > +  So in this document define the needed property.
> > +
> > +properties:
> > +  compatible:
> > +    enum:
> > +      - fsl,imx7ulp-rpmsg
> > +      - fsl,imx8mn-rpmsg
> > +      - fsl,imx8mm-rpmsg
> > +      - fsl,imx8mp-rpmsg
> > +
> > +  model:
> > +    $ref: /schemas/types.yaml#/definitions/string
> > +    description: User specified audio sound card name
> > +
> > +  clocks:
> > +    items:
> > +      - description: Peripheral clock for register access
> > +      - description: Master clock
> > +      - description: DMA clock for DMA register access
> > +      - description: Parent clock for multiple of 8kHz sample rates
> > +      - description: Parent clock for multiple of 11kHz sample rates
> > +    minItems: 5
>
> If this doesn't touch hardware, what are these clocks for?

When the cortex-M core support audio service, these clock
needed prepared & enabled by ALSA driver.

>
> You don't need 'minItems' unless it's less than the number of 'items'.

Ok, I will remove this minItems.

>
> > +
> > +  clock-names:
> > +    items:
> > +      - const: ipg
> > +      - const: mclk
> > +      - const: dma
> > +      - const: pll8k
> > +      - const: pll11k
> > +    minItems: 5
> > +
> > +  power-domains:
> > +    maxItems: 1
> > +
> > +  fsl,audioindex:
> > +    $ref: /schemas/types.yaml#/definitions/uint32
> > +    enum: [0, 1]
> > +    default: 0
> > +    description: Instance index for sound card in
> > +                 M core side, which share one rpmsg
> > +                 channel.
>
> We don't do indexes in DT. What's this numbering tied to?

I will remove it. it is not necessary

>
> > +
> > +  fsl,version:
>
> version of what?
>
> This seems odd at best.
>

I will remove it.  it is not necessary

> > +    $ref: /schemas/types.yaml#/definitions/uint32
> > +    enum: [1, 2]
>
> You're going to update this with every new firmware version?
>
> > +    default: 2
> > +    description: The version of M core image, which is
> > +                 to make driver compatible with different image.
> > +
> > +  fsl,buffer-size:
> > +    $ref: /schemas/types.yaml#/definitions/uint32
> > +    description: pre allocate dma buffer size
>
> How can you have DMA, this doesn't touch h/w?

The DMA is handled by M core image for sound playback
and capture. we need to allocated buffer in Linux side.
here just make the buffer size to be configurable.
>
> > +
> > +  fsl,enable-lpa:
> > +    $ref: /schemas/types.yaml#/definitions/flag
> > +    description: enable low power audio path.
> > +
> > +  fsl,rpmsg-out:
> > +    $ref: /schemas/types.yaml#/definitions/flag
> > +    description: |
> > +      This is a boolean property. If present, the transmitting function
> > +      will be enabled.
> > +
> > +  fsl,rpmsg-in:
> > +    $ref: /schemas/types.yaml#/definitions/flag
> > +    description: |
> > +      This is a boolean property. If present, the receiving function
> > +      will be enabled.
> > +
> > +  fsl,codec-type:
> > +    $ref: /schemas/types.yaml#/definitions/uint32
> > +    enum: [0, 1, 2]
> > +    default: 0
> > +    description: Sometimes the codec is registered by
> > +                 driver not by the device tree, this items
> > +                 can be used to distinguish codecs.
>
> How does one decide what value to use?

I will add more description:
0: dummy codec
1: WM8960 codec
2: AK4497 codec

>
> > +
> > +  audio-codec:
> > +    $ref: /schemas/types.yaml#/definitions/phandle
> > +    description: The phandle of the audio codec
>
> The codec is controlled from the Linux side?

yes.

>
> > +
> > +  memory-region:
> > +    $ref: /schemas/types.yaml#/definitions/phandle
> > +    description: phandle to the reserved memory nodes
> > +
> > +required:
> > +  - compatible
> > +  - fsl,audioindex
> > +  - fsl,version
> > +  - fsl,buffer-size
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +  - |
> > +    rpmsg_audio: rpmsg_audio {
> > +        compatible = "fsl,imx8mn-rpmsg";
> > +        fsl,audioindex = <0> ;
> > +        fsl,version = <2>;
> > +        fsl,buffer-size = <0x6000000>;
> > +        fsl,enable-lpa;
>
> How does this work? Don't you need somewhere to put the 'rpmsg' data?

The rpmsg data is not handled in this "rpmsg_audio" device, it is just to
prepare the resource for rpmsg audio function, the clock, the memory
the power...

The rpmsg data is handled in imx-pcm-rpmsg.c and imx-audio-rpmsg.c
These devices is registered by imx remoteproc driver.


I will update this document in v5

Best regards
Wang Shengjiu

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v4 3/6] ASoC: dt-bindings: fsl_rpmsg: Add binding doc for rpmsg cpu dai driver
  2021-03-10 13:33     ` Shengjiu Wang
@ 2021-03-10 21:12       ` Rob Herring
  2021-03-11 10:58         ` Shengjiu Wang
  0 siblings, 1 reply; 12+ messages in thread
From: Rob Herring @ 2021-03-10 21:12 UTC (permalink / raw)
  To: Shengjiu Wang
  Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Linux-ALSA, Timur Tabi, Xiubo Li, Fabio Estevam, Shengjiu Wang,
	Takashi Iwai, Liam Girdwood, linux-kernel, Nicolin Chen,
	Mark Brown, linuxppc-dev

On Wed, Mar 10, 2021 at 6:33 AM Shengjiu Wang <shengjiu.wang@gmail.com> wrote:
>
> Hi Rob
>
> On Wed, Mar 10, 2021 at 10:49 AM Rob Herring <robh@kernel.org> wrote:
> >
> > On Mon, Mar 08, 2021 at 09:22:27PM +0800, Shengjiu Wang wrote:
> > > fsl_rpmsg cpu dai driver is driver for rpmsg audio, which is mainly used
> >
> > Bindings describe h/w blocks, not drivers.
>
> I will modify the descriptions. but here it is a virtual device.  the
> mapping in real h/w is cortex M core, Cortex M core controls the SAI,
> DMA interface. What we see from Linux side is a audio service
> through rpmsg channel.

It's describing the h/w from the view of the OS. It's not important
that it's a Cortex-M, but how you interface to it whether that's
shared registers, mailbox, etc. And it's what resources the block uses
that the OS controls.

> > > for getting the user's configuration from device tree and configure the
> > > clocks which is used by Cortex-M core. So in this document define the
> > > needed property.
> > >
> > > Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
> > > ---
> > >  .../devicetree/bindings/sound/fsl,rpmsg.yaml  | 118 ++++++++++++++++++
> > >  1 file changed, 118 insertions(+)
> > >  create mode 100644 Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
> > >
> > > diff --git a/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
> > > new file mode 100644
> > > index 000000000000..5731c1fbc0a6
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
> > > @@ -0,0 +1,118 @@
> > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > +%YAML 1.2
> > > +---
> > > +$id: http://devicetree.org/schemas/sound/fsl,rpmsg.yaml#
> > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > +
> > > +title: NXP Audio RPMSG CPU DAI Controller
> > > +
> > > +maintainers:
> > > +  - Shengjiu Wang <shengjiu.wang@nxp.com>
> > > +
> > > +description: |
> > > +  fsl_rpmsg cpu dai driver is virtual driver for rpmsg audio, which doesn't
> > > +  touch hardware. It is mainly used for getting the user's configuration
> > > +  from device tree and configure the clocks which is used by Cortex-M core.
> > > +  So in this document define the needed property.
> > > +
> > > +properties:
> > > +  compatible:
> > > +    enum:
> > > +      - fsl,imx7ulp-rpmsg
> > > +      - fsl,imx8mn-rpmsg
> > > +      - fsl,imx8mm-rpmsg
> > > +      - fsl,imx8mp-rpmsg
> > > +
> > > +  model:
> > > +    $ref: /schemas/types.yaml#/definitions/string
> > > +    description: User specified audio sound card name
> > > +
> > > +  clocks:
> > > +    items:
> > > +      - description: Peripheral clock for register access
> > > +      - description: Master clock
> > > +      - description: DMA clock for DMA register access
> > > +      - description: Parent clock for multiple of 8kHz sample rates
> > > +      - description: Parent clock for multiple of 11kHz sample rates
> > > +    minItems: 5
> >
> > If this doesn't touch hardware, what are these clocks for?
>
> When the cortex-M core support audio service, these clock
> needed prepared & enabled by ALSA driver.
>
> >
> > You don't need 'minItems' unless it's less than the number of 'items'.
>
> Ok, I will remove this minItems.
>
> >
> > > +
> > > +  clock-names:
> > > +    items:
> > > +      - const: ipg
> > > +      - const: mclk
> > > +      - const: dma
> > > +      - const: pll8k
> > > +      - const: pll11k
> > > +    minItems: 5
> > > +
> > > +  power-domains:
> > > +    maxItems: 1
> > > +
> > > +  fsl,audioindex:
> > > +    $ref: /schemas/types.yaml#/definitions/uint32
> > > +    enum: [0, 1]
> > > +    default: 0
> > > +    description: Instance index for sound card in
> > > +                 M core side, which share one rpmsg
> > > +                 channel.
> >
> > We don't do indexes in DT. What's this numbering tied to?
>
> I will remove it. it is not necessary
>
> >
> > > +
> > > +  fsl,version:
> >
> > version of what?
> >
> > This seems odd at best.
> >
>
> I will remove it.  it is not necessary
>
> > > +    $ref: /schemas/types.yaml#/definitions/uint32
> > > +    enum: [1, 2]
> >
> > You're going to update this with every new firmware version?
> >
> > > +    default: 2
> > > +    description: The version of M core image, which is
> > > +                 to make driver compatible with different image.
> > > +
> > > +  fsl,buffer-size:
> > > +    $ref: /schemas/types.yaml#/definitions/uint32
> > > +    description: pre allocate dma buffer size
> >
> > How can you have DMA, this doesn't touch h/w?
>
> The DMA is handled by M core image for sound playback
> and capture. we need to allocated buffer in Linux side.
> here just make the buffer size to be configurable.

Do we set audio buffer sizes for other audio devices in DT? If not,
why is this special? If so, why is it not common.

> > > +  fsl,enable-lpa:
> > > +    $ref: /schemas/types.yaml#/definitions/flag
> > > +    description: enable low power audio path.
> > > +
> > > +  fsl,rpmsg-out:
> > > +    $ref: /schemas/types.yaml#/definitions/flag
> > > +    description: |
> > > +      This is a boolean property. If present, the transmitting function
> > > +      will be enabled.
> > > +
> > > +  fsl,rpmsg-in:
> > > +    $ref: /schemas/types.yaml#/definitions/flag
> > > +    description: |
> > > +      This is a boolean property. If present, the receiving function
> > > +      will be enabled.
> > > +
> > > +  fsl,codec-type:
> > > +    $ref: /schemas/types.yaml#/definitions/uint32
> > > +    enum: [0, 1, 2]
> > > +    default: 0
> > > +    description: Sometimes the codec is registered by
> > > +                 driver not by the device tree, this items
> > > +                 can be used to distinguish codecs.
> >
> > How does one decide what value to use?
>
> I will add more description:
> 0: dummy codec
> 1: WM8960 codec
> 2: AK4497 codec

I assume the last 2 cases have nodes in DT (pointed to by
'audio-codec'), so this is redundant.

> > > +
> > > +  audio-codec:
> > > +    $ref: /schemas/types.yaml#/definitions/phandle
> > > +    description: The phandle of the audio codec
> >
> > The codec is controlled from the Linux side?
>
> yes.
>
> >
> > > +
> > > +  memory-region:
> > > +    $ref: /schemas/types.yaml#/definitions/phandle
> > > +    description: phandle to the reserved memory nodes
> > > +
> > > +required:
> > > +  - compatible
> > > +  - fsl,audioindex
> > > +  - fsl,version
> > > +  - fsl,buffer-size
> > > +
> > > +additionalProperties: false
> > > +
> > > +examples:
> > > +  - |
> > > +    rpmsg_audio: rpmsg_audio {
> > > +        compatible = "fsl,imx8mn-rpmsg";
> > > +        fsl,audioindex = <0> ;
> > > +        fsl,version = <2>;
> > > +        fsl,buffer-size = <0x6000000>;
> > > +        fsl,enable-lpa;
> >
> > How does this work? Don't you need somewhere to put the 'rpmsg' data?
>
> The rpmsg data is not handled in this "rpmsg_audio" device, it is just to
> prepare the resource for rpmsg audio function, the clock, the memory
> the power...
>
> The rpmsg data is handled in imx-pcm-rpmsg.c and imx-audio-rpmsg.c
> These devices is registered by imx remoteproc driver.

Then what is 'memory-region' for? You need that, a mailbox, or ???
somewhere in DT.

Rob

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v4 3/6] ASoC: dt-bindings: fsl_rpmsg: Add binding doc for rpmsg cpu dai driver
  2021-03-10 21:12       ` Rob Herring
@ 2021-03-11 10:58         ` Shengjiu Wang
  0 siblings, 0 replies; 12+ messages in thread
From: Shengjiu Wang @ 2021-03-11 10:58 UTC (permalink / raw)
  To: Rob Herring
  Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Linux-ALSA, Timur Tabi, Xiubo Li, Fabio Estevam, Shengjiu Wang,
	Takashi Iwai, Liam Girdwood, linux-kernel, Nicolin Chen,
	Mark Brown, linuxppc-dev

Hi Rob

On Thu, Mar 11, 2021 at 5:12 AM Rob Herring <robh@kernel.org> wrote:
>
> On Wed, Mar 10, 2021 at 6:33 AM Shengjiu Wang <shengjiu.wang@gmail.com> wrote:
> >
> > Hi Rob
> >
> > On Wed, Mar 10, 2021 at 10:49 AM Rob Herring <robh@kernel.org> wrote:
> > >
> > > On Mon, Mar 08, 2021 at 09:22:27PM +0800, Shengjiu Wang wrote:
> > > > fsl_rpmsg cpu dai driver is driver for rpmsg audio, which is mainly used
> > >
> > > Bindings describe h/w blocks, not drivers.
> >
> > I will modify the descriptions. but here it is a virtual device.  the
> > mapping in real h/w is cortex M core, Cortex M core controls the SAI,
> > DMA interface. What we see from Linux side is a audio service
> > through rpmsg channel.
>
> It's describing the h/w from the view of the OS. It's not important
> that it's a Cortex-M, but how you interface to it whether that's
> shared registers, mailbox, etc. And it's what resources the block uses
> that the OS controls.

ok.

>
> > > > for getting the user's configuration from device tree and configure the
> > > > clocks which is used by Cortex-M core. So in this document define the
> > > > needed property.
> > > >
> > > > Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
> > > > ---
> > > >  .../devicetree/bindings/sound/fsl,rpmsg.yaml  | 118 ++++++++++++++++++
> > > >  1 file changed, 118 insertions(+)
> > > >  create mode 100644 Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
> > > >
> > > > diff --git a/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
> > > > new file mode 100644
> > > > index 000000000000..5731c1fbc0a6
> > > > --- /dev/null
> > > > +++ b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml
> > > > @@ -0,0 +1,118 @@
> > > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > > +%YAML 1.2
> > > > +---
> > > > +$id: http://devicetree.org/schemas/sound/fsl,rpmsg.yaml#
> > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > +
> > > > +title: NXP Audio RPMSG CPU DAI Controller
> > > > +
> > > > +maintainers:
> > > > +  - Shengjiu Wang <shengjiu.wang@nxp.com>
> > > > +
> > > > +description: |
> > > > +  fsl_rpmsg cpu dai driver is virtual driver for rpmsg audio, which doesn't
> > > > +  touch hardware. It is mainly used for getting the user's configuration
> > > > +  from device tree and configure the clocks which is used by Cortex-M core.
> > > > +  So in this document define the needed property.
> > > > +
> > > > +properties:
> > > > +  compatible:
> > > > +    enum:
> > > > +      - fsl,imx7ulp-rpmsg
> > > > +      - fsl,imx8mn-rpmsg
> > > > +      - fsl,imx8mm-rpmsg
> > > > +      - fsl,imx8mp-rpmsg
> > > > +
> > > > +  model:
> > > > +    $ref: /schemas/types.yaml#/definitions/string
> > > > +    description: User specified audio sound card name
> > > > +
> > > > +  clocks:
> > > > +    items:
> > > > +      - description: Peripheral clock for register access
> > > > +      - description: Master clock
> > > > +      - description: DMA clock for DMA register access
> > > > +      - description: Parent clock for multiple of 8kHz sample rates
> > > > +      - description: Parent clock for multiple of 11kHz sample rates
> > > > +    minItems: 5
> > >
> > > If this doesn't touch hardware, what are these clocks for?
> >
> > When the cortex-M core support audio service, these clock
> > needed prepared & enabled by ALSA driver.
> >
> > >
> > > You don't need 'minItems' unless it's less than the number of 'items'.
> >
> > Ok, I will remove this minItems.
> >
> > >
> > > > +
> > > > +  clock-names:
> > > > +    items:
> > > > +      - const: ipg
> > > > +      - const: mclk
> > > > +      - const: dma
> > > > +      - const: pll8k
> > > > +      - const: pll11k
> > > > +    minItems: 5
> > > > +
> > > > +  power-domains:
> > > > +    maxItems: 1
> > > > +
> > > > +  fsl,audioindex:
> > > > +    $ref: /schemas/types.yaml#/definitions/uint32
> > > > +    enum: [0, 1]
> > > > +    default: 0
> > > > +    description: Instance index for sound card in
> > > > +                 M core side, which share one rpmsg
> > > > +                 channel.
> > >
> > > We don't do indexes in DT. What's this numbering tied to?
> >
> > I will remove it. it is not necessary
> >
> > >
> > > > +
> > > > +  fsl,version:
> > >
> > > version of what?
> > >
> > > This seems odd at best.
> > >
> >
> > I will remove it.  it is not necessary
> >
> > > > +    $ref: /schemas/types.yaml#/definitions/uint32
> > > > +    enum: [1, 2]
> > >
> > > You're going to update this with every new firmware version?
> > >
> > > > +    default: 2
> > > > +    description: The version of M core image, which is
> > > > +                 to make driver compatible with different image.
> > > > +
> > > > +  fsl,buffer-size:
> > > > +    $ref: /schemas/types.yaml#/definitions/uint32
> > > > +    description: pre allocate dma buffer size
> > >
> > > How can you have DMA, this doesn't touch h/w?
> >
> > The DMA is handled by M core image for sound playback
> > and capture. we need to allocated buffer in Linux side.
> > here just make the buffer size to be configurable.
>
> Do we set audio buffer sizes for other audio devices in DT? If not,
> why is this special? If so, why is it not common.

No. I will move it to driver.

>
> > > > +  fsl,enable-lpa:
> > > > +    $ref: /schemas/types.yaml#/definitions/flag
> > > > +    description: enable low power audio path.
> > > > +
> > > > +  fsl,rpmsg-out:
> > > > +    $ref: /schemas/types.yaml#/definitions/flag
> > > > +    description: |
> > > > +      This is a boolean property. If present, the transmitting function
> > > > +      will be enabled.
> > > > +
> > > > +  fsl,rpmsg-in:
> > > > +    $ref: /schemas/types.yaml#/definitions/flag
> > > > +    description: |
> > > > +      This is a boolean property. If present, the receiving function
> > > > +      will be enabled.
> > > > +
> > > > +  fsl,codec-type:
> > > > +    $ref: /schemas/types.yaml#/definitions/uint32
> > > > +    enum: [0, 1, 2]
> > > > +    default: 0
> > > > +    description: Sometimes the codec is registered by
> > > > +                 driver not by the device tree, this items
> > > > +                 can be used to distinguish codecs.
> > >
> > > How does one decide what value to use?
> >
> > I will add more description:
> > 0: dummy codec
> > 1: WM8960 codec
> > 2: AK4497 codec
>
> I assume the last 2 cases have nodes in DT (pointed to by
> 'audio-codec'), so this is redundant.

Ok, will remove it.

>
> > > > +
> > > > +  audio-codec:
> > > > +    $ref: /schemas/types.yaml#/definitions/phandle
> > > > +    description: The phandle of the audio codec
> > >
> > > The codec is controlled from the Linux side?
> >
> > yes.
> >
> > >
> > > > +
> > > > +  memory-region:
> > > > +    $ref: /schemas/types.yaml#/definitions/phandle
> > > > +    description: phandle to the reserved memory nodes
> > > > +
> > > > +required:
> > > > +  - compatible
> > > > +  - fsl,audioindex
> > > > +  - fsl,version
> > > > +  - fsl,buffer-size
> > > > +
> > > > +additionalProperties: false
> > > > +
> > > > +examples:
> > > > +  - |
> > > > +    rpmsg_audio: rpmsg_audio {
> > > > +        compatible = "fsl,imx8mn-rpmsg";
> > > > +        fsl,audioindex = <0> ;
> > > > +        fsl,version = <2>;
> > > > +        fsl,buffer-size = <0x6000000>;
> > > > +        fsl,enable-lpa;
> > >
> > > How does this work? Don't you need somewhere to put the 'rpmsg' data?
> >
> > The rpmsg data is not handled in this "rpmsg_audio" device, it is just to
> > prepare the resource for rpmsg audio function, the clock, the memory
> > the power...
> >
> > The rpmsg data is handled in imx-pcm-rpmsg.c and imx-audio-rpmsg.c
> > These devices is registered by imx remoteproc driver.
>
> Then what is 'memory-region' for? You need that, a mailbox, or ???
> somewhere in DT.
>
The M core can't access all the DDR memory space on some platform,
so use 'memory-region' reserve a specific memory for dma buffer
which M core can access.

best regards
wang shengjiu

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2021-03-11 11:00 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-08 13:22 [PATCH v4 0/6] Add audio driver base on rpmsg on i.MX platform Shengjiu Wang
2021-03-08 13:22 ` [PATCH v4 1/6] ASoC: soc-component: Add snd_soc_pcm_component_ack Shengjiu Wang
2021-03-08 13:22 ` [PATCH v4 2/6] ASoC: fsl_rpmsg: Add CPU DAI driver for audio base on rpmsg Shengjiu Wang
2021-03-08 22:37   ` kernel test robot
2021-03-08 13:22 ` [PATCH v4 3/6] ASoC: dt-bindings: fsl_rpmsg: Add binding doc for rpmsg cpu dai driver Shengjiu Wang
2021-03-10  2:48   ` Rob Herring
2021-03-10 13:33     ` Shengjiu Wang
2021-03-10 21:12       ` Rob Herring
2021-03-11 10:58         ` Shengjiu Wang
2021-03-08 13:22 ` [PATCH v4 4/6] ASoC: imx-audio-rpmsg: Add rpmsg_driver for audio channel Shengjiu Wang
2021-03-08 13:22 ` [PATCH v4 5/6] ASoC: imx-pcm-rpmsg: Add platform driver for audio base on rpmsg Shengjiu Wang
2021-03-08 13:22 ` [PATCH v4 6/6] ASoC: imx-rpmsg: Add machine " Shengjiu Wang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).