All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops
@ 2022-06-09  3:26 Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 01/23] ASoC: SOF: Add topology tokens for IPC4 Ranjani Sridharan
                   ` (23 more replies)
  0 siblings, 24 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel; +Cc: tiwai, broonie, Ranjani Sridharan

This set of patches includes changes to add the topology, control and
PCM ops for IPC4. It also includes a couple of patches to set the IPC4
BE DAI trigger ops for SSP/DMIC/HDA type DAI's.

Bard Liao (1):
  ASoC: SOF: IPC4: add sdw blob

Ranjani Sridharan (22):
  ASoC: SOF: Add topology tokens for IPC4
  ASoC: SOF: IPC4: Introduce topology ops
  ASoC: SOF: ipc4-topology: Add support for parsing AIF_IN/AIF_OUT
    widgets
  ASoC: SOF: ipc4-topology: Add support for parsing DAI_IN/DAI_OUT
    widgets
  ASoC: SOF: ipc4-topology: Add prepare op for AIF type widgets
  ASoC: SOF: ipc4-topology: Add prepare op for DAI type widgets
  ASoC: SOF: ipc4-topology: Add support for parsing and preparing pga
    widgets
  ASoC: SOF: ipc4-topology: Add support for parsing mixer widgets
  ASoC: SOF: ipc4-topology: Add control_setup op
  ASoC: SOF: ipc4-topology: Add control IO ops
  ASoC: SOF: IPC4: Add pcm ops
  ASoC: SOF: ipc4-topology: Add widget_setup/widget_free ops
  ASoC: SOF: ipc4-topology: Add route_setup/route_free ops
  ASoC: SOF: ipc4-topology: Add the dai_config op
  ASoC: SOF: ipc4-pcm: Expose sof_ipc4_set_pipeline_state()
  ASoC: SOF: IPC4: set the BE DAI ops
  ASoC: SOF: Add ops_free
  ASoC: SOF: Intel: hda: init NHLT for IPC4
  ASoC: SOF: Add two new structures for topology manifest data
  ASoC: SOF: Add a new IPC op for parsing topology manifest
  ASoC: SOF: ipc4-topology: Add support for SSP/DMIC DAI's
  AsoC: SOF: ipc4-topology: Add dai_get_clk op

 include/sound/sof.h             |    1 +
 include/uapi/sound/sof/abi.h    |    2 +
 include/uapi/sound/sof/header.h |   30 +
 include/uapi/sound/sof/tokens.h |   40 +
 sound/soc/sof/Makefile          |    2 +-
 sound/soc/sof/core.c            |    7 +-
 sound/soc/sof/intel/hda-dai.c   |  201 +++-
 sound/soc/sof/intel/hda.h       |    1 +
 sound/soc/sof/intel/pci-apl.c   |    1 +
 sound/soc/sof/intel/pci-cnl.c   |    1 +
 sound/soc/sof/intel/pci-icl.c   |    1 +
 sound/soc/sof/intel/pci-tgl.c   |    1 +
 sound/soc/sof/ipc3-topology.c   |   48 +
 sound/soc/sof/ipc4-control.c    |  216 ++++
 sound/soc/sof/ipc4-pcm.c        |  230 +++++
 sound/soc/sof/ipc4-priv.h       |    7 +
 sound/soc/sof/ipc4-topology.c   | 1702 +++++++++++++++++++++++++++++++
 sound/soc/sof/ipc4-topology.h   |  234 +++++
 sound/soc/sof/ipc4.c            |    2 +
 sound/soc/sof/ops.h             |    6 +
 sound/soc/sof/sof-audio.h       |   11 +
 sound/soc/sof/topology.c        |  114 +--
 22 files changed, 2794 insertions(+), 64 deletions(-)
 create mode 100644 sound/soc/sof/ipc4-control.c
 create mode 100644 sound/soc/sof/ipc4-pcm.c
 create mode 100644 sound/soc/sof/ipc4-topology.c
 create mode 100644 sound/soc/sof/ipc4-topology.h

-- 
2.25.1


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

* [PATCH 01/23] ASoC: SOF: Add topology tokens for IPC4
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 02/23] ASoC: SOF: IPC4: Introduce topology ops Ranjani Sridharan
                   ` (22 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Péter Ujfalusi, Pierre-Louis Bossart,
	Ranjani Sridharan, broonie, Bard Liao, Rander Wang

Add the required tokens for parsing the topology for IPC4.

Co-developed-by: Rander Wang <rander.wang@linux.intel.com>
Signed-off-by: Rander Wang <rander.wang@linux.intel.com>
Co-developed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
---
 include/uapi/sound/sof/tokens.h | 40 +++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h
index b72fa385bebf..f7b2019065ad 100644
--- a/include/uapi/sound/sof/tokens.h
+++ b/include/uapi/sound/sof/tokens.h
@@ -52,11 +52,17 @@
 #define SOF_TKN_SCHED_FRAMES			204
 #define SOF_TKN_SCHED_TIME_DOMAIN		205
 #define SOF_TKN_SCHED_DYNAMIC_PIPELINE		206
+#define SOF_TKN_SCHED_LP_MODE			207
+#define SOF_TKN_SCHED_MEM_USAGE			208
 
 /* volume */
 #define SOF_TKN_VOLUME_RAMP_STEP_TYPE		250
 #define SOF_TKN_VOLUME_RAMP_STEP_MS		251
 
+#define SOF_TKN_GAIN_RAMP_TYPE			260
+#define SOF_TKN_GAIN_RAMP_DURATION		261
+#define SOF_TKN_GAIN_VAL			262
+
 /* SRC */
 #define SOF_TKN_SRC_RATE_IN			300
 #define SOF_TKN_SRC_RATE_OUT			301
@@ -79,6 +85,9 @@
  */
 #define SOF_TKN_COMP_CORE_ID			404
 #define SOF_TKN_COMP_UUID                       405
+#define SOF_TKN_COMP_CPC			406
+#define SOF_TKN_COMP_IS_PAGES			409
+#define SOF_TKN_COMP_NUM_AUDIO_FORMATS		410
 
 /* SSP */
 #define SOF_TKN_INTEL_SSP_CLKS_CONTROL		500
@@ -145,4 +154,35 @@
 #define SOF_TKN_MEDIATEK_AFE_CH			1601
 #define SOF_TKN_MEDIATEK_AFE_FORMAT		1602
 
+/* MIXER */
+#define SOF_TKN_MIXER_TYPE			1700
+
+/* CAVS AUDIO FORMAT */
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_RATE	1900
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_BIT_DEPTH	1901
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_VALID_BIT	1902
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_CHANNELS	1903
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_MAP	1904
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_CFG	1905
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_INTERLEAVING_STYLE	1906
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_FMT_CFG	1907
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IN_SAMPLE_TYPE	1908
+/* intentional token numbering discontinuity, reserved for future use */
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_RATE	1930
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_BIT_DEPTH	1931
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_VALID_BIT	1932
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CHANNELS	1933
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_MAP	1934
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_CFG	1935
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_INTERLEAVING_STYLE	1936
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_FMT_CFG	1937
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OUT_SAMPLE_TYPE	1938
+/* intentional token numbering discontinuity, reserved for future use */
+#define SOF_TKN_CAVS_AUDIO_FORMAT_IBS		1970
+#define SOF_TKN_CAVS_AUDIO_FORMAT_OBS		1971
+#define SOF_TKN_CAVS_AUDIO_FORMAT_DMA_BUFFER_SIZE	1972
+
+/* COPIER */
+#define SOF_TKN_INTEL_COPIER_NODE_TYPE		1980
+
 #endif
-- 
2.25.1


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

* [PATCH 02/23] ASoC: SOF: IPC4: Introduce topology ops
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 01/23] ASoC: SOF: Add topology tokens for IPC4 Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 03/23] ASoC: SOF: ipc4-topology: Add support for parsing AIF_IN/AIF_OUT widgets Ranjani Sridharan
                   ` (21 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Bard Liao, Ranjani Sridharan, Pierre-Louis Bossart,
	broonie, Paul Olaru, Péter Ujfalusi, Rander Wang

Introduce the topology ops for IPC4. Set the widget_ops and token_list
for parsing the scheduler type widget. Support for other widget types
will be added in the follow up patches.

Co-developed-by: Rander Wang <rander.wang@linux.intel.com>
Signed-off-by: Rander Wang <rander.wang@linux.intel.com>
Co-developed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Paul Olaru <paul.olaru@oss.nxp.com>
---
 sound/soc/sof/Makefile        |   2 +-
 sound/soc/sof/ipc4-priv.h     |   1 +
 sound/soc/sof/ipc4-topology.c | 102 ++++++++++++++++++++++++++++++++++
 sound/soc/sof/ipc4-topology.h |  30 ++++++++++
 sound/soc/sof/ipc4.c          |   1 +
 5 files changed, 135 insertions(+), 1 deletion(-)
 create mode 100644 sound/soc/sof/ipc4-topology.c
 create mode 100644 sound/soc/sof/ipc4-topology.h

diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile
index 92b5e83601be..73524fadb3ce 100644
--- a/sound/soc/sof/Makefile
+++ b/sound/soc/sof/Makefile
@@ -4,7 +4,7 @@ snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
 		control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o\
 		ipc3-topology.o ipc3-control.o ipc3.o ipc3-pcm.o ipc3-loader.o\
 		ipc3-dtrace.o\
-		ipc4.o ipc4-loader.o
+		ipc4.o ipc4-loader.o ipc4-topology.o
 ifneq ($(CONFIG_SND_SOC_SOF_CLIENT),)
 snd-sof-objs += sof-client.o
 endif
diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h
index 2b71d5675933..5388b888fefa 100644
--- a/sound/soc/sof/ipc4-priv.h
+++ b/sound/soc/sof/ipc4-priv.h
@@ -40,5 +40,6 @@ struct sof_ipc4_fw_module {
 };
 
 extern const struct sof_ipc_fw_loader_ops ipc4_loader_ops;
+extern const struct sof_ipc_tplg_ops ipc4_tplg_ops;
 
 #endif
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
new file mode 100644
index 000000000000..bccf576c8edd
--- /dev/null
+++ b/sound/soc/sof/ipc4-topology.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license.  When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2022 Intel Corporation. All rights reserved.
+//
+//
+#include <uapi/sound/sof/tokens.h>
+#include <sound/pcm_params.h>
+#include <sound/sof/ext_manifest4.h>
+#include "sof-priv.h"
+#include "sof-audio.h"
+#include "ipc4-priv.h"
+#include "ipc4-topology.h"
+#include "ops.h"
+
+static const struct sof_topology_token ipc4_sched_tokens[] = {
+	{SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+		offsetof(struct sof_ipc4_pipeline, lp_mode)}
+};
+
+static const struct sof_topology_token pipeline_tokens[] = {
+	{SOF_TKN_SCHED_DYNAMIC_PIPELINE, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
+		offsetof(struct snd_sof_widget, dynamic_pipeline_widget)},
+};
+
+static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
+	[SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)},
+	[SOF_SCHED_TOKENS] = {"Scheduler tokens", ipc4_sched_tokens,
+		ARRAY_SIZE(ipc4_sched_tokens)},
+};
+
+static void sof_ipc4_widget_free_comp(struct snd_sof_widget *swidget)
+{
+	kfree(swidget->private);
+}
+
+static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
+{
+	struct snd_soc_component *scomp = swidget->scomp;
+	struct sof_ipc4_pipeline *pipeline;
+	int ret;
+
+	pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL);
+	if (!pipeline)
+		return -ENOMEM;
+
+	ret = sof_update_ipc_object(scomp, pipeline, SOF_SCHED_TOKENS, swidget->tuples,
+				    swidget->num_tuples, sizeof(*pipeline), 1);
+	if (ret) {
+		dev_err(scomp->dev, "parsing scheduler tokens failed\n");
+		goto err;
+	}
+
+	/* parse one set of pipeline tokens */
+	ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples,
+				    swidget->num_tuples, sizeof(*swidget), 1);
+	if (ret) {
+		dev_err(scomp->dev, "parsing pipeline tokens failed\n");
+		goto err;
+	}
+
+	/* TODO: Get priority from topology */
+	pipeline->priority = 0;
+
+	dev_dbg(scomp->dev, "pipeline '%s': id %d pri %d lp mode %d\n",
+		swidget->widget->name, swidget->pipeline_id,
+		pipeline->priority, pipeline->lp_mode);
+
+	swidget->private = pipeline;
+
+	pipeline->msg.primary = SOF_IPC4_GLB_PIPE_PRIORITY(pipeline->priority);
+	pipeline->msg.primary |= SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->pipeline_id);
+	pipeline->msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CREATE_PIPELINE);
+	pipeline->msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+	pipeline->msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
+
+	pipeline->msg.extension = pipeline->lp_mode;
+	pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
+
+	return 0;
+err:
+	kfree(pipeline);
+	return ret;
+}
+
+static enum sof_tokens pipeline_token_list[] = {
+	SOF_SCHED_TOKENS,
+	SOF_PIPELINE_TOKENS,
+};
+
+static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
+	[snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline, sof_ipc4_widget_free_comp,
+				    pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL,
+				    NULL, NULL},
+};
+
+const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
+	.widget = tplg_ipc4_widget_ops,
+	.token_list = ipc4_token_list,
+};
diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h
new file mode 100644
index 000000000000..0e9be2b2d8a1
--- /dev/null
+++ b/sound/soc/sof/ipc4-topology.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * Copyright(c) 2022 Intel Corporation. All rights reserved.
+ */
+
+#ifndef __INCLUDE_SOUND_SOF_IPC4_TOPOLOGY_H__
+#define __INCLUDE_SOUND_SOF_IPC4_TOPOLOGY_H__
+
+#include <sound/sof/ipc4/header.h>
+
+/**
+ * struct sof_ipc4_pipeline - pipeline config data
+ * @priority: Priority of this pipeline
+ * @lp_mode: Low power mode
+ * @mem_usage: Memory usage
+ * @state: Pipeline state
+ * @msg: message structure for pipeline
+ */
+struct sof_ipc4_pipeline {
+	uint32_t priority;
+	uint32_t lp_mode;
+	uint32_t mem_usage;
+	int state;
+	struct sof_ipc4_msg msg;
+};
+
+#endif
diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c
index 658802c86685..be677a33882d 100644
--- a/sound/soc/sof/ipc4.c
+++ b/sound/soc/sof/ipc4.c
@@ -603,4 +603,5 @@ const struct sof_ipc_ops ipc4_ops = {
 	.set_get_data = sof_ipc4_set_get_data,
 	.get_reply = sof_ipc4_get_reply,
 	.fw_loader = &ipc4_loader_ops,
+	.tplg = &ipc4_tplg_ops,
 };
-- 
2.25.1


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

* [PATCH 03/23] ASoC: SOF: ipc4-topology: Add support for parsing AIF_IN/AIF_OUT widgets
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 01/23] ASoC: SOF: Add topology tokens for IPC4 Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 02/23] ASoC: SOF: IPC4: Introduce topology ops Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 04/23] ASoC: SOF: ipc4-topology: Add support for parsing DAI_IN/DAI_OUT widgets Ranjani Sridharan
                   ` (20 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Bard Liao, Ranjani Sridharan, Pierre-Louis Bossart,
	broonie, Paul Olaru, Péter Ujfalusi, Rander Wang

Add support for parsing AIF_IN/AIF_OUT type widgets in IPC4. Add all the
new required token ID's for parsing these widgets to the list of tokens in
enum sof_tokens and the definitions of the token arrays corresponding to
each of the token ID's.

Also, upgrade the sof_widget_parse_tokens() function in the common
topology parser to be able to parse multiple sets of tokens for the
audio format and copier gateway config tokens.

Co-developed-by: Rander Wang <rander.wang@linux.intel.com>
Signed-off-by: Rander Wang <rander.wang@linux.intel.com>
Co-developed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Paul Olaru <paul.olaru@oss.nxp.com>
---
 sound/soc/sof/ipc4-topology.c | 370 ++++++++++++++++++++++++++++++++++
 sound/soc/sof/ipc4-topology.h |  83 ++++++++
 sound/soc/sof/sof-audio.h     |   7 +
 sound/soc/sof/topology.c      |  69 +++++--
 4 files changed, 511 insertions(+), 18 deletions(-)

diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index bccf576c8edd..559148f5644c 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -25,17 +25,370 @@ static const struct sof_topology_token pipeline_tokens[] = {
 		offsetof(struct snd_sof_widget, dynamic_pipeline_widget)},
 };
 
+static const struct sof_topology_token ipc4_comp_tokens[] = {
+	{SOF_TKN_COMP_CPC, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+		offsetof(struct sof_ipc4_base_module_cfg, cpc)},
+	{SOF_TKN_COMP_IS_PAGES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+		offsetof(struct sof_ipc4_base_module_cfg, is_pages)},
+};
+
+static const struct sof_topology_token ipc4_audio_format_buffer_size_tokens[] = {
+	{SOF_TKN_CAVS_AUDIO_FORMAT_IBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+		offsetof(struct sof_ipc4_base_module_cfg, ibs)},
+	{SOF_TKN_CAVS_AUDIO_FORMAT_OBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+		offsetof(struct sof_ipc4_base_module_cfg, obs)},
+};
+
+static const struct sof_topology_token ipc4_in_audio_format_tokens[] = {
+	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+		offsetof(struct sof_ipc4_audio_format, sampling_frequency)},
+	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+		offsetof(struct sof_ipc4_audio_format, bit_depth)},
+	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+		offsetof(struct sof_ipc4_audio_format, ch_map)},
+	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+		offsetof(struct sof_ipc4_audio_format, ch_cfg)},
+	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
+		get_token_u32, offsetof(struct sof_ipc4_audio_format, interleaving_style)},
+	{SOF_TKN_CAVS_AUDIO_FORMAT_IN_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+		offsetof(struct sof_ipc4_audio_format, fmt_cfg)},
+};
+
+static const struct sof_topology_token ipc4_out_audio_format_tokens[] = {
+	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+		offsetof(struct sof_ipc4_audio_format, sampling_frequency)},
+	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+		offsetof(struct sof_ipc4_audio_format, bit_depth)},
+	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+		offsetof(struct sof_ipc4_audio_format, ch_map)},
+	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+		offsetof(struct sof_ipc4_audio_format, ch_cfg)},
+	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
+		get_token_u32, offsetof(struct sof_ipc4_audio_format, interleaving_style)},
+	{SOF_TKN_CAVS_AUDIO_FORMAT_OUT_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+		offsetof(struct sof_ipc4_audio_format, fmt_cfg)},
+};
+
+static const struct sof_topology_token ipc4_copier_gateway_cfg_tokens[] = {
+	{SOF_TKN_CAVS_AUDIO_FORMAT_DMA_BUFFER_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0},
+};
+
+static const struct sof_topology_token ipc4_copier_tokens[] = {
+	{SOF_TKN_INTEL_COPIER_NODE_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0},
+};
+
+static const struct sof_topology_token ipc4_audio_fmt_num_tokens[] = {
+	{SOF_TKN_COMP_NUM_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+		0},
+};
+
+/* Component extended tokens */
+static const struct sof_topology_token comp_ext_tokens[] = {
+	{SOF_TKN_COMP_UUID, SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid,
+		offsetof(struct snd_sof_widget, uuid)},
+};
+
 static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
 	[SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)},
 	[SOF_SCHED_TOKENS] = {"Scheduler tokens", ipc4_sched_tokens,
 		ARRAY_SIZE(ipc4_sched_tokens)},
+	[SOF_COMP_EXT_TOKENS] = {"Comp extended tokens", comp_ext_tokens,
+		ARRAY_SIZE(comp_ext_tokens)},
+	[SOF_COMP_TOKENS] = {"IPC4 Component tokens",
+		ipc4_comp_tokens, ARRAY_SIZE(ipc4_comp_tokens)},
+	[SOF_IN_AUDIO_FORMAT_TOKENS] = {"IPC4 Input Audio format tokens",
+		ipc4_in_audio_format_tokens, ARRAY_SIZE(ipc4_in_audio_format_tokens)},
+	[SOF_OUT_AUDIO_FORMAT_TOKENS] = {"IPC4 Output Audio format tokens",
+		ipc4_out_audio_format_tokens, ARRAY_SIZE(ipc4_out_audio_format_tokens)},
+	[SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS] = {"IPC4 Audio format buffer size tokens",
+		ipc4_audio_format_buffer_size_tokens,
+		ARRAY_SIZE(ipc4_audio_format_buffer_size_tokens)},
+	[SOF_COPIER_GATEWAY_CFG_TOKENS] = {"IPC4 Copier gateway config tokens",
+		ipc4_copier_gateway_cfg_tokens, ARRAY_SIZE(ipc4_copier_gateway_cfg_tokens)},
+	[SOF_COPIER_TOKENS] = {"IPC4 Copier tokens", ipc4_copier_tokens,
+		ARRAY_SIZE(ipc4_copier_tokens)},
+	[SOF_AUDIO_FMT_NUM_TOKENS] = {"IPC4 Audio format number tokens",
+		ipc4_audio_fmt_num_tokens, ARRAY_SIZE(ipc4_audio_fmt_num_tokens)},
 };
 
+static void sof_ipc4_dbg_audio_format(struct device *dev,
+				      struct sof_ipc4_audio_format *format,
+				      size_t object_size, int num_format)
+{
+	struct sof_ipc4_audio_format *fmt;
+	void *ptr = format;
+	int i;
+
+	for (i = 0; i < num_format; i++, ptr = (u8 *)ptr + object_size) {
+		fmt = ptr;
+		dev_dbg(dev,
+			" #%d: %uKHz, %ubit (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x)\n",
+			i, fmt->sampling_frequency, fmt->bit_depth, fmt->ch_map,
+			fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg);
+	}
+}
+
+/**
+ * sof_ipc4_get_audio_fmt - get available audio formats from swidget->tuples
+ * @scomp: pointer to pointer to SOC component
+ * @swidget: pointer to struct snd_sof_widget containing tuples
+ * @available_fmt: pointer to struct sof_ipc4_available_audio_format being filling in
+ * @has_out_format: true if available_fmt contains output format
+ *
+ * Return: 0 if successful
+ */
+static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp,
+				  struct snd_sof_widget *swidget,
+				  struct sof_ipc4_available_audio_format *available_fmt,
+				  bool has_out_format)
+{
+	struct sof_ipc4_base_module_cfg *base_config;
+	struct sof_ipc4_audio_format *out_format;
+	int audio_fmt_num = 0;
+	int ret, i;
+
+	ret = sof_update_ipc_object(scomp, &audio_fmt_num,
+				    SOF_AUDIO_FMT_NUM_TOKENS, swidget->tuples,
+				    swidget->num_tuples, sizeof(audio_fmt_num), 1);
+	if (ret || audio_fmt_num <= 0) {
+		dev_err(scomp->dev, "Invalid number of audio formats: %d\n", audio_fmt_num);
+		return -EINVAL;
+	}
+	available_fmt->audio_fmt_num = audio_fmt_num;
+
+	dev_dbg(scomp->dev, "Number of audio formats: %d\n", available_fmt->audio_fmt_num);
+
+	base_config = kcalloc(available_fmt->audio_fmt_num, sizeof(*base_config), GFP_KERNEL);
+	if (!base_config)
+		return -ENOMEM;
+
+	/* set cpc and is_pages for all base_cfg */
+	for (i = 0; i < available_fmt->audio_fmt_num; i++) {
+		ret = sof_update_ipc_object(scomp, &base_config[i],
+					    SOF_COMP_TOKENS, swidget->tuples,
+					    swidget->num_tuples, sizeof(*base_config), 1);
+		if (ret) {
+			dev_err(scomp->dev, "parse comp tokens failed %d\n", ret);
+			goto err_in;
+		}
+	}
+
+	/* copy the ibs/obs for each base_cfg */
+	ret = sof_update_ipc_object(scomp, base_config,
+				    SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, swidget->tuples,
+				    swidget->num_tuples, sizeof(*base_config),
+				    available_fmt->audio_fmt_num);
+	if (ret) {
+		dev_err(scomp->dev, "parse buffer size tokens failed %d\n", ret);
+		goto err_in;
+	}
+
+	for (i = 0; i < available_fmt->audio_fmt_num; i++)
+		dev_dbg(scomp->dev, "%d: ibs: %d obs: %d cpc: %d is_pages: %d\n", i,
+			base_config[i].ibs, base_config[i].obs,
+			base_config[i].cpc, base_config[i].is_pages);
+
+	ret = sof_update_ipc_object(scomp, &base_config->audio_fmt,
+				    SOF_IN_AUDIO_FORMAT_TOKENS, swidget->tuples,
+				    swidget->num_tuples, sizeof(*base_config),
+				    available_fmt->audio_fmt_num);
+	if (ret) {
+		dev_err(scomp->dev, "parse base_config audio_fmt tokens failed %d\n", ret);
+		goto err_in;
+	}
+
+	dev_dbg(scomp->dev, "Get input audio formats for %s\n", swidget->widget->name);
+	sof_ipc4_dbg_audio_format(scomp->dev, &base_config->audio_fmt,
+				  sizeof(*base_config),
+				  available_fmt->audio_fmt_num);
+
+	available_fmt->base_config = base_config;
+
+	if (!has_out_format)
+		return 0;
+
+	out_format = kcalloc(available_fmt->audio_fmt_num, sizeof(*out_format), GFP_KERNEL);
+	if (!out_format) {
+		ret = -ENOMEM;
+		goto err_in;
+	}
+
+	ret = sof_update_ipc_object(scomp, out_format,
+				    SOF_OUT_AUDIO_FORMAT_TOKENS, swidget->tuples,
+				    swidget->num_tuples, sizeof(*out_format),
+				    available_fmt->audio_fmt_num);
+
+	if (ret) {
+		dev_err(scomp->dev, "parse output audio_fmt tokens failed\n");
+		goto err_out;
+	}
+
+	available_fmt->out_audio_fmt = out_format;
+	dev_dbg(scomp->dev, "Get output audio formats for %s\n", swidget->widget->name);
+	sof_ipc4_dbg_audio_format(scomp->dev, out_format, sizeof(*out_format),
+				  available_fmt->audio_fmt_num);
+
+	return 0;
+
+err_out:
+	kfree(out_format);
+err_in:
+	kfree(base_config);
+
+	return ret;
+}
+
 static void sof_ipc4_widget_free_comp(struct snd_sof_widget *swidget)
 {
 	kfree(swidget->private);
 }
 
+static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget)
+{
+	struct snd_soc_component *scomp = swidget->scomp;
+	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+	struct sof_ipc4_fw_module *fw_modules = ipc4_data->fw_modules;
+	int i;
+
+	if (!fw_modules) {
+		dev_err(sdev->dev, "no fw_module information\n");
+		return -EINVAL;
+	}
+
+	/* set module info */
+	for (i = 0; i < ipc4_data->num_fw_modules; i++) {
+		if (guid_equal(&swidget->uuid, &fw_modules[i].man4_module_entry.uuid)) {
+			swidget->module_info = &fw_modules[i];
+			return 0;
+		}
+	}
+
+	dev_err(sdev->dev, "failed to find module info for widget %s with UUID %pUL\n",
+		swidget->widget->name, &swidget->uuid);
+	return -EINVAL;
+}
+
+static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ipc4_msg *msg)
+{
+	struct sof_ipc4_fw_module *fw_module;
+	int ret;
+
+	ret = sof_ipc4_widget_set_module_info(swidget);
+	if (ret)
+		return ret;
+
+	fw_module = swidget->module_info;
+
+	msg->primary = fw_module->man4_module_entry.id;
+	msg->primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_INIT_INSTANCE);
+	msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+	msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+
+	msg->extension = SOF_IPC4_MOD_EXT_PPL_ID(swidget->pipeline_id);
+	msg->extension |= SOF_IPC4_MOD_EXT_CORE_ID(swidget->core);
+
+	return 0;
+}
+
+static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
+{
+	struct sof_ipc4_available_audio_format *available_fmt;
+	struct snd_soc_component *scomp = swidget->scomp;
+	struct sof_ipc4_copier *ipc4_copier;
+	int node_type = 0;
+	int ret, i;
+
+	ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL);
+	if (!ipc4_copier)
+		return -ENOMEM;
+
+	swidget->private = ipc4_copier;
+	available_fmt = &ipc4_copier->available_fmt;
+
+	dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
+
+	ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt, true);
+	if (ret)
+		goto free_copier;
+
+	available_fmt->dma_buffer_size = kcalloc(available_fmt->audio_fmt_num, sizeof(u32),
+						 GFP_KERNEL);
+	if (!available_fmt->dma_buffer_size) {
+		ret = -ENOMEM;
+		goto free_copier;
+	}
+
+	ret = sof_update_ipc_object(scomp, available_fmt->dma_buffer_size,
+				    SOF_COPIER_GATEWAY_CFG_TOKENS, swidget->tuples,
+				    swidget->num_tuples, sizeof(u32),
+				    available_fmt->audio_fmt_num);
+	if (ret) {
+		dev_err(scomp->dev, "Failed to parse dma buffer size in audio format for %s\n",
+			swidget->widget->name);
+		goto err;
+	}
+
+	dev_dbg(scomp->dev, "dma buffer size:\n");
+	for (i = 0; i < available_fmt->audio_fmt_num; i++)
+		dev_dbg(scomp->dev, "%d: %u\n", i,
+			available_fmt->dma_buffer_size[i]);
+
+	ret = sof_update_ipc_object(scomp, &node_type,
+				    SOF_COPIER_TOKENS, swidget->tuples,
+				    swidget->num_tuples, sizeof(node_type), 1);
+
+	if (ret) {
+		dev_err(scomp->dev, "parse host copier node type token failed %d\n",
+			ret);
+		goto err;
+	}
+	dev_dbg(scomp->dev, "host copier '%s' node_type %u\n", swidget->widget->name, node_type);
+
+	ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
+	ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL);
+	if (!ipc4_copier->gtw_attr) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr;
+	ipc4_copier->data.gtw_cfg.config_length =
+		sizeof(struct sof_ipc4_gtw_attributes) >> 2;
+
+	/* set up module info and message header */
+	ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg);
+	if (ret)
+		goto free_gtw_attr;
+
+	return 0;
+
+free_gtw_attr:
+	kfree(ipc4_copier->gtw_attr);
+err:
+	kfree(available_fmt->dma_buffer_size);
+free_copier:
+	kfree(ipc4_copier);
+	return ret;
+}
+
+static void sof_ipc4_widget_free_comp_pcm(struct snd_sof_widget *swidget)
+{
+	struct sof_ipc4_copier *ipc4_copier = swidget->private;
+	struct sof_ipc4_available_audio_format *available_fmt;
+
+	if (!ipc4_copier)
+		return;
+
+	available_fmt = &ipc4_copier->available_fmt;
+	kfree(available_fmt->dma_buffer_size);
+	kfree(available_fmt->base_config);
+	kfree(available_fmt->out_audio_fmt);
+	kfree(ipc4_copier->gtw_attr);
+	kfree(ipc4_copier);
+	swidget->private = NULL;
+}
+
 static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
 {
 	struct snd_soc_component *scomp = swidget->scomp;
@@ -85,12 +438,29 @@ static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
 	return ret;
 }
 
+static enum sof_tokens host_token_list[] = {
+	SOF_COMP_TOKENS,
+	SOF_AUDIO_FMT_NUM_TOKENS,
+	SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
+	SOF_IN_AUDIO_FORMAT_TOKENS,
+	SOF_OUT_AUDIO_FORMAT_TOKENS,
+	SOF_COPIER_GATEWAY_CFG_TOKENS,
+	SOF_COPIER_TOKENS,
+	SOF_COMP_EXT_TOKENS,
+};
+
 static enum sof_tokens pipeline_token_list[] = {
 	SOF_SCHED_TOKENS,
 	SOF_PIPELINE_TOKENS,
 };
 
 static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
+	[snd_soc_dapm_aif_in] =  {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
+				  host_token_list, ARRAY_SIZE(host_token_list), NULL,
+				  NULL, NULL},
+	[snd_soc_dapm_aif_out] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
+				  host_token_list, ARRAY_SIZE(host_token_list), NULL,
+				  NULL, NULL},
 	[snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline, sof_ipc4_widget_free_comp,
 				    pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL,
 				    NULL, NULL},
diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h
index 0e9be2b2d8a1..f4f62dda63a3 100644
--- a/sound/soc/sof/ipc4-topology.h
+++ b/sound/soc/sof/ipc4-topology.h
@@ -11,6 +11,8 @@
 
 #include <sound/sof/ipc4/header.h>
 
+#define SOF_IPC4_NODE_TYPE(x)  ((x) << 8)
+
 /**
  * struct sof_ipc4_pipeline - pipeline config data
  * @priority: Priority of this pipeline
@@ -27,4 +29,85 @@ struct sof_ipc4_pipeline {
 	struct sof_ipc4_msg msg;
 };
 
+/**
+ * struct sof_ipc4_available_audio_format - Available audio formats
+ * @base_config: Available base config
+ * @out_audio_fmt: Available output audio format
+ * @ref_audio_fmt: Reference audio format to match runtime audio format
+ * @dma_buffer_size: Available Gateway DMA buffer size (in bytes)
+ * @audio_fmt_num: Number of available audio formats
+ */
+struct sof_ipc4_available_audio_format {
+	struct sof_ipc4_base_module_cfg *base_config;
+	struct sof_ipc4_audio_format *out_audio_fmt;
+	struct sof_ipc4_audio_format *ref_audio_fmt;
+	u32 *dma_buffer_size;
+	int audio_fmt_num;
+};
+
+/**
+ * struct sof_copier_gateway_cfg - IPC gateway configuration
+ * @node_id: ID of Gateway Node
+ * @dma_buffer_size: Preferred Gateway DMA buffer size (in bytes)
+ * @config_length: Length of gateway node configuration blob specified in #config_data
+ * config_data: Gateway node configuration blob
+ */
+struct sof_copier_gateway_cfg {
+	uint32_t node_id;
+	uint32_t dma_buffer_size;
+	uint32_t config_length;
+	uint32_t config_data[];
+};
+
+/**
+ * struct sof_ipc4_copier_data - IPC data for copier
+ * @base_config: Base configuration including input audio format
+ * @out_format: Output audio format
+ * @copier_feature_mask: Copier feature mask
+ * @gtw_cfg: Gateway configuration
+ */
+struct sof_ipc4_copier_data {
+	struct sof_ipc4_base_module_cfg base_config;
+	struct sof_ipc4_audio_format out_format;
+	uint32_t copier_feature_mask;
+	struct sof_copier_gateway_cfg gtw_cfg;
+};
+
+/**
+ * struct sof_ipc4_gtw_attributes: Gateway attributes
+ * @lp_buffer_alloc: Gateway data requested in low power memory
+ * @alloc_from_reg_file: Gateway data requested in register file memory
+ * @rsvd: reserved for future use
+ */
+struct sof_ipc4_gtw_attributes {
+	uint32_t lp_buffer_alloc : 1;
+	uint32_t alloc_from_reg_file : 1;
+	uint32_t rsvd : 30;
+};
+
+/**
+ * struct sof_ipc4_copier - copier config data
+ * @data: IPC copier data
+ * @copier_config: Copier + blob
+ * @ipc_config_size: Size of copier_config
+ * @available_fmt: Available audio format
+ * @frame_fmt: frame format
+ * @msg: message structure for copier
+ * @gtw_attr: Gateway attributes for copier blob
+ * @dai_type: DAI type
+ * @dai_index: DAI index
+ */
+struct sof_ipc4_copier {
+	struct sof_ipc4_copier_data data;
+	u32 *copier_config;
+	uint32_t ipc_config_size;
+	void *ipc_config_data;
+	struct sof_ipc4_available_audio_format available_fmt;
+	u32 frame_fmt;
+	struct sof_ipc4_msg msg;
+	struct sof_ipc4_gtw_attributes *gtw_attr;
+	u32 dai_type;
+	int dai_index;
+};
+
 #endif
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h
index 27cc5fb642e5..c38b4bdd685a 100644
--- a/sound/soc/sof/sof-audio.h
+++ b/sound/soc/sof/sof-audio.h
@@ -225,6 +225,13 @@ enum sof_tokens {
 	SOF_AFE_TOKENS,
 	SOF_CORE_TOKENS,
 	SOF_COMP_EXT_TOKENS,
+	SOF_IN_AUDIO_FORMAT_TOKENS,
+	SOF_OUT_AUDIO_FORMAT_TOKENS,
+	SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
+	SOF_COPIER_GATEWAY_CFG_TOKENS,
+	SOF_COPIER_TOKENS,
+	SOF_AUDIO_FMT_NUM_TOKENS,
+	SOF_COPIER_FORMAT_TOKENS,
 
 	/* this should be the last */
 	SOF_TOKEN_COUNT,
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index b1fcab7ce48e..606dbca94246 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -1141,6 +1141,21 @@ static int spcm_bind(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm,
 	return 0;
 }
 
+static int sof_get_token_value(u32 token_id, struct snd_sof_tuple *tuples, int num_tuples)
+{
+	int i;
+
+	if (!tuples)
+		return -EINVAL;
+
+	for (i = 0; i < num_tuples; i++) {
+		if (tuples[i].token == token_id)
+			return tuples[i].value.v;
+	}
+
+	return -EINVAL;
+}
+
 static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_sof_widget *swidget,
 				   struct snd_soc_tplg_dapm_widget *tw,
 				   enum sof_tokens *object_token_list, int count)
@@ -1168,6 +1183,8 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s
 
 	/* parse token list for widget */
 	for (i = 0; i < count; i++) {
+		int num_sets = 1;
+
 		if (object_token_list[i] >= SOF_TOKEN_COUNT) {
 			dev_err(scomp->dev, "Invalid token id %d for widget %s\n",
 				object_token_list[i], swidget->widget->name);
@@ -1175,8 +1192,9 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s
 			goto err;
 		}
 
-		/* parse and save UUID in swidget */
-		if (object_token_list[i] == SOF_COMP_EXT_TOKENS) {
+		switch (object_token_list[i]) {
+		case SOF_COMP_EXT_TOKENS:
+			/* parse and save UUID in swidget */
 			ret = sof_parse_tokens(scomp, swidget,
 					       token_list[object_token_list[i]].tokens,
 					       token_list[object_token_list[i]].count,
@@ -1189,11 +1207,41 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s
 			}
 
 			continue;
+		case SOF_IN_AUDIO_FORMAT_TOKENS:
+		case SOF_OUT_AUDIO_FORMAT_TOKENS:
+		case SOF_COPIER_GATEWAY_CFG_TOKENS:
+		case SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS:
+			num_sets = sof_get_token_value(SOF_TKN_COMP_NUM_AUDIO_FORMATS,
+						       swidget->tuples, swidget->num_tuples);
+
+			if (num_sets < 0) {
+				dev_err(sdev->dev, "Invalid audio format count for %s\n",
+					swidget->widget->name);
+				ret = num_sets;
+				goto err;
+			}
+
+			if (num_sets > 1) {
+				struct snd_sof_tuple *new_tuples;
+
+				num_tuples += token_list[object_token_list[i]].count * num_sets;
+				new_tuples = krealloc(swidget->tuples,
+						      sizeof(*new_tuples) * num_tuples, GFP_KERNEL);
+				if (!new_tuples) {
+					ret = -ENOMEM;
+					goto err;
+				}
+
+				swidget->tuples = new_tuples;
+			}
+			break;
+		default:
+			break;
 		}
 
 		/* copy one set of tuples per token ID into swidget->tuples */
 		ret = sof_copy_tuples(sdev, private->array, le32_to_cpu(private->size),
-				      object_token_list[i], 1, swidget->tuples,
+				      object_token_list[i], num_sets, swidget->tuples,
 				      num_tuples, &swidget->num_tuples);
 		if (ret < 0) {
 			dev_err(scomp->dev, "Failed parsing %s for widget %s err: %d\n",
@@ -1208,21 +1256,6 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s
 	return ret;
 }
 
-static int sof_get_token_value(u32 token_id, struct snd_sof_tuple *tuples, int num_tuples)
-{
-	int i;
-
-	if (!tuples)
-		return -EINVAL;
-
-	for (i = 0; i < num_tuples; i++) {
-		if (tuples[i].token == token_id)
-			return tuples[i].value.v;
-	}
-
-	return -EINVAL;
-}
-
 /* external widget init - used for any driver specific init */
 static int sof_widget_ready(struct snd_soc_component *scomp, int index,
 			    struct snd_soc_dapm_widget *w,
-- 
2.25.1


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

* [PATCH 04/23] ASoC: SOF: ipc4-topology: Add support for parsing DAI_IN/DAI_OUT widgets
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
                   ` (2 preceding siblings ...)
  2022-06-09  3:26 ` [PATCH 03/23] ASoC: SOF: ipc4-topology: Add support for parsing AIF_IN/AIF_OUT widgets Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 05/23] ASoC: SOF: ipc4-topology: Add prepare op for AIF type widgets Ranjani Sridharan
                   ` (19 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Bard Liao, Ranjani Sridharan, Pierre-Louis Bossart,
	broonie, Péter Ujfalusi, Rander Wang

Add support for parsing and setting up the IPC structure for
DAI_IN/DAI_OUT type widgets in IPC4.

Co-developed-by: Rander Wang <rander.wang@linux.intel.com>
Signed-off-by: Rander Wang <rander.wang@linux.intel.com>
Co-developed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
---
 sound/soc/sof/ipc4-topology.c | 135 ++++++++++++++++++++++++++++++++++
 1 file changed, 135 insertions(+)

diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 559148f5644c..5bb80306794b 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -82,6 +82,13 @@ static const struct sof_topology_token ipc4_audio_fmt_num_tokens[] = {
 		0},
 };
 
+static const struct sof_topology_token dai_tokens[] = {
+	{SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type,
+		offsetof(struct sof_ipc4_copier, dai_type)},
+	{SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+		offsetof(struct sof_ipc4_copier, dai_index)},
+};
+
 /* Component extended tokens */
 static const struct sof_topology_token comp_ext_tokens[] = {
 	{SOF_TKN_COMP_UUID, SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid,
@@ -89,6 +96,7 @@ static const struct sof_topology_token comp_ext_tokens[] = {
 };
 
 static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
+	[SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)},
 	[SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)},
 	[SOF_SCHED_TOKENS] = {"Scheduler tokens", ipc4_sched_tokens,
 		ARRAY_SIZE(ipc4_sched_tokens)},
@@ -389,6 +397,117 @@ static void sof_ipc4_widget_free_comp_pcm(struct snd_sof_widget *swidget)
 	swidget->private = NULL;
 }
 
+static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
+{
+	struct sof_ipc4_available_audio_format *available_fmt;
+	struct snd_soc_component *scomp = swidget->scomp;
+	struct snd_sof_dai *dai = swidget->private;
+	struct sof_ipc4_copier *ipc4_copier;
+	int node_type = 0;
+	int ret, i;
+
+	ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL);
+	if (!ipc4_copier)
+		return -ENOMEM;
+
+	available_fmt = &ipc4_copier->available_fmt;
+
+	dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
+
+	ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt, true);
+	if (ret)
+		goto free_copier;
+
+	available_fmt->dma_buffer_size = kcalloc(available_fmt->audio_fmt_num, sizeof(u32),
+						 GFP_KERNEL);
+	if (!available_fmt->dma_buffer_size) {
+		ret = -ENOMEM;
+		goto free_copier;
+	}
+
+	ret = sof_update_ipc_object(scomp, available_fmt->dma_buffer_size,
+				    SOF_COPIER_GATEWAY_CFG_TOKENS, swidget->tuples,
+				    swidget->num_tuples, sizeof(u32),
+				    available_fmt->audio_fmt_num);
+	if (ret) {
+		dev_err(scomp->dev, "Failed to parse dma buffer size in audio format for %s\n",
+			swidget->widget->name);
+		goto err;
+	}
+
+	for (i = 0; i < available_fmt->audio_fmt_num; i++)
+		dev_dbg(scomp->dev, "%d: dma buffer size: %u\n", i,
+			available_fmt->dma_buffer_size[i]);
+
+	ret = sof_update_ipc_object(scomp, &node_type,
+				    SOF_COPIER_TOKENS, swidget->tuples,
+				    swidget->num_tuples, sizeof(node_type), 1);
+	if (ret) {
+		dev_err(scomp->dev, "parse dai node type failed %d\n", ret);
+		goto err;
+	}
+
+	ret = sof_update_ipc_object(scomp, ipc4_copier,
+				    SOF_DAI_TOKENS, swidget->tuples,
+				    swidget->num_tuples, sizeof(u32), 1);
+	if (ret) {
+		dev_err(scomp->dev, "parse dai copier node token failed %d\n", ret);
+		goto err;
+	}
+
+	dev_dbg(scomp->dev, "dai %s node_type %u dai_type %u dai_index %d\n", swidget->widget->name,
+		node_type, ipc4_copier->dai_type, ipc4_copier->dai_index);
+
+	ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
+	ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL);
+	if (!ipc4_copier->gtw_attr) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr;
+	ipc4_copier->data.gtw_cfg.config_length = sizeof(struct sof_ipc4_gtw_attributes) >> 2;
+
+	dai->scomp = scomp;
+	dai->private = ipc4_copier;
+
+	/* set up module info and message header */
+	ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg);
+	if (ret)
+		goto free_copier_config;
+
+	return 0;
+
+free_copier_config:
+	kfree(ipc4_copier->copier_config);
+err:
+	kfree(available_fmt->dma_buffer_size);
+free_copier:
+	kfree(ipc4_copier);
+	return ret;
+}
+
+static void sof_ipc4_widget_free_comp_dai(struct snd_sof_widget *swidget)
+{
+	struct sof_ipc4_available_audio_format *available_fmt;
+	struct snd_sof_dai *dai = swidget->private;
+	struct sof_ipc4_copier *ipc4_copier;
+
+	if (!dai)
+		return;
+
+	ipc4_copier = dai->private;
+	available_fmt = &ipc4_copier->available_fmt;
+
+	kfree(available_fmt->dma_buffer_size);
+	kfree(available_fmt->base_config);
+	kfree(available_fmt->out_audio_fmt);
+	kfree(ipc4_copier->copier_config);
+	kfree(dai->private);
+	kfree(dai);
+	swidget->private = NULL;
+}
+
 static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
 {
 	struct snd_soc_component *scomp = swidget->scomp;
@@ -454,6 +573,18 @@ static enum sof_tokens pipeline_token_list[] = {
 	SOF_PIPELINE_TOKENS,
 };
 
+static enum sof_tokens dai_token_list[] = {
+	SOF_COMP_TOKENS,
+	SOF_AUDIO_FMT_NUM_TOKENS,
+	SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
+	SOF_IN_AUDIO_FORMAT_TOKENS,
+	SOF_OUT_AUDIO_FORMAT_TOKENS,
+	SOF_COPIER_GATEWAY_CFG_TOKENS,
+	SOF_COPIER_TOKENS,
+	SOF_DAI_TOKENS,
+	SOF_COMP_EXT_TOKENS,
+};
+
 static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
 	[snd_soc_dapm_aif_in] =  {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
 				  host_token_list, ARRAY_SIZE(host_token_list), NULL,
@@ -461,6 +592,10 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TY
 	[snd_soc_dapm_aif_out] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
 				  host_token_list, ARRAY_SIZE(host_token_list), NULL,
 				  NULL, NULL},
+	[snd_soc_dapm_dai_in] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
+				 dai_token_list, ARRAY_SIZE(dai_token_list), NULL, NULL, NULL},
+	[snd_soc_dapm_dai_out] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
+				  dai_token_list, ARRAY_SIZE(dai_token_list), NULL, NULL, NULL},
 	[snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline, sof_ipc4_widget_free_comp,
 				    pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL,
 				    NULL, NULL},
-- 
2.25.1


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

* [PATCH 05/23] ASoC: SOF: ipc4-topology: Add prepare op for AIF type widgets
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
                   ` (3 preceding siblings ...)
  2022-06-09  3:26 ` [PATCH 04/23] ASoC: SOF: ipc4-topology: Add support for parsing DAI_IN/DAI_OUT widgets Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 06/23] ASoC: SOF: ipc4-topology: Add prepare op for DAI " Ranjani Sridharan
                   ` (18 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Bard Liao, Ranjani Sridharan, Pierre-Louis Bossart,
	broonie, Péter Ujfalusi, Rander Wang

Define the prepare op for the AIF type widgets for IPC4.
The prepare op is responsible for choosing the input/output audio
formats for these widgets based on the runtime PCM params, assigning the
instance ID and updating the total memory usage for the pipelines these
widgets belong to.

Co-developed-by: Rander Wang <rander.wang@linux.intel.com>
Signed-off-by: Rander Wang <rander.wang@linux.intel.com>
Co-developed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 sound/soc/sof/ipc4-topology.c | 290 +++++++++++++++++++++++++++++++++-
 sound/soc/sof/ipc4-topology.h |  18 +++
 2 files changed, 306 insertions(+), 2 deletions(-)

diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 5bb80306794b..1a73c16f1624 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -557,6 +557,290 @@ static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
 	return ret;
 }
 
+static void
+sof_ipc4_update_pipeline_mem_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
+				   struct sof_ipc4_base_module_cfg *base_config)
+{
+	struct sof_ipc4_fw_module *fw_module = swidget->module_info;
+	struct snd_sof_widget *pipe_widget;
+	struct sof_ipc4_pipeline *pipeline;
+	int task_mem, queue_mem;
+	int ibs, bss, total;
+
+	ibs = base_config->ibs;
+	bss = base_config->is_pages;
+
+	task_mem = SOF_IPC4_PIPELINE_OBJECT_SIZE;
+	task_mem += SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE + bss;
+
+	if (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_LL) {
+		task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_LL_TASK_OBJECT_SIZE);
+		task_mem += SOF_IPC4_FW_MAX_QUEUE_COUNT * SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE;
+		task_mem += SOF_IPC4_LL_TASK_LIST_ITEM_SIZE;
+	} else {
+		task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_DP_TASK_OBJECT_SIZE);
+		task_mem += SOF_IPC4_DP_TASK_LIST_SIZE;
+	}
+
+	ibs = SOF_IPC4_FW_ROUNDUP(ibs);
+	queue_mem = SOF_IPC4_FW_MAX_QUEUE_COUNT * (SOF_IPC4_DATA_QUEUE_OBJECT_SIZE +  ibs);
+
+	total = SOF_IPC4_FW_PAGE(task_mem + queue_mem);
+
+	pipe_widget = swidget->pipe_widget;
+	pipeline = pipe_widget->private;
+	pipeline->mem_usage += total;
+}
+
+static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev,
+					      struct snd_sof_widget *swidget)
+{
+	struct sof_ipc4_fw_module *fw_module = swidget->module_info;
+	int max_instances = fw_module->man4_module_entry.instance_max_count;
+
+	swidget->instance_id = ida_alloc_max(&fw_module->m_ida, max_instances, GFP_KERNEL);
+	if (swidget->instance_id < 0) {
+		dev_err(sdev->dev, "failed to assign instance id for widget %s",
+			swidget->widget->name);
+		return swidget->instance_id;
+	}
+
+	return 0;
+}
+
+static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev,
+				   struct snd_sof_widget *swidget,
+				   struct sof_ipc4_base_module_cfg *base_config,
+				   struct sof_ipc4_audio_format *out_format,
+				   struct snd_pcm_hw_params *params,
+				   struct sof_ipc4_available_audio_format *available_fmt,
+				   size_t object_offset)
+{
+	void *ptr = available_fmt->ref_audio_fmt;
+	u32 valid_bits;
+	u32 channels;
+	u32 rate;
+	int sample_valid_bits;
+	int i;
+
+	if (!ptr) {
+		dev_err(sdev->dev, "no reference formats for %s\n", swidget->widget->name);
+		return -EINVAL;
+	}
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		sample_valid_bits = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		sample_valid_bits = 24;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		sample_valid_bits = 32;
+		break;
+	default:
+		dev_err(sdev->dev, "invalid pcm frame format %d\n", params_format(params));
+		return -EINVAL;
+	}
+
+	if (!available_fmt->audio_fmt_num) {
+		dev_err(sdev->dev, "no formats available for %s\n", swidget->widget->name);
+		return -EINVAL;
+	}
+
+	/*
+	 * Search supported audio formats to match rate, channels ,and
+	 * sample_valid_bytes from runtime params
+	 */
+	for (i = 0; i < available_fmt->audio_fmt_num; i++, ptr = (u8 *)ptr + object_offset) {
+		struct sof_ipc4_audio_format *fmt = ptr;
+
+		rate = fmt->sampling_frequency;
+		channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
+		valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
+		if (params_rate(params) == rate && params_channels(params) == channels &&
+		    sample_valid_bits == valid_bits) {
+			dev_dbg(sdev->dev, "%s: matching audio format index for %uHz, %ubit, %u channels: %d\n",
+				__func__, rate, valid_bits, channels, i);
+
+			/* copy ibs/obs and input format */
+			memcpy(base_config, &available_fmt->base_config[i],
+			       sizeof(struct sof_ipc4_base_module_cfg));
+
+			/* copy output format */
+			if (out_format)
+				memcpy(out_format, &available_fmt->out_audio_fmt[i],
+				       sizeof(struct sof_ipc4_audio_format));
+			break;
+		}
+	}
+
+	if (i == available_fmt->audio_fmt_num) {
+		dev_err(sdev->dev, "%s: Unsupported audio format: %uHz, %ubit, %u channels\n",
+			__func__, params_rate(params), sample_valid_bits, params_channels(params));
+		return -EINVAL;
+	}
+
+	dev_dbg(sdev->dev, "Init input audio formats for %s\n", swidget->widget->name);
+	sof_ipc4_dbg_audio_format(sdev->dev, &base_config->audio_fmt,
+				  sizeof(*base_config), 1);
+	if (out_format) {
+		dev_dbg(sdev->dev, "Init output audio formats for %s\n", swidget->widget->name);
+		sof_ipc4_dbg_audio_format(sdev->dev, out_format,
+					  sizeof(*out_format), 1);
+	}
+
+	/* Return the index of the matched format */
+	return i;
+}
+
+static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
+{
+	struct sof_ipc4_fw_module *fw_module = swidget->module_info;
+	struct sof_ipc4_copier *ipc4_copier = NULL;
+	struct snd_sof_widget *pipe_widget;
+	struct sof_ipc4_pipeline *pipeline;
+
+	/* reset pipeline memory usage */
+	pipe_widget = swidget->pipe_widget;
+	pipeline = pipe_widget->private;
+	pipeline->mem_usage = 0;
+
+	if (WIDGET_IS_AIF(swidget->id))
+		ipc4_copier = swidget->private;
+
+	if (ipc4_copier) {
+		kfree(ipc4_copier->ipc_config_data);
+		ipc4_copier->ipc_config_data = NULL;
+		ipc4_copier->ipc_config_size = 0;
+	}
+
+	ida_free(&fw_module->m_ida, swidget->instance_id);
+}
+
+static int
+sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
+			       struct snd_pcm_hw_params *fe_params,
+			       struct snd_sof_platform_stream_params *platform_params,
+			       struct snd_pcm_hw_params *pipeline_params, int dir)
+{
+	struct sof_ipc4_available_audio_format *available_fmt;
+	struct snd_soc_component *scomp = swidget->scomp;
+	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+	struct sof_ipc4_copier_data *copier_data;
+	struct snd_pcm_hw_params *ref_params;
+	struct sof_ipc4_copier *ipc4_copier;
+	struct snd_mask *fmt;
+	int out_sample_valid_bits;
+	size_t ref_audio_fmt_size;
+	void **ipc_config_data;
+	int *ipc_config_size;
+	u32 **data;
+	int ipc_size, ret;
+
+	dev_dbg(sdev->dev, "%s: copier %s, type %d", __func__, swidget->widget->name, swidget->id);
+
+	switch (swidget->id) {
+	case snd_soc_dapm_aif_in:
+	case snd_soc_dapm_aif_out:
+	{
+		struct sof_ipc4_gtw_attributes *gtw_attr;
+		struct snd_sof_widget *pipe_widget;
+		struct sof_ipc4_pipeline *pipeline;
+
+		pipe_widget = swidget->pipe_widget;
+		pipeline = pipe_widget->private;
+		ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
+		gtw_attr = ipc4_copier->gtw_attr;
+		copier_data = &ipc4_copier->data;
+		available_fmt = &ipc4_copier->available_fmt;
+
+		/*
+		 * base_config->audio_fmt and out_audio_fmt represent the input and output audio
+		 * formats. Use the input format as the reference to match pcm params for playback
+		 * and the output format as reference for capture.
+		 */
+		if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+			available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt;
+			ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg);
+		} else {
+			available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt;
+			ref_audio_fmt_size = sizeof(struct sof_ipc4_audio_format);
+		}
+		copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
+		copier_data->gtw_cfg.node_id |=
+			SOF_IPC4_NODE_INDEX(platform_params->stream_tag - 1);
+
+		/* set gateway attributes */
+		gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
+		ref_params = fe_params;
+		break;
+	}
+	default:
+		dev_err(sdev->dev, "unsupported type %d for copier %s",
+			swidget->id, swidget->widget->name);
+		return -EINVAL;
+	}
+
+	/* set input and output audio formats */
+	ret = sof_ipc4_init_audio_fmt(sdev, swidget, &copier_data->base_config,
+				      &copier_data->out_format, ref_params,
+				      available_fmt, ref_audio_fmt_size);
+	if (ret < 0)
+		return ret;
+
+	/* modify the input params for the next widget */
+	fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT);
+	out_sample_valid_bits =
+		SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(copier_data->out_format.fmt_cfg);
+	snd_mask_none(fmt);
+	switch (out_sample_valid_bits) {
+	case 16:
+		snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
+		break;
+	case 24:
+		snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+		break;
+	case 32:
+		snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
+		break;
+	default:
+		dev_err(sdev->dev, "invalid sample frame format %d\n",
+			params_format(pipeline_params));
+		return -EINVAL;
+	}
+
+	/* set the gateway dma_buffer_size using the matched ID returned above */
+	copier_data->gtw_cfg.dma_buffer_size = available_fmt->dma_buffer_size[ret];
+
+	data = &ipc4_copier->copier_config;
+	ipc_config_size = &ipc4_copier->ipc_config_size;
+	ipc_config_data = &ipc4_copier->ipc_config_data;
+
+	/* config_length is DWORD based */
+	ipc_size = sizeof(*copier_data) + copier_data->gtw_cfg.config_length * 4;
+
+	dev_dbg(sdev->dev, "copier %s, IPC size is %d", swidget->widget->name, ipc_size);
+
+	*ipc_config_data = kzalloc(ipc_size, GFP_KERNEL);
+	if (!*ipc_config_data)
+		return -ENOMEM;
+
+	*ipc_config_size = ipc_size;
+
+	/* copy IPC data */
+	memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data));
+	if (copier_data->gtw_cfg.config_length)
+		memcpy(*ipc_config_data + sizeof(*copier_data),
+		       *data, copier_data->gtw_cfg.config_length * 4);
+
+	/* update pipeline memory usage */
+	sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &copier_data->base_config);
+
+	/* assign instance ID */
+	return sof_ipc4_widget_assign_instance_id(sdev, swidget);
+}
+
 static enum sof_tokens host_token_list[] = {
 	SOF_COMP_TOKENS,
 	SOF_AUDIO_FMT_NUM_TOKENS,
@@ -588,10 +872,12 @@ static enum sof_tokens dai_token_list[] = {
 static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
 	[snd_soc_dapm_aif_in] =  {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
 				  host_token_list, ARRAY_SIZE(host_token_list), NULL,
-				  NULL, NULL},
+				  sof_ipc4_prepare_copier_module,
+				  sof_ipc4_unprepare_copier_module},
 	[snd_soc_dapm_aif_out] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
 				  host_token_list, ARRAY_SIZE(host_token_list), NULL,
-				  NULL, NULL},
+				  sof_ipc4_prepare_copier_module,
+				  sof_ipc4_unprepare_copier_module},
 	[snd_soc_dapm_dai_in] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
 				 dai_token_list, ARRAY_SIZE(dai_token_list), NULL, NULL, NULL},
 	[snd_soc_dapm_dai_out] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h
index f4f62dda63a3..5f4c463f329e 100644
--- a/sound/soc/sof/ipc4-topology.h
+++ b/sound/soc/sof/ipc4-topology.h
@@ -11,6 +11,24 @@
 
 #include <sound/sof/ipc4/header.h>
 
+#define SOF_IPC4_FW_PAGE_SIZE BIT(12)
+#define SOF_IPC4_FW_PAGE(x) ((((x) + BIT(12) - 1) & ~(BIT(12) - 1)) >> 12)
+#define SOF_IPC4_FW_ROUNDUP(x) (((x) + BIT(6) - 1) & (~(BIT(6) - 1)))
+
+#define SOF_IPC4_MODULE_LL      BIT(5)
+#define SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE 12
+#define SOF_IPC4_PIPELINE_OBJECT_SIZE 448
+#define SOF_IPC4_DATA_QUEUE_OBJECT_SIZE 128
+#define SOF_IPC4_LL_TASK_OBJECT_SIZE 72
+#define SOF_IPC4_DP_TASK_OBJECT_SIZE 104
+#define SOF_IPC4_DP_TASK_LIST_SIZE (12 + 8)
+#define SOF_IPC4_LL_TASK_LIST_ITEM_SIZE 12
+#define SOF_IPC4_FW_MAX_PAGE_COUNT 20
+#define SOF_IPC4_FW_MAX_QUEUE_COUNT 8
+
+/* Node index and mask applicable for host copier */
+#define SOF_IPC4_NODE_INDEX_MASK	0xFF
+#define SOF_IPC4_NODE_INDEX(x)	((x) & SOF_IPC4_NODE_INDEX_MASK)
 #define SOF_IPC4_NODE_TYPE(x)  ((x) << 8)
 
 /**
-- 
2.25.1


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

* [PATCH 06/23] ASoC: SOF: ipc4-topology: Add prepare op for DAI type widgets
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
                   ` (4 preceding siblings ...)
  2022-06-09  3:26 ` [PATCH 05/23] ASoC: SOF: ipc4-topology: Add prepare op for AIF type widgets Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 07/23] ASoC: SOF: ipc4-topology: Add support for parsing and preparing pga widgets Ranjani Sridharan
                   ` (17 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Bard Liao, Ranjani Sridharan, Pierre-Louis Bossart,
	broonie, Péter Ujfalusi, Rander Wang

Define the prepare op for the DAI type widgets for IPC4.
The prepare op is responsible for choosing the input/output audio
formats for these widgets based on the runtime PCM params, assigning the
instance ID and updating the total memory usage for the pipelines these
widgets belong to.

Co-developed-by: Rander Wang <rander.wang@linux.intel.com>
Signed-off-by: Rander Wang <rander.wang@linux.intel.com>
Co-developed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
---
 sound/soc/sof/ipc4-topology.c | 43 ++++++++++++++++++++++++++++++++---
 1 file changed, 40 insertions(+), 3 deletions(-)

diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 1a73c16f1624..1bc5ff0154c5 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -706,8 +706,13 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
 	pipeline = pipe_widget->private;
 	pipeline->mem_usage = 0;
 
-	if (WIDGET_IS_AIF(swidget->id))
+	if (WIDGET_IS_AIF(swidget->id)) {
 		ipc4_copier = swidget->private;
+	} else if (WIDGET_IS_DAI(swidget->id)) {
+		struct snd_sof_dai *dai = swidget->private;
+
+		ipc4_copier = dai->private;
+	}
 
 	if (ipc4_copier) {
 		kfree(ipc4_copier->ipc_config_data);
@@ -776,6 +781,34 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
 		ref_params = fe_params;
 		break;
 	}
+	case snd_soc_dapm_dai_in:
+	case snd_soc_dapm_dai_out:
+	{
+		struct snd_sof_dai *dai = swidget->private;
+
+		ipc4_copier = (struct sof_ipc4_copier *)dai->private;
+		copier_data = &ipc4_copier->data;
+		available_fmt = &ipc4_copier->available_fmt;
+		if (dir == SNDRV_PCM_STREAM_CAPTURE) {
+			available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt;
+			ref_audio_fmt_size = sizeof(struct sof_ipc4_audio_format);
+
+			/*
+			 * modify the input params for the dai copier as it only supports
+			 * 32-bit always
+			 */
+			fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT);
+			snd_mask_none(fmt);
+			snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
+		} else {
+			available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt;
+			ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg);
+		}
+
+		ref_params = pipeline_params;
+
+		break;
+	}
 	default:
 		dev_err(sdev->dev, "unsupported type %d for copier %s",
 			swidget->id, swidget->widget->name);
@@ -879,9 +912,13 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TY
 				  sof_ipc4_prepare_copier_module,
 				  sof_ipc4_unprepare_copier_module},
 	[snd_soc_dapm_dai_in] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
-				 dai_token_list, ARRAY_SIZE(dai_token_list), NULL, NULL, NULL},
+				 dai_token_list, ARRAY_SIZE(dai_token_list), NULL,
+				 sof_ipc4_prepare_copier_module,
+				 sof_ipc4_unprepare_copier_module},
 	[snd_soc_dapm_dai_out] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai,
-				  dai_token_list, ARRAY_SIZE(dai_token_list), NULL, NULL, NULL},
+				  dai_token_list, ARRAY_SIZE(dai_token_list), NULL,
+				  sof_ipc4_prepare_copier_module,
+				  sof_ipc4_unprepare_copier_module},
 	[snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline, sof_ipc4_widget_free_comp,
 				    pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL,
 				    NULL, NULL},
-- 
2.25.1


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

* [PATCH 07/23] ASoC: SOF: ipc4-topology: Add support for parsing and preparing pga widgets
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
                   ` (5 preceding siblings ...)
  2022-06-09  3:26 ` [PATCH 06/23] ASoC: SOF: ipc4-topology: Add prepare op for DAI " Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 08/23] ASoC: SOF: ipc4-topology: Add support for parsing mixer widgets Ranjani Sridharan
                   ` (16 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Bard Liao, Ranjani Sridharan, Pierre-Louis Bossart,
	broonie, Paul Olaru, Péter Ujfalusi, Rander Wang

Add support for parsing and preparing pga type widgets. Define the
token ID's and the associated token arrays needed to parse these
widgets.

Co-developed-by: Rander Wang <rander.wang@linux.intel.com>
Signed-off-by: Rander Wang <rander.wang@linux.intel.com>
Co-developed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Paul Olaru <paul.olaru@oss.nxp.com>
---
 sound/soc/sof/ipc4-topology.c | 113 ++++++++++++++++++++++++++++++++++
 sound/soc/sof/ipc4-topology.h |  60 ++++++++++++++++++
 sound/soc/sof/sof-audio.h     |   1 +
 3 files changed, 174 insertions(+)

diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 1bc5ff0154c5..30549573bd34 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -95,6 +95,16 @@ static const struct sof_topology_token comp_ext_tokens[] = {
 		offsetof(struct snd_sof_widget, uuid)},
 };
 
+static const struct sof_topology_token gain_tokens[] = {
+	{SOF_TKN_GAIN_RAMP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
+		get_token_u32, offsetof(struct sof_ipc4_gain_data, curve_type)},
+	{SOF_TKN_GAIN_RAMP_DURATION,
+		SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+		offsetof(struct sof_ipc4_gain_data, curve_duration)},
+	{SOF_TKN_GAIN_VAL, SND_SOC_TPLG_TUPLE_TYPE_WORD,
+		get_token_u32, offsetof(struct sof_ipc4_gain_data, init_val)},
+};
+
 static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
 	[SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)},
 	[SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)},
@@ -117,6 +127,7 @@ static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
 		ARRAY_SIZE(ipc4_copier_tokens)},
 	[SOF_AUDIO_FMT_NUM_TOKENS] = {"IPC4 Audio format number tokens",
 		ipc4_audio_fmt_num_tokens, ARRAY_SIZE(ipc4_audio_fmt_num_tokens)},
+	[SOF_GAIN_TOKENS] = {"Gain tokens", gain_tokens, ARRAY_SIZE(gain_tokens)},
 };
 
 static void sof_ipc4_dbg_audio_format(struct device *dev,
@@ -557,6 +568,62 @@ static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
 	return ret;
 }
 
+static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget)
+{
+	struct snd_soc_component *scomp = swidget->scomp;
+	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+	struct sof_ipc4_fw_module *fw_module;
+	struct snd_sof_control *scontrol;
+	struct sof_ipc4_gain *gain;
+	int ret;
+
+	gain = kzalloc(sizeof(*gain), GFP_KERNEL);
+	if (!gain)
+		return -ENOMEM;
+
+	swidget->private = gain;
+
+	gain->data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
+	gain->data.init_val = SOF_IPC4_VOL_ZERO_DB;
+
+	/* The out_audio_fmt in topology is ignored as it is not required to be sent to the FW */
+	ret = sof_ipc4_get_audio_fmt(scomp, swidget, &gain->available_fmt, false);
+	if (ret)
+		goto err;
+
+	ret = sof_update_ipc_object(scomp, &gain->data, SOF_GAIN_TOKENS, swidget->tuples,
+				    swidget->num_tuples, sizeof(gain->data), 1);
+	if (ret) {
+		dev_err(scomp->dev, "Parsing gain tokens failed\n");
+		goto err;
+	}
+
+	dev_dbg(scomp->dev,
+		"pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x, cpc %d\n",
+		swidget->widget->name, gain->data.curve_type, gain->data.curve_duration,
+		gain->data.init_val, gain->base_config.cpc);
+
+	ret = sof_ipc4_widget_setup_msg(swidget, &gain->msg);
+	if (ret)
+		goto err;
+
+	fw_module = swidget->module_info;
+
+	/* update module ID for all kcontrols for this widget */
+	list_for_each_entry(scontrol, &sdev->kcontrol_list, list)
+		if (scontrol->comp_id == swidget->comp_id) {
+			struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+			struct sof_ipc4_msg *msg = &cdata->msg;
+
+			msg->primary |= fw_module->man4_module_entry.id;
+		}
+
+	return 0;
+err:
+	kfree(gain);
+	return ret;
+}
+
 static void
 sof_ipc4_update_pipeline_mem_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
 				   struct sof_ipc4_base_module_cfg *base_config)
@@ -874,6 +941,39 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
 	return sof_ipc4_widget_assign_instance_id(sdev, swidget);
 }
 
+static void sof_ipc4_unprepare_generic_module(struct snd_sof_widget *swidget)
+{
+	struct sof_ipc4_fw_module *fw_module = swidget->module_info;
+
+	ida_free(&fw_module->m_ida, swidget->instance_id);
+}
+
+static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
+					struct snd_pcm_hw_params *fe_params,
+					struct snd_sof_platform_stream_params *platform_params,
+					struct snd_pcm_hw_params *pipeline_params, int dir)
+{
+	struct snd_soc_component *scomp = swidget->scomp;
+	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+	struct sof_ipc4_gain *gain = swidget->private;
+	int ret;
+
+	gain->available_fmt.ref_audio_fmt = &gain->available_fmt.base_config->audio_fmt;
+
+	/* output format is not required to be sent to the FW for gain */
+	ret = sof_ipc4_init_audio_fmt(sdev, swidget, &gain->base_config,
+				      NULL, pipeline_params, &gain->available_fmt,
+				      sizeof(gain->base_config));
+	if (ret < 0)
+		return ret;
+
+	/* update pipeline memory usage */
+	sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &gain->base_config);
+
+	/* assign instance ID */
+	return sof_ipc4_widget_assign_instance_id(sdev, swidget);
+}
+
 static enum sof_tokens host_token_list[] = {
 	SOF_COMP_TOKENS,
 	SOF_AUDIO_FMT_NUM_TOKENS,
@@ -902,6 +1002,15 @@ static enum sof_tokens dai_token_list[] = {
 	SOF_COMP_EXT_TOKENS,
 };
 
+static enum sof_tokens pga_token_list[] = {
+	SOF_COMP_TOKENS,
+	SOF_GAIN_TOKENS,
+	SOF_AUDIO_FMT_NUM_TOKENS,
+	SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
+	SOF_IN_AUDIO_FORMAT_TOKENS,
+	SOF_COMP_EXT_TOKENS,
+};
+
 static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
 	[snd_soc_dapm_aif_in] =  {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
 				  host_token_list, ARRAY_SIZE(host_token_list), NULL,
@@ -922,6 +1031,10 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TY
 	[snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline, sof_ipc4_widget_free_comp,
 				    pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL,
 				    NULL, NULL},
+	[snd_soc_dapm_pga] = {sof_ipc4_widget_setup_comp_pga, sof_ipc4_widget_free_comp,
+			      pga_token_list, ARRAY_SIZE(pga_token_list), NULL,
+			      sof_ipc4_prepare_gain_module,
+			      sof_ipc4_unprepare_generic_module},
 };
 
 const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h
index 5f4c463f329e..060123826db4 100644
--- a/sound/soc/sof/ipc4-topology.h
+++ b/sound/soc/sof/ipc4-topology.h
@@ -31,6 +31,9 @@
 #define SOF_IPC4_NODE_INDEX(x)	((x) & SOF_IPC4_NODE_INDEX_MASK)
 #define SOF_IPC4_NODE_TYPE(x)  ((x) << 8)
 
+#define SOF_IPC4_GAIN_ALL_CHANNELS_MASK 0xffffffff
+#define SOF_IPC4_VOL_ZERO_DB	0x7fffffff
+
 /**
  * struct sof_ipc4_pipeline - pipeline config data
  * @priority: Priority of this pipeline
@@ -128,4 +131,61 @@ struct sof_ipc4_copier {
 	int dai_index;
 };
 
+/**
+ * struct sof_ipc4_ctrl_value_chan: generic channel mapped value data
+ * @channel: Channel ID
+ * @value: gain value
+ */
+struct sof_ipc4_ctrl_value_chan {
+	u32 channel;
+	u32 value;
+};
+
+/**
+ * struct sof_ipc4_control_data - IPC data for kcontrol IO
+ * @msg: message structure for kcontrol IO
+ * @index: pipeline ID
+ * @chanv: channel ID and value array used by volume type controls
+ * @data: data for binary kcontrols
+ */
+struct sof_ipc4_control_data {
+	struct sof_ipc4_msg msg;
+	int index;
+
+	union {
+		struct sof_ipc4_ctrl_value_chan chanv[0];
+		struct sof_abi_hdr data[0];
+	};
+};
+
+/**
+ * struct sof_ipc4_gain_data - IPC gain blob
+ * @channels: Channels
+ * @init_val: Initial value
+ * @curve_type: Curve type
+ * @reserved: reserved for future use
+ * @curve_duration: Curve duration
+ */
+struct sof_ipc4_gain_data {
+	uint32_t channels;
+	uint32_t init_val;
+	uint32_t curve_type;
+	uint32_t reserved;
+	uint32_t curve_duration;
+} __aligned(8);
+
+/**
+ * struct sof_ipc4_gain - gain config data
+ * @base_config: IPC base config data
+ * @data: IPC gain blob
+ * @available_fmt: Available audio format
+ * @msg: message structure for gain
+ */
+struct sof_ipc4_gain {
+	struct sof_ipc4_base_module_cfg base_config;
+	struct sof_ipc4_gain_data data;
+	struct sof_ipc4_available_audio_format available_fmt;
+	struct sof_ipc4_msg msg;
+};
+
 #endif
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h
index c38b4bdd685a..d896da1192c5 100644
--- a/sound/soc/sof/sof-audio.h
+++ b/sound/soc/sof/sof-audio.h
@@ -232,6 +232,7 @@ enum sof_tokens {
 	SOF_COPIER_TOKENS,
 	SOF_AUDIO_FMT_NUM_TOKENS,
 	SOF_COPIER_FORMAT_TOKENS,
+	SOF_GAIN_TOKENS,
 
 	/* this should be the last */
 	SOF_TOKEN_COUNT,
-- 
2.25.1


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

* [PATCH 08/23] ASoC: SOF: ipc4-topology: Add support for parsing mixer widgets
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
                   ` (6 preceding siblings ...)
  2022-06-09  3:26 ` [PATCH 07/23] ASoC: SOF: ipc4-topology: Add support for parsing and preparing pga widgets Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 09/23] ASoC: SOF: ipc4-topology: Add control_setup op Ranjani Sridharan
                   ` (15 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Bard Liao, Ranjani Sridharan, Pierre-Louis Bossart,
	broonie, Paul Olaru, Péter Ujfalusi, Rander Wang

Add support for parsing and preparing mixer type widgets. Define the
token ID's and the associated token arrays needed to parse these
widgets.

Co-developed-by: Rander Wang <rander.wang@linux.intel.com>
Signed-off-by: Rander Wang <rander.wang@linux.intel.com>
Co-developed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Paul Olaru <paul.olaru@oss.nxp.com>
---
 sound/soc/sof/ipc4-topology.c | 68 +++++++++++++++++++++++++++++++++++
 sound/soc/sof/ipc4-topology.h | 12 +++++++
 2 files changed, 80 insertions(+)

diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 30549573bd34..35457fe4edd9 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -624,6 +624,35 @@ static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget)
 	return ret;
 }
 
+static int sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget *swidget)
+{
+	struct snd_soc_component *scomp = swidget->scomp;
+	struct sof_ipc4_mixer *mixer;
+	int ret;
+
+	dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name);
+
+	mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
+	if (!mixer)
+		return -ENOMEM;
+
+	swidget->private = mixer;
+
+	/* The out_audio_fmt in topology is ignored as it is not required to be sent to the FW */
+	ret = sof_ipc4_get_audio_fmt(scomp, swidget, &mixer->available_fmt, false);
+	if (ret)
+		goto err;
+
+	ret = sof_ipc4_widget_setup_msg(swidget, &mixer->msg);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	kfree(mixer);
+	return ret;
+}
+
 static void
 sof_ipc4_update_pipeline_mem_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
 				   struct sof_ipc4_base_module_cfg *base_config)
@@ -974,6 +1003,33 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
 	return sof_ipc4_widget_assign_instance_id(sdev, swidget);
 }
 
+static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget,
+					 struct snd_pcm_hw_params *fe_params,
+					 struct snd_sof_platform_stream_params *platform_params,
+					 struct snd_pcm_hw_params *pipeline_params, int dir)
+{
+	struct snd_soc_component *scomp = swidget->scomp;
+	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+	struct sof_ipc4_mixer *mixer = swidget->private;
+	int ret;
+
+	/* only 32bit is supported by mixer */
+	mixer->available_fmt.ref_audio_fmt = &mixer->available_fmt.base_config->audio_fmt;
+
+	/* output format is not required to be sent to the FW for mixer */
+	ret = sof_ipc4_init_audio_fmt(sdev, swidget, &mixer->base_config,
+				      NULL, pipeline_params, &mixer->available_fmt,
+				      sizeof(mixer->base_config));
+	if (ret < 0)
+		return ret;
+
+	/* update pipeline memory usage */
+	sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &mixer->base_config);
+
+	/* assign instance ID */
+	return sof_ipc4_widget_assign_instance_id(sdev, swidget);
+}
+
 static enum sof_tokens host_token_list[] = {
 	SOF_COMP_TOKENS,
 	SOF_AUDIO_FMT_NUM_TOKENS,
@@ -1011,6 +1067,14 @@ static enum sof_tokens pga_token_list[] = {
 	SOF_COMP_EXT_TOKENS,
 };
 
+static enum sof_tokens mixer_token_list[] = {
+	SOF_COMP_TOKENS,
+	SOF_AUDIO_FMT_NUM_TOKENS,
+	SOF_IN_AUDIO_FORMAT_TOKENS,
+	SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS,
+	SOF_COMP_EXT_TOKENS,
+};
+
 static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
 	[snd_soc_dapm_aif_in] =  {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm,
 				  host_token_list, ARRAY_SIZE(host_token_list), NULL,
@@ -1035,6 +1099,10 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TY
 			      pga_token_list, ARRAY_SIZE(pga_token_list), NULL,
 			      sof_ipc4_prepare_gain_module,
 			      sof_ipc4_unprepare_generic_module},
+	[snd_soc_dapm_mixer] = {sof_ipc4_widget_setup_comp_mixer, sof_ipc4_widget_free_comp,
+				mixer_token_list, ARRAY_SIZE(mixer_token_list),
+				NULL, sof_ipc4_prepare_mixer_module,
+				sof_ipc4_unprepare_generic_module},
 };
 
 const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h
index 060123826db4..eebf46b24430 100644
--- a/sound/soc/sof/ipc4-topology.h
+++ b/sound/soc/sof/ipc4-topology.h
@@ -188,4 +188,16 @@ struct sof_ipc4_gain {
 	struct sof_ipc4_msg msg;
 };
 
+/**
+ * struct sof_ipc4_mixer - mixer config data
+ * @base_config: IPC base config data
+ * @available_fmt: Available audio format
+ * @msg: IPC4 message struct containing header and data info
+ */
+struct sof_ipc4_mixer {
+	struct sof_ipc4_base_module_cfg base_config;
+	struct sof_ipc4_available_audio_format available_fmt;
+	struct sof_ipc4_msg msg;
+};
+
 #endif
-- 
2.25.1


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

* [PATCH 09/23] ASoC: SOF: ipc4-topology: Add control_setup op
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
                   ` (7 preceding siblings ...)
  2022-06-09  3:26 ` [PATCH 08/23] ASoC: SOF: ipc4-topology: Add support for parsing mixer widgets Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 10/23] ASoC: SOF: ipc4-topology: Add control IO ops Ranjani Sridharan
                   ` (14 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Bard Liao, Ranjani Sridharan, Pierre-Louis Bossart,
	broonie, Péter Ujfalusi, Rander Wang

Define the control_setup op for IPC4 topology IPC ops to handle the
volume kcontrol types. Support for other kcontrol types will be added in
the follow up patches.

Co-developed-by: Rander Wang <rander.wang@linux.intel.com>
Signed-off-by: Rander Wang <rander.wang@linux.intel.com>
Co-developed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
---
 sound/soc/sof/ipc4-topology.c | 49 +++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 35457fe4edd9..0c36b7cb6e79 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -15,6 +15,8 @@
 #include "ipc4-topology.h"
 #include "ops.h"
 
+#define SOF_IPC4_GAIN_PARAM_ID  0
+
 static const struct sof_topology_token ipc4_sched_tokens[] = {
 	{SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
 		offsetof(struct sof_ipc4_pipeline, lp_mode)}
@@ -1030,6 +1032,52 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget,
 	return sof_ipc4_widget_assign_instance_id(sdev, swidget);
 }
 
+static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
+{
+	struct sof_ipc4_control_data *control_data;
+	struct sof_ipc4_msg *msg;
+	int i;
+
+	scontrol->size = struct_size(control_data, chanv, scontrol->num_channels);
+
+	/* scontrol->ipc_control_data will be freed in sof_control_unload */
+	scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
+	if (!scontrol->ipc_control_data)
+		return -ENOMEM;
+
+	control_data = scontrol->ipc_control_data;
+	control_data->index = scontrol->index;
+
+	msg = &control_data->msg;
+	msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET);
+	msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+	msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+
+	msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_GAIN_PARAM_ID);
+
+	/* set default volume values to 0dB in control */
+	for (i = 0; i < scontrol->num_channels; i++) {
+		control_data->chanv[i].channel = i;
+		control_data->chanv[i].value = SOF_IPC4_VOL_ZERO_DB;
+	}
+
+	return 0;
+}
+
+static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
+{
+	switch (scontrol->info_type) {
+	case SND_SOC_TPLG_CTL_VOLSW:
+	case SND_SOC_TPLG_CTL_VOLSW_SX:
+	case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
+		return sof_ipc4_control_load_volume(sdev, scontrol);
+	default:
+		break;
+	}
+
+	return 0;
+}
+
 static enum sof_tokens host_token_list[] = {
 	SOF_COMP_TOKENS,
 	SOF_AUDIO_FMT_NUM_TOKENS,
@@ -1108,4 +1156,5 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TY
 const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
 	.widget = tplg_ipc4_widget_ops,
 	.token_list = ipc4_token_list,
+	.control_setup = sof_ipc4_control_setup,
 };
-- 
2.25.1


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

* [PATCH 10/23] ASoC: SOF: ipc4-topology: Add control IO ops
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
                   ` (8 preceding siblings ...)
  2022-06-09  3:26 ` [PATCH 09/23] ASoC: SOF: ipc4-topology: Add control_setup op Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 11/23] ASoC: SOF: IPC4: Add pcm ops Ranjani Sridharan
                   ` (13 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Bard Liao, Ranjani Sridharan, Pierre-Louis Bossart,
	broonie, Péter Ujfalusi, Rander Wang

Define the kcontrol IO ops for volume type controls for IPC4. Support
for other kcontrol types will be added later.

Co-developed-by: Rander Wang <rander.wang@linux.intel.com>
Signed-off-by: Rander Wang <rander.wang@linux.intel.com>
Co-developed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
---
 sound/soc/sof/Makefile        |   2 +-
 sound/soc/sof/ipc4-control.c  | 216 ++++++++++++++++++++++++++++++++++
 sound/soc/sof/ipc4-priv.h     |   1 +
 sound/soc/sof/ipc4-topology.c |   1 +
 4 files changed, 219 insertions(+), 1 deletion(-)
 create mode 100644 sound/soc/sof/ipc4-control.c

diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile
index 73524fadb3ce..1e15937f2bde 100644
--- a/sound/soc/sof/Makefile
+++ b/sound/soc/sof/Makefile
@@ -4,7 +4,7 @@ snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
 		control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o\
 		ipc3-topology.o ipc3-control.o ipc3.o ipc3-pcm.o ipc3-loader.o\
 		ipc3-dtrace.o\
-		ipc4.o ipc4-loader.o ipc4-topology.o
+		ipc4.o ipc4-loader.o ipc4-topology.o ipc4-control.o
 ifneq ($(CONFIG_SND_SOC_SOF_CLIENT),)
 snd-sof-objs += sof-client.o
 endif
diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c
new file mode 100644
index 000000000000..95ee121dd3cf
--- /dev/null
+++ b/sound/soc/sof/ipc4-control.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license.  When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2022 Intel Corporation. All rights reserved.
+//
+//
+
+#include "sof-priv.h"
+#include "sof-audio.h"
+#include "ipc4-priv.h"
+#include "ipc4-topology.h"
+
+static int sof_ipc4_set_get_kcontrol_data(struct snd_sof_control *scontrol, bool set)
+{
+	struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+	struct snd_soc_component *scomp = scontrol->scomp;
+	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+	const struct sof_ipc_ops *iops = sdev->ipc->ops;
+	struct sof_ipc4_msg *msg = &cdata->msg;
+	struct snd_sof_widget *swidget;
+	bool widget_found = false;
+
+	/* find widget associated with the control */
+	list_for_each_entry(swidget, &sdev->widget_list, list) {
+		if (swidget->comp_id == scontrol->comp_id) {
+			widget_found = true;
+			break;
+		}
+	}
+
+	if (!widget_found) {
+		dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
+		return -ENOENT;
+	}
+
+	/*
+	 * Volatile controls should always be part of static pipelines and the widget use_count
+	 * would always be > 0 in this case. For the others, just return the cached value if the
+	 * widget is not set up.
+	 */
+	if (!swidget->use_count)
+		return 0;
+
+	msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK;
+	msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
+
+	return iops->set_get_data(sdev, msg, msg->data_size, set);
+}
+
+static int
+sof_ipc4_set_volume_data(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
+			 struct snd_sof_control *scontrol)
+{
+	struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+	struct sof_ipc4_gain *gain = swidget->private;
+	struct sof_ipc4_msg *msg = &cdata->msg;
+	struct sof_ipc4_gain_data data;
+	bool all_channels_equal = true;
+	u32 value;
+	int ret, i;
+
+	/* check if all channel values are equal */
+	value = cdata->chanv[0].value;
+	for (i = 1; i < scontrol->num_channels; i++) {
+		if (cdata->chanv[i].value != value) {
+			all_channels_equal = false;
+			break;
+		}
+	}
+
+	/*
+	 * notify DSP with a single IPC message if all channel values are equal. Otherwise send
+	 * a separate IPC for each channel.
+	 */
+	for (i = 0; i < scontrol->num_channels; i++) {
+		if (all_channels_equal) {
+			data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
+			data.init_val = cdata->chanv[0].value;
+		} else {
+			data.channels = cdata->chanv[i].channel;
+			data.init_val = cdata->chanv[i].value;
+		}
+
+		/* set curve type and duration from topology */
+		data.curve_duration = gain->data.curve_duration;
+		data.curve_type = gain->data.curve_type;
+
+		msg->data_ptr = &data;
+		msg->data_size = sizeof(data);
+
+		ret = sof_ipc4_set_get_kcontrol_data(scontrol, true);
+		msg->data_ptr = NULL;
+		msg->data_size = 0;
+		if (ret < 0) {
+			dev_err(sdev->dev, "Failed to set volume update for %s\n",
+				scontrol->name);
+			return ret;
+		}
+
+		if (all_channels_equal)
+			break;
+	}
+
+	return 0;
+}
+
+static bool sof_ipc4_volume_put(struct snd_sof_control *scontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+	struct snd_soc_component *scomp = scontrol->scomp;
+	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+	unsigned int channels = scontrol->num_channels;
+	struct snd_sof_widget *swidget;
+	bool widget_found = false;
+	bool change = false;
+	unsigned int i;
+	int ret;
+
+	/* update each channel */
+	for (i = 0; i < channels; i++) {
+		u32 value = mixer_to_ipc(ucontrol->value.integer.value[i],
+					 scontrol->volume_table, scontrol->max + 1);
+
+		change = change || (value != cdata->chanv[i].value);
+		cdata->chanv[i].channel = i;
+		cdata->chanv[i].value = value;
+	}
+
+	if (!pm_runtime_active(scomp->dev))
+		return change;
+
+	/* find widget associated with the control */
+	list_for_each_entry(swidget, &sdev->widget_list, list) {
+		if (swidget->comp_id == scontrol->comp_id) {
+			widget_found = true;
+			break;
+		}
+	}
+
+	if (!widget_found) {
+		dev_err(scomp->dev, "Failed to find widget for kcontrol %s\n", scontrol->name);
+		return -ENOENT;
+	}
+
+	ret = sof_ipc4_set_volume_data(sdev, swidget, scontrol);
+	if (ret < 0)
+		return false;
+
+	return change;
+}
+
+static int sof_ipc4_volume_get(struct snd_sof_control *scontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+	unsigned int channels = scontrol->num_channels;
+	unsigned int i;
+
+	for (i = 0; i < channels; i++)
+		ucontrol->value.integer.value[i] = ipc_to_mixer(cdata->chanv[i].value,
+								scontrol->volume_table,
+								scontrol->max + 1);
+
+	return 0;
+}
+
+/* set up all controls for the widget */
+static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
+{
+	struct snd_sof_control *scontrol;
+	int ret;
+
+	list_for_each_entry(scontrol, &sdev->kcontrol_list, list)
+		if (scontrol->comp_id == swidget->comp_id) {
+			ret = sof_ipc4_set_volume_data(sdev, swidget, scontrol);
+			if (ret < 0) {
+				dev_err(sdev->dev, "%s: kcontrol %d set up failed for widget %s\n",
+					__func__, scontrol->comp_id, swidget->widget->name);
+				return ret;
+			}
+		}
+
+	return 0;
+}
+
+static int
+sof_ipc4_set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_ITEMS], int size)
+{
+	int i;
+
+	/* init the volume table */
+	scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL);
+	if (!scontrol->volume_table)
+		return -ENOMEM;
+
+	/* populate the volume table */
+	for (i = 0; i < size ; i++) {
+		u32 val = vol_compute_gain(i, tlv);
+		u64 q31val = ((u64)val) << 15; /* Can be over Q1.31, need to saturate */
+
+		scontrol->volume_table[i] = q31val > SOF_IPC4_VOL_ZERO_DB ?
+						SOF_IPC4_VOL_ZERO_DB : q31val;
+	}
+
+	return 0;
+}
+
+const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops = {
+	.volume_put = sof_ipc4_volume_put,
+	.volume_get = sof_ipc4_volume_get,
+	.widget_kcontrol_setup = sof_ipc4_widget_kcontrol_setup,
+	.set_up_volume_table = sof_ipc4_set_up_volume_table,
+};
diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h
index 5388b888fefa..d0b110811aeb 100644
--- a/sound/soc/sof/ipc4-priv.h
+++ b/sound/soc/sof/ipc4-priv.h
@@ -41,5 +41,6 @@ struct sof_ipc4_fw_module {
 
 extern const struct sof_ipc_fw_loader_ops ipc4_loader_ops;
 extern const struct sof_ipc_tplg_ops ipc4_tplg_ops;
+extern const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops;
 
 #endif
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 0c36b7cb6e79..3cebd6fe7cd1 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -1157,4 +1157,5 @@ const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
 	.widget = tplg_ipc4_widget_ops,
 	.token_list = ipc4_token_list,
 	.control_setup = sof_ipc4_control_setup,
+	.control = &tplg_ipc4_control_ops,
 };
-- 
2.25.1


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

* [PATCH 11/23] ASoC: SOF: IPC4: Add pcm ops
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
                   ` (9 preceding siblings ...)
  2022-06-09  3:26 ` [PATCH 10/23] ASoC: SOF: ipc4-topology: Add control IO ops Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 12/23] ASoC: SOF: ipc4-topology: Add widget_setup/widget_free ops Ranjani Sridharan
                   ` (12 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Bard Liao, Ranjani Sridharan, Pierre-Louis Bossart,
	broonie, Yaochun Hung, Péter Ujfalusi, Rander Wang

Define and set the PCM ops for IPC4.

Co-developed-by: Rander Wang <rander.wang@linux.intel.com>
Signed-off-by: Rander Wang <rander.wang@linux.intel.com>
Co-developed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Yaochun Hung <yc.hung@mediatek.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
---
 sound/soc/sof/Makefile    |   2 +-
 sound/soc/sof/ipc4-pcm.c  | 229 ++++++++++++++++++++++++++++++++++++++
 sound/soc/sof/ipc4-priv.h |   1 +
 sound/soc/sof/ipc4.c      |   1 +
 4 files changed, 232 insertions(+), 1 deletion(-)
 create mode 100644 sound/soc/sof/ipc4-pcm.c

diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile
index 1e15937f2bde..2fa8088707a8 100644
--- a/sound/soc/sof/Makefile
+++ b/sound/soc/sof/Makefile
@@ -4,7 +4,7 @@ snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
 		control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o\
 		ipc3-topology.o ipc3-control.o ipc3.o ipc3-pcm.o ipc3-loader.o\
 		ipc3-dtrace.o\
-		ipc4.o ipc4-loader.o ipc4-topology.o ipc4-control.o
+		ipc4.o ipc4-loader.o ipc4-topology.o ipc4-control.o ipc4-pcm.o
 ifneq ($(CONFIG_SND_SOC_SOF_CLIENT),)
 snd-sof-objs += sof-client.o
 endif
diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c
new file mode 100644
index 000000000000..7a56fba8f1d9
--- /dev/null
+++ b/sound/soc/sof/ipc4-pcm.c
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license.  When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2022 Intel Corporation. All rights reserved.
+//
+
+#include <sound/pcm_params.h>
+#include <sound/sof/ipc4/header.h>
+#include "sof-audio.h"
+#include "sof-priv.h"
+#include "ipc4-priv.h"
+#include "ipc4-topology.h"
+
+static int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state)
+{
+	struct sof_ipc4_msg msg = {{ 0 }};
+	u32 primary;
+
+	dev_dbg(sdev->dev, "ipc4 set pipeline %d state %d", id, state);
+
+	primary = state;
+	primary |= SOF_IPC4_GLB_PIPE_STATE_ID(id);
+	primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE);
+	primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+	primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
+
+	msg.primary = primary;
+
+	return sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
+}
+
+static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
+				      struct snd_pcm_substream *substream, int state)
+{
+	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
+	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+	struct snd_sof_widget *pipeline_widget;
+	struct snd_soc_dapm_widget_list *list;
+	struct snd_soc_dapm_widget *widget;
+	struct sof_ipc4_pipeline *pipeline;
+	struct snd_sof_widget *swidget;
+	struct snd_sof_pcm *spcm;
+	int ret = 0;
+	int num_widgets;
+
+	spcm = snd_sof_find_spcm_dai(component, rtd);
+	if (!spcm)
+		return -EINVAL;
+
+	list = spcm->stream[substream->stream].list;
+
+	for_each_dapm_widgets(list, num_widgets, widget) {
+		swidget = widget->dobj.private;
+
+		if (!swidget)
+			continue;
+
+		/*
+		 * set pipeline state for both FE and BE pipelines for RUNNING state.
+		 * For PAUSE/RESET, set the pipeline state only for the FE pipeline.
+		 */
+		switch (state) {
+		case SOF_IPC4_PIPE_PAUSED:
+		case SOF_IPC4_PIPE_RESET:
+			if (!WIDGET_IS_AIF(swidget->id))
+				continue;
+			break;
+		default:
+			break;
+		}
+
+		/* find pipeline widget for the pipeline that this widget belongs to */
+		pipeline_widget = swidget->pipe_widget;
+		pipeline = (struct sof_ipc4_pipeline *)pipeline_widget->private;
+
+		if (pipeline->state == state)
+			continue;
+
+		/* first set the pipeline to PAUSED state */
+		if (pipeline->state != SOF_IPC4_PIPE_PAUSED) {
+			ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+							  SOF_IPC4_PIPE_PAUSED);
+			if (ret < 0) {
+				dev_err(sdev->dev, "failed to pause pipeline %d\n",
+					swidget->pipeline_id);
+				return ret;
+			}
+		}
+
+		pipeline->state = SOF_IPC4_PIPE_PAUSED;
+
+		if (pipeline->state == state)
+			continue;
+
+		/* then set the final state */
+		ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id, state);
+		if (ret < 0) {
+			dev_err(sdev->dev, "failed to set state %d for pipeline %d\n",
+				state, swidget->pipeline_id);
+			break;
+		}
+
+		pipeline->state = state;
+	}
+
+	return ret;
+}
+
+static int sof_ipc4_pcm_trigger(struct snd_soc_component *component,
+				struct snd_pcm_substream *substream, int cmd)
+{
+	int state;
+
+	/* determine the pipeline state */
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		state = SOF_IPC4_PIPE_PAUSED;
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_START:
+		state = SOF_IPC4_PIPE_RUNNING;
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_STOP:
+		state = SOF_IPC4_PIPE_PAUSED;
+		break;
+	default:
+		dev_err(component->dev, "%s: unhandled trigger cmd %d\n", __func__, cmd);
+		return -EINVAL;
+	}
+
+	/* set the pipeline state */
+	return sof_ipc4_trigger_pipelines(component, substream, state);
+}
+
+static int sof_ipc4_pcm_hw_free(struct snd_soc_component *component,
+				struct snd_pcm_substream *substream)
+{
+	return sof_ipc4_trigger_pipelines(component, substream, SOF_IPC4_PIPE_RESET);
+}
+
+static void ipc4_ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const char *link_name,
+						 struct snd_pcm_hw_params *params)
+{
+	struct snd_sof_dai_link *slink;
+	struct snd_sof_dai *dai;
+	bool dai_link_found = false;
+	int i;
+
+	list_for_each_entry(slink, &sdev->dai_link_list, list) {
+		if (!strcmp(slink->link->name, link_name)) {
+			dai_link_found = true;
+			break;
+		}
+	}
+
+	if (!dai_link_found)
+		return;
+
+	for (i = 0; i < slink->num_hw_configs; i++) {
+		struct snd_soc_tplg_hw_config *hw_config = &slink->hw_configs[i];
+
+		if (params_rate(params) == le32_to_cpu(hw_config->fsync_rate)) {
+			/* set current config for all DAI's with matching name */
+			list_for_each_entry(dai, &sdev->dai_list, list)
+				if (!strcmp(slink->link->name, dai->name))
+					dai->current_config = le32_to_cpu(hw_config->id);
+			break;
+		}
+	}
+}
+
+static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
+				       struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
+	struct snd_sof_dai *dai = snd_sof_find_dai(component, rtd->dai_link->name);
+	struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
+	struct sof_ipc4_copier *ipc4_copier;
+	struct snd_soc_dpcm *dpcm;
+
+	if (!dai) {
+		dev_err(component->dev, "%s: No DAI found with name %s\n", __func__,
+			rtd->dai_link->name);
+		return -EINVAL;
+	}
+
+	ipc4_copier = dai->private;
+	if (!ipc4_copier) {
+		dev_err(component->dev, "%s: No private data found for DAI %s\n",
+			__func__, rtd->dai_link->name);
+		return -EINVAL;
+	}
+
+	/* always set BE format to 32-bits for both playback and capture */
+	snd_mask_none(fmt);
+	snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
+
+	/*
+	 * Set trigger order for capture to SND_SOC_DPCM_TRIGGER_PRE. This is required
+	 * to ensure that the BE DAI pipeline gets stopped/suspended before the FE DAI
+	 * pipeline gets triggered and the pipeline widgets are freed.
+	 */
+	for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_CAPTURE, dpcm) {
+		struct snd_soc_pcm_runtime *fe = dpcm->fe;
+
+		fe->dai_link->trigger[SNDRV_PCM_STREAM_CAPTURE] = SND_SOC_DPCM_TRIGGER_PRE;
+	}
+
+	switch (ipc4_copier->dai_type) {
+	case SOF_DAI_INTEL_SSP:
+		ipc4_ssp_dai_config_pcm_params_match(sdev, (char *)rtd->dai_link->name, params);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+const struct sof_ipc_pcm_ops ipc4_pcm_ops = {
+	.trigger = sof_ipc4_pcm_trigger,
+	.hw_free = sof_ipc4_pcm_hw_free,
+	.dai_link_fixup = sof_ipc4_pcm_dai_link_fixup,
+};
diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h
index d0b110811aeb..e4381a74516c 100644
--- a/sound/soc/sof/ipc4-priv.h
+++ b/sound/soc/sof/ipc4-priv.h
@@ -42,5 +42,6 @@ struct sof_ipc4_fw_module {
 extern const struct sof_ipc_fw_loader_ops ipc4_loader_ops;
 extern const struct sof_ipc_tplg_ops ipc4_tplg_ops;
 extern const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops;
+extern const struct sof_ipc_pcm_ops ipc4_pcm_ops;
 
 #endif
diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c
index be677a33882d..700069e759c4 100644
--- a/sound/soc/sof/ipc4.c
+++ b/sound/soc/sof/ipc4.c
@@ -604,4 +604,5 @@ const struct sof_ipc_ops ipc4_ops = {
 	.get_reply = sof_ipc4_get_reply,
 	.fw_loader = &ipc4_loader_ops,
 	.tplg = &ipc4_tplg_ops,
+	.pcm = &ipc4_pcm_ops,
 };
-- 
2.25.1


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

* [PATCH 12/23] ASoC: SOF: ipc4-topology: Add widget_setup/widget_free ops
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
                   ` (10 preceding siblings ...)
  2022-06-09  3:26 ` [PATCH 11/23] ASoC: SOF: IPC4: Add pcm ops Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 13/23] ASoC: SOF: ipc4-topology: Add route_setup/route_free ops Ranjani Sridharan
                   ` (11 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Péter Ujfalusi, Pierre-Louis Bossart,
	Ranjani Sridharan, broonie, Bard Liao, Rander Wang

Define and set the widget_setup/widget_free ops for IPC4.

Co-developed-by: Rander Wang <rander.wang@linux.intel.com>
Signed-off-by: Rander Wang <rander.wang@linux.intel.com>
Co-developed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
---
 sound/soc/sof/ipc4-topology.c | 123 ++++++++++++++++++++++++++++++++++
 1 file changed, 123 insertions(+)

diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 3cebd6fe7cd1..44f65b8b526a 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -1078,6 +1078,127 @@ static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_contr
 	return 0;
 }
 
+static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
+{
+	struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
+	struct sof_ipc4_pipeline *pipeline;
+	struct sof_ipc4_msg *msg;
+	void *ipc_data = NULL;
+	u32 ipc_size = 0;
+	int ret;
+
+	dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n",
+		swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core);
+
+	switch (swidget->id) {
+	case snd_soc_dapm_scheduler:
+		pipeline = swidget->private;
+
+		dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id,
+			pipeline->mem_usage);
+
+		msg = &pipeline->msg;
+		msg->primary |= pipeline->mem_usage;
+		break;
+	case snd_soc_dapm_aif_in:
+	case snd_soc_dapm_aif_out:
+	{
+		struct sof_ipc4_copier *ipc4_copier = swidget->private;
+
+		ipc_size = ipc4_copier->ipc_config_size;
+		ipc_data = ipc4_copier->ipc_config_data;
+
+		msg = &ipc4_copier->msg;
+		break;
+	}
+	case snd_soc_dapm_dai_in:
+	case snd_soc_dapm_dai_out:
+	{
+		struct snd_sof_dai *dai = swidget->private;
+		struct sof_ipc4_copier *ipc4_copier = dai->private;
+
+		ipc_size = ipc4_copier->ipc_config_size;
+		ipc_data = ipc4_copier->ipc_config_data;
+
+		msg = &ipc4_copier->msg;
+		break;
+	}
+	case snd_soc_dapm_pga:
+	{
+		struct sof_ipc4_gain *gain = swidget->private;
+
+		ipc_size = sizeof(struct sof_ipc4_base_module_cfg) +
+			   sizeof(struct sof_ipc4_gain_data);
+		ipc_data = gain;
+
+		msg = &gain->msg;
+		break;
+	}
+	case snd_soc_dapm_mixer:
+	{
+		struct sof_ipc4_mixer *mixer = swidget->private;
+
+		ipc_size = sizeof(mixer->base_config);
+		ipc_data = &mixer->base_config;
+
+		msg = &mixer->msg;
+		break;
+	}
+	default:
+		dev_err(sdev->dev, "widget type %d not supported", swidget->id);
+		return -EINVAL;
+	}
+
+	if (swidget->id != snd_soc_dapm_scheduler) {
+		pipeline = pipe_widget->private;
+		msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK;
+		msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
+
+		msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK;
+		msg->extension |= ipc_size >> 2;
+		msg->extension &= ~SOF_IPC4_MOD_EXT_DOMAIN_MASK;
+		msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(pipeline->lp_mode);
+	}
+
+	msg->data_size = ipc_size;
+	msg->data_ptr = ipc_data;
+
+	ret = sof_ipc_tx_message(sdev->ipc, msg, ipc_size, NULL, 0);
+	if (ret < 0)
+		dev_err(sdev->dev, "failed to create module %s\n", swidget->widget->name);
+
+	return ret;
+}
+
+static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
+{
+	int ret = 0;
+
+	/* freeing a pipeline frees all the widgets associated with it */
+	if (swidget->id == snd_soc_dapm_scheduler) {
+		struct sof_ipc4_pipeline *pipeline = swidget->private;
+		struct sof_ipc4_msg msg = {{ 0 }};
+		u32 header;
+
+		header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->pipeline_id);
+		header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE);
+		header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+		header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
+
+		msg.primary = header;
+
+		ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
+		if (ret < 0)
+			dev_err(sdev->dev, "failed to free pipeline widget %s\n",
+				swidget->widget->name);
+
+		pipeline->mem_usage = 0;
+		pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
+	}
+
+	return ret;
+}
+
 static enum sof_tokens host_token_list[] = {
 	SOF_COMP_TOKENS,
 	SOF_AUDIO_FMT_NUM_TOKENS,
@@ -1158,4 +1279,6 @@ const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
 	.token_list = ipc4_token_list,
 	.control_setup = sof_ipc4_control_setup,
 	.control = &tplg_ipc4_control_ops,
+	.widget_setup = sof_ipc4_widget_setup,
+	.widget_free = sof_ipc4_widget_free,
 };
-- 
2.25.1


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

* [PATCH 13/23] ASoC: SOF: ipc4-topology: Add route_setup/route_free ops
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
                   ` (11 preceding siblings ...)
  2022-06-09  3:26 ` [PATCH 12/23] ASoC: SOF: ipc4-topology: Add widget_setup/widget_free ops Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 14/23] ASoC: SOF: ipc4-topology: Add the dai_config op Ranjani Sridharan
                   ` (10 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Péter Ujfalusi, Pierre-Louis Bossart,
	Ranjani Sridharan, broonie, Bard Liao, Rander Wang

Define and set the route_setup/route_free ops for IPC4.

Co-developed-by: Rander Wang <rander.wang@linux.intel.com>
Signed-off-by: Rander Wang <rander.wang@linux.intel.com>
Co-developed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
---
 sound/soc/sof/ipc4-topology.c | 76 +++++++++++++++++++++++++++++++++++
 1 file changed, 76 insertions(+)

diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 44f65b8b526a..f5067d630f2d 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -1199,6 +1199,80 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget
 	return ret;
 }
 
+static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
+{
+	struct snd_sof_widget *src_widget = sroute->src_widget;
+	struct snd_sof_widget *sink_widget = sroute->sink_widget;
+	struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
+	struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
+	struct sof_ipc4_msg msg = {{ 0 }};
+	u32 header, extension;
+	int src_queue = 0;
+	int dst_queue = 0;
+	int ret;
+
+	dev_dbg(sdev->dev, "%s: bind %s -> %s\n", __func__,
+		src_widget->widget->name, sink_widget->widget->name);
+
+	header = src_fw_module->man4_module_entry.id;
+	header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
+	header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_BIND);
+	header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+	header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+
+	extension = sink_fw_module->man4_module_entry.id;
+	extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
+	extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(dst_queue);
+	extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(src_queue);
+
+	msg.primary = header;
+	msg.extension = extension;
+
+	ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
+	if (ret < 0)
+		dev_err(sdev->dev, "%s: failed to bind modules %s -> %s\n",
+			__func__, src_widget->widget->name, sink_widget->widget->name);
+
+	return ret;
+}
+
+static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
+{
+	struct snd_sof_widget *src_widget = sroute->src_widget;
+	struct snd_sof_widget *sink_widget = sroute->sink_widget;
+	struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info;
+	struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info;
+	struct sof_ipc4_msg msg = {{ 0 }};
+	u32 header, extension;
+	int src_queue = 0;
+	int dst_queue = 0;
+	int ret;
+
+	dev_dbg(sdev->dev, "%s: unbind modules %s -> %s\n", __func__,
+		src_widget->widget->name, sink_widget->widget->name);
+
+	header = src_fw_module->man4_module_entry.id;
+	header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id);
+	header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_UNBIND);
+	header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+	header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+
+	extension = sink_fw_module->man4_module_entry.id;
+	extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id);
+	extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(dst_queue);
+	extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(src_queue);
+
+	msg.primary = header;
+	msg.extension = extension;
+
+	ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
+	if (ret < 0)
+		dev_err(sdev->dev, "failed to unbind modules %s -> %s\n",
+			src_widget->widget->name, sink_widget->widget->name);
+
+	return ret;
+}
+
 static enum sof_tokens host_token_list[] = {
 	SOF_COMP_TOKENS,
 	SOF_AUDIO_FMT_NUM_TOKENS,
@@ -1281,4 +1355,6 @@ const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
 	.control = &tplg_ipc4_control_ops,
 	.widget_setup = sof_ipc4_widget_setup,
 	.widget_free = sof_ipc4_widget_free,
+	.route_setup = sof_ipc4_route_setup,
+	.route_free = sof_ipc4_route_free,
 };
-- 
2.25.1


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

* [PATCH 14/23] ASoC: SOF: ipc4-topology: Add the dai_config op
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
                   ` (12 preceding siblings ...)
  2022-06-09  3:26 ` [PATCH 13/23] ASoC: SOF: ipc4-topology: Add route_setup/route_free ops Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 15/23] ASoC: SOF: ipc4-pcm: Expose sof_ipc4_set_pipeline_state() Ranjani Sridharan
                   ` (9 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Bard Liao, Ranjani Sridharan, Pierre-Louis Bossart,
	broonie, Péter Ujfalusi, Rander Wang

Define and set the dai_config op for IPC4.

Co-developed-by: Rander Wang <rander.wang@linux.intel.com>
Signed-off-by: Rander Wang <rander.wang@linux.intel.com>
Co-developed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
 sound/soc/sof/ipc4-topology.c | 45 +++++++++++++++++++++++++++++++++++
 sound/soc/sof/ipc4-topology.h |  2 +-
 2 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index f5067d630f2d..9615034f8c70 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -1273,6 +1273,50 @@ static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *s
 	return ret;
 }
 
+static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
+			       unsigned int flags, struct snd_sof_dai_config_data *data)
+{
+	struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
+	struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
+	struct snd_sof_dai *dai = swidget->private;
+	struct sof_ipc4_gtw_attributes *gtw_attr;
+	struct sof_ipc4_copier_data *copier_data;
+	struct sof_ipc4_copier *ipc4_copier;
+
+	if (!dai || !dai->private) {
+		dev_err(sdev->dev, "Invalid DAI or DAI private data for %s\n",
+			swidget->widget->name);
+		return -EINVAL;
+	}
+
+	ipc4_copier = (struct sof_ipc4_copier *)dai->private;
+	copier_data = &ipc4_copier->data;
+
+	if (!data)
+		return 0;
+
+	switch (ipc4_copier->dai_type) {
+	case SOF_DAI_INTEL_HDA:
+		gtw_attr = ipc4_copier->gtw_attr;
+		gtw_attr->lp_buffer_alloc = pipeline->lp_mode;
+		fallthrough;
+	case SOF_DAI_INTEL_ALH:
+		copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
+		copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data);
+		break;
+	case SOF_DAI_INTEL_DMIC:
+	case SOF_DAI_INTEL_SSP:
+		/* nothing to do for SSP/DMIC */
+		break;
+	default:
+		dev_err(sdev->dev, "%s: unsupported dai type %d\n", __func__,
+			ipc4_copier->dai_type);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static enum sof_tokens host_token_list[] = {
 	SOF_COMP_TOKENS,
 	SOF_AUDIO_FMT_NUM_TOKENS,
@@ -1357,4 +1401,5 @@ const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
 	.widget_free = sof_ipc4_widget_free,
 	.route_setup = sof_ipc4_route_setup,
 	.route_free = sof_ipc4_route_free,
+	.dai_config = sof_ipc4_dai_config,
 };
diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h
index eebf46b24430..0cadf04efa6a 100644
--- a/sound/soc/sof/ipc4-topology.h
+++ b/sound/soc/sof/ipc4-topology.h
@@ -26,7 +26,7 @@
 #define SOF_IPC4_FW_MAX_PAGE_COUNT 20
 #define SOF_IPC4_FW_MAX_QUEUE_COUNT 8
 
-/* Node index and mask applicable for host copier */
+/* Node index and mask applicable for host copier and ALH/HDA type DAI copiers */
 #define SOF_IPC4_NODE_INDEX_MASK	0xFF
 #define SOF_IPC4_NODE_INDEX(x)	((x) & SOF_IPC4_NODE_INDEX_MASK)
 #define SOF_IPC4_NODE_TYPE(x)  ((x) << 8)
-- 
2.25.1


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

* [PATCH 15/23] ASoC: SOF: ipc4-pcm: Expose sof_ipc4_set_pipeline_state()
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
                   ` (13 preceding siblings ...)
  2022-06-09  3:26 ` [PATCH 14/23] ASoC: SOF: ipc4-topology: Add the dai_config op Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 16/23] ASoC: SOF: IPC4: set the BE DAI ops Ranjani Sridharan
                   ` (8 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Péter Ujfalusi, Ranjani Sridharan,
	Pierre-Louis Bossart, broonie, Bard Liao

Expose the sof_ipc4_set_pipeline_state() function as it will be used in
the IPC4-specific BE DAI driver ops.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
---
 sound/soc/sof/ipc4-pcm.c  | 3 ++-
 sound/soc/sof/ipc4-priv.h | 2 ++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c
index 7a56fba8f1d9..6a702f9dc065 100644
--- a/sound/soc/sof/ipc4-pcm.c
+++ b/sound/soc/sof/ipc4-pcm.c
@@ -13,7 +13,7 @@
 #include "ipc4-priv.h"
 #include "ipc4-topology.h"
 
-static int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state)
+int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state)
 {
 	struct sof_ipc4_msg msg = {{ 0 }};
 	u32 primary;
@@ -30,6 +30,7 @@ static int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 sta
 
 	return sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0);
 }
+EXPORT_SYMBOL(sof_ipc4_set_pipeline_state);
 
 static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
 				      struct snd_pcm_substream *substream, int state)
diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h
index e4381a74516c..8dddceaf5eb3 100644
--- a/sound/soc/sof/ipc4-priv.h
+++ b/sound/soc/sof/ipc4-priv.h
@@ -44,4 +44,6 @@ extern const struct sof_ipc_tplg_ops ipc4_tplg_ops;
 extern const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops;
 extern const struct sof_ipc_pcm_ops ipc4_pcm_ops;
 
+int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state);
+
 #endif
-- 
2.25.1


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

* [PATCH 16/23] ASoC: SOF: IPC4: set the BE DAI ops
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
                   ` (14 preceding siblings ...)
  2022-06-09  3:26 ` [PATCH 15/23] ASoC: SOF: ipc4-pcm: Expose sof_ipc4_set_pipeline_state() Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 17/23] ASoC: SOF: Add ops_free Ranjani Sridharan
                   ` (7 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Péter Ujfalusi, Ranjani Sridharan,
	Pierre-Louis Bossart, broonie, Bard Liao

Add BE DAI drv ops for IPC4 for DMIC, SSP and HDA type DAI's.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
---
 sound/soc/sof/intel/hda-dai.c | 173 +++++++++++++++++++++++++++++++++-
 1 file changed, 170 insertions(+), 3 deletions(-)

diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index 9823230d2ef4..5423667002e5 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -10,6 +10,10 @@
 
 #include <sound/pcm_params.h>
 #include <sound/hdaudio_ext.h>
+#include <sound/sof/ipc4/header.h>
+#include <uapi/sound/sof/header.h>
+#include "../ipc4-priv.h"
+#include "../ipc4-topology.h"
 #include "../sof-priv.h"
 #include "../sof-audio.h"
 #include "hda.h"
@@ -369,8 +373,7 @@ static int hda_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w)
 	return ret;
 }
 
-static int ipc3_hda_dai_prepare(struct snd_pcm_substream *substream,
-				struct snd_soc_dai *dai)
+static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
 {
 	struct hdac_ext_stream *hext_stream =
 				snd_soc_dai_get_dma_data(dai, substream);
@@ -438,6 +441,91 @@ static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+/*
+ * In contrast to IPC3, the dai trigger in IPC4 mixes pipeline state changes
+ * (over IPC channel) and DMA state change (direct host register changes).
+ */
+static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream,
+				int cmd, struct snd_soc_dai *dai)
+{
+	struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(dai, substream);
+	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_sof_widget *swidget;
+	struct snd_soc_dapm_widget *w;
+	struct snd_soc_dai *codec_dai;
+	struct hdac_stream *hstream;
+	struct snd_soc_dai *cpu_dai;
+	int ret;
+
+	dev_dbg(dai->dev, "%s: cmd=%d dai %s direction %d\n", __func__, cmd,
+		dai->name, substream->stream);
+
+	hstream = substream->runtime->private_data;
+	rtd = asoc_substream_to_rtd(substream);
+	cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+	codec_dai = asoc_rtd_to_codec(rtd, 0);
+
+	w = snd_soc_dai_get_widget(dai, substream->stream);
+	swidget = w->dobj.private;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		snd_hdac_ext_link_stream_start(hext_stream);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_STOP:
+	{
+		struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
+		struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
+
+		ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+						  SOF_IPC4_PIPE_PAUSED);
+		if (ret < 0)
+			return ret;
+
+		pipeline->state = SOF_IPC4_PIPE_PAUSED;
+
+		snd_hdac_ext_link_stream_clear(hext_stream);
+
+		ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+						  SOF_IPC4_PIPE_RESET);
+		if (ret < 0)
+			return ret;
+
+		pipeline->state = SOF_IPC4_PIPE_RESET;
+
+		ret = hda_link_dma_cleanup(substream, hstream, cpu_dai, codec_dai, false);
+		if (ret < 0) {
+			dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__);
+			return ret;
+		}
+		break;
+	}
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	{
+		struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
+		struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
+
+		ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+						  SOF_IPC4_PIPE_PAUSED);
+		if (ret < 0)
+			return ret;
+
+		pipeline->state = SOF_IPC4_PIPE_PAUSED;
+
+		snd_hdac_ext_link_stream_clear(hext_stream);
+		break;
+	}
+	default:
+		dev_err(sdev->dev, "%s: unknown trigger command %d\n", __func__, cmd);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int hda_dai_hw_free(struct snd_pcm_substream *substream,
 			   struct snd_soc_dai *dai)
 {
@@ -454,7 +542,7 @@ static const struct snd_soc_dai_ops ipc3_hda_dai_ops = {
 	.hw_params = hda_dai_hw_params,
 	.hw_free = hda_dai_hw_free,
 	.trigger = ipc3_hda_dai_trigger,
-	.prepare = ipc3_hda_dai_prepare,
+	.prepare = hda_dai_prepare,
 };
 
 static int hda_dai_suspend(struct hdac_bus *bus)
@@ -497,6 +585,14 @@ static int hda_dai_suspend(struct hdac_bus *bus)
 
 	return 0;
 }
+
+static const struct snd_soc_dai_ops ipc4_hda_dai_ops = {
+	.hw_params = hda_dai_hw_params,
+	.hw_free = hda_dai_hw_free,
+	.trigger = ipc4_hda_dai_trigger,
+	.prepare = hda_dai_prepare,
+};
+
 #endif
 
 /* only one flag used so far to harden hw_params/hw_free/trigger/prepare */
@@ -608,6 +704,59 @@ static const struct snd_soc_dai_ops ipc3_ssp_dai_ops = {
 	.shutdown = ssp_dai_shutdown,
 };
 
+static int ipc4_be_dai_trigger(struct snd_pcm_substream *substream,
+			       int cmd, struct snd_soc_dai *dai)
+{
+	struct snd_sof_widget *pipe_widget;
+	struct sof_ipc4_pipeline *pipeline;
+	struct snd_sof_widget *swidget;
+	struct snd_soc_dapm_widget *w;
+	struct snd_sof_dev *sdev;
+	int ret;
+
+	w = snd_soc_dai_get_widget(dai, substream->stream);
+	swidget = w->dobj.private;
+	pipe_widget = swidget->pipe_widget;
+	pipeline = pipe_widget->private;
+	sdev = snd_soc_component_get_drvdata(swidget->scomp);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_STOP:
+		ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+						  SOF_IPC4_PIPE_PAUSED);
+		if (ret < 0)
+			return ret;
+		pipeline->state = SOF_IPC4_PIPE_PAUSED;
+
+		ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+						  SOF_IPC4_PIPE_RESET);
+		if (ret < 0)
+			return ret;
+		pipeline->state = SOF_IPC4_PIPE_RESET;
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
+						  SOF_IPC4_PIPE_PAUSED);
+		if (ret < 0)
+			return ret;
+		pipeline->state = SOF_IPC4_PIPE_PAUSED;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops ipc4_dmic_dai_ops = {
+	.trigger = ipc4_be_dai_trigger,
+};
+
+static const struct snd_soc_dai_ops ipc4_ssp_dai_ops = {
+	.trigger = ipc4_be_dai_trigger,
+};
+
 void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
 {
 	int i;
@@ -624,6 +773,24 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
 			    strstr(ops->drv[i].name, "Analog") ||
 			    strstr(ops->drv[i].name, "Digital"))
 				ops->drv[i].ops = &ipc3_hda_dai_ops;
+#endif
+		}
+		break;
+	case SOF_INTEL_IPC4:
+		for (i = 0; i < ops->num_drv; i++) {
+			if (strstr(ops->drv[i].name, "DMIC")) {
+				ops->drv[i].ops = &ipc4_dmic_dai_ops;
+				continue;
+			}
+			if (strstr(ops->drv[i].name, "SSP")) {
+				ops->drv[i].ops = &ipc4_ssp_dai_ops;
+				continue;
+			}
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+			if (strstr(ops->drv[i].name, "iDisp") ||
+			    strstr(ops->drv[i].name, "Analog") ||
+			    strstr(ops->drv[i].name, "Digital"))
+				ops->drv[i].ops = &ipc4_hda_dai_ops;
 #endif
 		}
 		break;
-- 
2.25.1


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

* [PATCH 17/23] ASoC: SOF: Add ops_free
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
                   ` (15 preceding siblings ...)
  2022-06-09  3:26 ` [PATCH 16/23] ASoC: SOF: IPC4: set the BE DAI ops Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 18/23] ASoC: SOF: Intel: hda: init NHLT for IPC4 Ranjani Sridharan
                   ` (6 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Péter Ujfalusi, Ranjani Sridharan,
	Pierre-Louis Bossart, broonie, Bard Liao

Add the ops_free callback in struct sof_dev_desc.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
---
 include/sound/sof.h  | 1 +
 sound/soc/sof/core.c | 7 ++++++-
 sound/soc/sof/ops.h  | 6 ++++++
 3 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/include/sound/sof.h b/include/sound/sof.h
index 1a82a0db5e7f..367dccfea7ad 100644
--- a/include/sound/sof.h
+++ b/include/sound/sof.h
@@ -138,6 +138,7 @@ struct sof_dev_desc {
 
 	struct snd_sof_dsp_ops *ops;
 	int (*ops_init)(struct snd_sof_dev *sdev);
+	void (*ops_free)(struct snd_sof_dev *sdev);
 };
 
 int sof_dai_get_mclk(struct snd_soc_pcm_runtime *rtd);
diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c
index 53719c04658f..c99b5e6c026c 100644
--- a/sound/soc/sof/core.c
+++ b/sound/soc/sof/core.c
@@ -189,7 +189,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
 	ret = snd_sof_probe(sdev);
 	if (ret < 0) {
 		dev_err(sdev->dev, "error: failed to probe DSP %d\n", ret);
-		return ret;
+		goto probe_err;
 	}
 
 	sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE);
@@ -317,6 +317,8 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
 	snd_sof_free_debug(sdev);
 dsp_err:
 	snd_sof_remove(sdev);
+probe_err:
+	sof_ops_free(sdev);
 
 	/* all resources freed, update state to match */
 	sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED);
@@ -374,6 +376,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
 	    !sof_ops(sdev)->block_read || !sof_ops(sdev)->block_write ||
 	    !sof_ops(sdev)->send_msg || !sof_ops(sdev)->load_firmware ||
 	    !sof_ops(sdev)->ipc_msg_data) {
+		sof_ops_free(sdev);
 		dev_err(dev, "error: missing mandatory ops\n");
 		return -EINVAL;
 	}
@@ -457,6 +460,8 @@ int snd_sof_device_remove(struct device *dev)
 		snd_sof_remove(sdev);
 	}
 
+	sof_ops_free(sdev);
+
 	/* release firmware */
 	snd_sof_fw_unload(sdev);
 
diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h
index b79ae4f66eba..55d43adb6a29 100644
--- a/sound/soc/sof/ops.h
+++ b/sound/soc/sof/ops.h
@@ -29,6 +29,12 @@ static inline int sof_ops_init(struct snd_sof_dev *sdev)
 	return 0;
 }
 
+static inline void sof_ops_free(struct snd_sof_dev *sdev)
+{
+	if (sdev->pdata->desc->ops_free)
+		sdev->pdata->desc->ops_free(sdev);
+}
+
 /* Mandatory operations are verified during probing */
 
 /* init */
-- 
2.25.1


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

* [PATCH 18/23] ASoC: SOF: Intel: hda: init NHLT for IPC4
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
                   ` (16 preceding siblings ...)
  2022-06-09  3:26 ` [PATCH 17/23] ASoC: SOF: Add ops_free Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 19/23] ASoC: SOF: Add two new structures for topology manifest data Ranjani Sridharan
                   ` (5 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Bard Liao, Pierre-Louis Bossart, Ranjani Sridharan,
	broonie, Péter Ujfalusi, Jaska Uimonen

Init and save the BIOS NHLT as part of the IPC4 FW data.
Add a kernel module param to override the BIOS NHLT with the NHLT from
the topology. Also, add the ops_free callback for all HDA platforms to
free the NHLT.

Co-developed-by: Jaska Uimonen <jaska.uimonen@linux.intel.com>
Signed-off-by: Jaska Uimonen <jaska.uimonen@linux.intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
---
 sound/soc/sof/intel/hda-dai.c | 28 ++++++++++++++++++++++++++++
 sound/soc/sof/intel/hda.h     |  1 +
 sound/soc/sof/intel/pci-apl.c |  1 +
 sound/soc/sof/intel/pci-cnl.c |  1 +
 sound/soc/sof/intel/pci-icl.c |  1 +
 sound/soc/sof/intel/pci-tgl.c |  1 +
 sound/soc/sof/ipc4-priv.h     |  2 ++
 7 files changed, 35 insertions(+)

diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index 5423667002e5..228079a52c3d 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -10,6 +10,7 @@
 
 #include <sound/pcm_params.h>
 #include <sound/hdaudio_ext.h>
+#include <sound/intel-nhlt.h>
 #include <sound/sof/ipc4/header.h>
 #include <uapi/sound/sof/header.h>
 #include "../ipc4-priv.h"
@@ -18,6 +19,14 @@
 #include "../sof-audio.h"
 #include "hda.h"
 
+/*
+ * The default method is to fetch NHLT from BIOS. With this parameter set
+ * it is possible to override that with NHLT in the SOF topology manifest.
+ */
+static bool hda_use_tplg_nhlt;
+module_param_named(sof_use_tplg_nhlt, hda_use_tplg_nhlt, bool, 0444);
+MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override");
+
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
 
 struct hda_pipe_params {
@@ -777,6 +786,9 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
 		}
 		break;
 	case SOF_INTEL_IPC4:
+	{
+		struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+
 		for (i = 0; i < ops->num_drv; i++) {
 			if (strstr(ops->drv[i].name, "DMIC")) {
 				ops->drv[i].ops = &ipc4_dmic_dai_ops;
@@ -793,12 +805,28 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
 				ops->drv[i].ops = &ipc4_hda_dai_ops;
 #endif
 		}
+
+		if (!hda_use_tplg_nhlt)
+			ipc4_data->nhlt = intel_nhlt_init(sdev->dev);
+
 		break;
+	}
 	default:
 		break;
 	}
 }
 
+void hda_ops_free(struct snd_sof_dev *sdev)
+{
+	if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
+		struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+
+		if (!hda_use_tplg_nhlt)
+			intel_nhlt_free(ipc4_data->nhlt);
+	}
+}
+EXPORT_SYMBOL_NS(hda_ops_free, SND_SOC_SOF_INTEL_HDA_COMMON);
+
 /*
  * common dai driver for skl+ platforms.
  * some products who use this DAI array only physically have a subset of
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index 3e0f7b0c586a..59181468e05e 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -763,6 +763,7 @@ int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_f
 extern int sof_hda_position_quirk;
 
 void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops);
+void hda_ops_free(struct snd_sof_dev *sdev);
 
 /* IPC4 */
 irqreturn_t cnl_ipc4_irq_thread(int irq, void *context);
diff --git a/sound/soc/sof/intel/pci-apl.c b/sound/soc/sof/intel/pci-apl.c
index 2de3658eb817..998e219011f0 100644
--- a/sound/soc/sof/intel/pci-apl.c
+++ b/sound/soc/sof/intel/pci-apl.c
@@ -44,6 +44,7 @@ static const struct sof_dev_desc bxt_desc = {
 	.nocodec_tplg_filename = "sof-apl-nocodec.tplg",
 	.ops = &sof_apl_ops,
 	.ops_init = sof_apl_ops_init,
+	.ops_free = hda_ops_free,
 };
 
 static const struct sof_dev_desc glk_desc = {
diff --git a/sound/soc/sof/intel/pci-cnl.c b/sound/soc/sof/intel/pci-cnl.c
index 87e587aef9c9..c797356f7028 100644
--- a/sound/soc/sof/intel/pci-cnl.c
+++ b/sound/soc/sof/intel/pci-cnl.c
@@ -73,6 +73,7 @@ static const struct sof_dev_desc cfl_desc = {
 	.nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
 	.ops = &sof_cnl_ops,
 	.ops_init = sof_cnl_ops_init,
+	.ops_free = hda_ops_free,
 };
 
 static const struct sof_dev_desc cml_desc = {
diff --git a/sound/soc/sof/intel/pci-icl.c b/sound/soc/sof/intel/pci-icl.c
index 1c7f16ce531e..48f24f8ace26 100644
--- a/sound/soc/sof/intel/pci-icl.c
+++ b/sound/soc/sof/intel/pci-icl.c
@@ -45,6 +45,7 @@ static const struct sof_dev_desc icl_desc = {
 	.nocodec_tplg_filename = "sof-icl-nocodec.tplg",
 	.ops = &sof_icl_ops,
 	.ops_init = sof_icl_ops_init,
+	.ops_free = hda_ops_free,
 };
 
 static const struct sof_dev_desc jsl_desc = {
diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c
index 58a9bd92a237..ccc44ba3ad94 100644
--- a/sound/soc/sof/intel/pci-tgl.c
+++ b/sound/soc/sof/intel/pci-tgl.c
@@ -73,6 +73,7 @@ static const struct sof_dev_desc tglh_desc = {
 	.nocodec_tplg_filename = "sof-tgl-nocodec.tplg",
 	.ops = &sof_tgl_ops,
 	.ops_init = sof_tgl_ops_init,
+	.ops_free = hda_ops_free,
 };
 
 static const struct sof_dev_desc ehl_desc = {
diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h
index 8dddceaf5eb3..9492fe1796c2 100644
--- a/sound/soc/sof/ipc4-priv.h
+++ b/sound/soc/sof/ipc4-priv.h
@@ -18,11 +18,13 @@
  * @manifest_fw_hdr_offset: FW header offset in the manifest
  * @num_fw_modules : Number of modules in base FW
  * @fw_modules: Array of base FW modules
+ * @nhlt: NHLT table either from the BIOS or the topology manifest
  */
 struct sof_ipc4_fw_data {
 	u32 manifest_fw_hdr_offset;
 	int num_fw_modules;
 	void *fw_modules;
+	void *nhlt;
 };
 
 /**
-- 
2.25.1


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

* [PATCH 19/23] ASoC: SOF: Add two new structures for topology manifest data
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
                   ` (17 preceding siblings ...)
  2022-06-09  3:26 ` [PATCH 18/23] ASoC: SOF: Intel: hda: init NHLT for IPC4 Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 20/23] ASoC: SOF: Add a new IPC op for parsing topology manifest Ranjani Sridharan
                   ` (4 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Bard Liao, Pierre-Louis Bossart, Ranjani Sridharan,
	broonie, Péter Ujfalusi, Jaska Uimonen

Add a couple of structures for parsing and saving the topology manifest
data.

Co-developed-by: Jaska Uimonen <jaska.uimonen@linux.intel.com>
Signed-off-by: Jaska Uimonen <jaska.uimonen@linux.intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
---
 include/uapi/sound/sof/abi.h    |  2 ++
 include/uapi/sound/sof/header.h | 30 ++++++++++++++++++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h
index 0e7dccdc25fd..c88f467374ae 100644
--- a/include/uapi/sound/sof/abi.h
+++ b/include/uapi/sound/sof/abi.h
@@ -24,6 +24,8 @@
 #ifndef __INCLUDE_UAPI_SOUND_SOF_ABI_H__
 #define __INCLUDE_UAPI_SOUND_SOF_ABI_H__
 
+#include <linux/types.h>
+
 /* SOF ABI version major, minor and patch numbers */
 #define SOF_ABI_MAJOR 3
 #define SOF_ABI_MINOR 21
diff --git a/include/uapi/sound/sof/header.h b/include/uapi/sound/sof/header.h
index 5f4518e7a972..f125f7772ee7 100644
--- a/include/uapi/sound/sof/header.h
+++ b/include/uapi/sound/sof/header.h
@@ -26,4 +26,34 @@ struct sof_abi_hdr {
 	__u32 data[0];		/**< Component data - opaque to core */
 }  __packed;
 
+#define SOF_MANIFEST_DATA_TYPE_NHLT 1
+
+/**
+ * struct sof_manifest_tlv - SOF manifest TLV data
+ * @type: type of data
+ * @size: data size (not including the size of this struct)
+ * @data: payload data
+ */
+struct sof_manifest_tlv {
+	__le32 type;
+	__le32 size;
+	__u8 data[];
+};
+
+/**
+ * struct sof_manifest - SOF topology manifest
+ * @abi_major: Major ABI version
+ * @abi_minor: Minor ABI version
+ * @abi_patch: ABI patch
+ * @count: count of tlv items
+ * @items: consecutive variable size tlv items
+ */
+struct sof_manifest {
+	__le16 abi_major;
+	__le16 abi_minor;
+	__le16 abi_patch;
+	__le16 count;
+	struct sof_manifest_tlv items[];
+};
+
 #endif
-- 
2.25.1


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

* [PATCH 20/23] ASoC: SOF: Add a new IPC op for parsing topology manifest
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
                   ` (18 preceding siblings ...)
  2022-06-09  3:26 ` [PATCH 19/23] ASoC: SOF: Add two new structures for topology manifest data Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 21/23] ASoC: SOF: ipc4-topology: Add support for SSP/DMIC DAI's Ranjani Sridharan
                   ` (3 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Bard Liao, Pierre-Louis Bossart, Ranjani Sridharan,
	broonie, Péter Ujfalusi, Jaska Uimonen

Add a new topology IPC op, parse_manifest. Define and set the op for
IPC4 and IPC4.

Co-developed-by: Jaska Uimonen <jaska.uimonen@linux.intel.com>
Signed-off-by: Jaska Uimonen <jaska.uimonen@linux.intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
---
 sound/soc/sof/ipc3-topology.c | 48 ++++++++++++++++++++++++++
 sound/soc/sof/ipc4-topology.c | 63 +++++++++++++++++++++++++++++++++++
 sound/soc/sof/sof-audio.h     |  3 ++
 sound/soc/sof/topology.c      | 45 +++----------------------
 4 files changed, 118 insertions(+), 41 deletions(-)

diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c
index 043554d7cb4a..a91d7df3f07e 100644
--- a/sound/soc/sof/ipc3-topology.c
+++ b/sound/soc/sof/ipc3-topology.c
@@ -17,6 +17,9 @@
 /* Full volume for default values */
 #define VOL_ZERO_DB	BIT(VOLUME_FWL)
 
+/* size of tplg ABI in bytes */
+#define SOF_IPC3_TPLG_ABI_SIZE 3
+
 struct sof_widget_data {
 	int ctrl_type;
 	int ipc_cmd;
@@ -2303,6 +2306,50 @@ static int sof_ipc3_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *da
 	return -EINVAL;
 }
 
+static int sof_ipc3_parse_manifest(struct snd_soc_component *scomp, int index,
+				   struct snd_soc_tplg_manifest *man)
+{
+	u32 size = le32_to_cpu(man->priv.size);
+	u32 abi_version;
+
+	/* backward compatible with tplg without ABI info */
+	if (!size) {
+		dev_dbg(scomp->dev, "No topology ABI info\n");
+		return 0;
+	}
+
+	if (size != SOF_IPC3_TPLG_ABI_SIZE) {
+		dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n",
+			__func__, size);
+		return -EINVAL;
+	}
+
+	dev_info(scomp->dev,
+		 "Topology: ABI %d:%d:%d Kernel ABI %hhu:%hhu:%hhu\n",
+		 man->priv.data[0], man->priv.data[1], man->priv.data[2],
+		 SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
+
+	abi_version = SOF_ABI_VER(man->priv.data[0], man->priv.data[1], man->priv.data[2]);
+
+	if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, abi_version)) {
+		dev_err(scomp->dev, "%s: Incompatible topology ABI version\n", __func__);
+		return -EINVAL;
+	}
+
+	if (SOF_ABI_VERSION_MINOR(abi_version) > SOF_ABI_MINOR) {
+		if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) {
+			dev_warn(scomp->dev, "%s: Topology ABI is more recent than kernel\n",
+				 __func__);
+		} else {
+			dev_err(scomp->dev, "%s: Topology ABI is more recent than kernel\n",
+				__func__);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 /* token list for each topology object */
 static enum sof_tokens host_token_list[] = {
 	SOF_CORE_TOKENS,
@@ -2413,4 +2460,5 @@ const struct sof_ipc_tplg_ops ipc3_tplg_ops = {
 	.dai_get_clk = sof_ipc3_dai_get_clk,
 	.set_up_all_pipelines = sof_ipc3_set_up_all_pipelines,
 	.tear_down_all_pipelines = sof_ipc3_tear_down_all_pipelines,
+	.parse_manifest = sof_ipc3_parse_manifest,
 };
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 9615034f8c70..27ad48990383 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -16,6 +16,7 @@
 #include "ops.h"
 
 #define SOF_IPC4_GAIN_PARAM_ID  0
+#define SOF_IPC4_TPLG_ABI_SIZE 6
 
 static const struct sof_topology_token ipc4_sched_tokens[] = {
 	{SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
@@ -1317,6 +1318,67 @@ static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *
 	return 0;
 }
 
+static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index,
+				   struct snd_soc_tplg_manifest *man)
+{
+	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+	struct sof_manifest_tlv *manifest_tlv;
+	struct sof_manifest *manifest;
+	u32 size = le32_to_cpu(man->priv.size);
+	u8 *man_ptr = man->priv.data;
+	u32 len_check;
+	int i;
+
+	if (!size || size < SOF_IPC4_TPLG_ABI_SIZE) {
+		dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n",
+			__func__, size);
+		return -EINVAL;
+	}
+
+	manifest = (struct sof_manifest *)man_ptr;
+
+	dev_info(scomp->dev,
+		 "Topology: ABI %d:%d:%d Kernel ABI %u:%u:%u\n",
+		  le16_to_cpu(manifest->abi_major), le16_to_cpu(manifest->abi_minor),
+		  le16_to_cpu(manifest->abi_patch),
+		  SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
+
+	/* TODO: Add ABI compatibility check */
+
+	/* no more data after the ABI version */
+	if (size <= SOF_IPC4_TPLG_ABI_SIZE)
+		return 0;
+
+	manifest_tlv = manifest->items;
+	len_check = sizeof(struct sof_manifest);
+	for (i = 0; i < le16_to_cpu(manifest->count); i++) {
+		len_check += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size);
+		if (len_check > size)
+			return -EINVAL;
+
+		switch (le32_to_cpu(manifest_tlv->type)) {
+		case SOF_MANIFEST_DATA_TYPE_NHLT:
+			/* no NHLT in BIOS, so use the one from topology manifest */
+			if (ipc4_data->nhlt)
+				break;
+			ipc4_data->nhlt = devm_kmemdup(sdev->dev, manifest_tlv->data,
+						       le32_to_cpu(manifest_tlv->size), GFP_KERNEL);
+			if (!ipc4_data->nhlt)
+				return -ENOMEM;
+			break;
+		default:
+			dev_warn(scomp->dev, "Skipping unknown manifest data type %d\n",
+				 manifest_tlv->type);
+			break;
+		}
+		man_ptr += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size);
+		manifest_tlv = (struct sof_manifest_tlv *)man_ptr;
+	}
+
+	return 0;
+}
+
 static enum sof_tokens host_token_list[] = {
 	SOF_COMP_TOKENS,
 	SOF_AUDIO_FMT_NUM_TOKENS,
@@ -1402,4 +1464,5 @@ const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
 	.route_setup = sof_ipc4_route_setup,
 	.route_free = sof_ipc4_route_free,
 	.dai_config = sof_ipc4_dai_config,
+	.parse_manifest = sof_ipc4_parse_manifest,
 };
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h
index d896da1192c5..79486266081f 100644
--- a/sound/soc/sof/sof-audio.h
+++ b/sound/soc/sof/sof-audio.h
@@ -168,6 +168,7 @@ struct sof_ipc_tplg_widget_ops {
  * @dai_get_clk: Function pointer for getting the DAI clock setting
  * @set_up_all_pipelines: Function pointer for setting up all topology pipelines
  * @tear_down_all_pipelines: Function pointer for tearing down all topology pipelines
+ * @parse_manifest: Optional function pointer for ipc4 specific parsing of topology manifest
  */
 struct sof_ipc_tplg_ops {
 	const struct sof_ipc_tplg_widget_ops *widget;
@@ -185,6 +186,8 @@ struct sof_ipc_tplg_ops {
 	int (*dai_get_clk)(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type);
 	int (*set_up_all_pipelines)(struct snd_sof_dev *sdev, bool verify);
 	int (*tear_down_all_pipelines)(struct snd_sof_dev *sdev, bool verify);
+	int (*parse_manifest)(struct snd_soc_component *scomp, int index,
+			      struct snd_soc_tplg_manifest *man);
 };
 
 /** struct snd_sof_tuple - Tuple info
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index 606dbca94246..1893c590f2f0 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -36,9 +36,6 @@
 #define TLV_STEP	1
 #define TLV_MUTE	2
 
-/* size of tplg abi in byte */
-#define SOF_TPLG_ABI_SIZE 3
-
 /**
  * sof_update_ipc_object - Parse multiple sets of tokens within the token array associated with the
  *			    token ID.
@@ -2020,45 +2017,11 @@ static int sof_complete(struct snd_soc_component *scomp)
 static int sof_manifest(struct snd_soc_component *scomp, int index,
 			struct snd_soc_tplg_manifest *man)
 {
-	u32 size;
-	u32 abi_version;
-
-	size = le32_to_cpu(man->priv.size);
-
-	/* backward compatible with tplg without ABI info */
-	if (!size) {
-		dev_dbg(scomp->dev, "No topology ABI info\n");
-		return 0;
-	}
-
-	if (size != SOF_TPLG_ABI_SIZE) {
-		dev_err(scomp->dev, "error: invalid topology ABI size\n");
-		return -EINVAL;
-	}
-
-	dev_info(scomp->dev,
-		 "Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
-		 man->priv.data[0], man->priv.data[1],
-		 man->priv.data[2], SOF_ABI_MAJOR, SOF_ABI_MINOR,
-		 SOF_ABI_PATCH);
-
-	abi_version = SOF_ABI_VER(man->priv.data[0],
-				  man->priv.data[1],
-				  man->priv.data[2]);
-
-	if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, abi_version)) {
-		dev_err(scomp->dev, "error: incompatible topology ABI version\n");
-		return -EINVAL;
-	}
+	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+	const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg;
 
-	if (SOF_ABI_VERSION_MINOR(abi_version) > SOF_ABI_MINOR) {
-		if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) {
-			dev_warn(scomp->dev, "warn: topology ABI is more recent than kernel\n");
-		} else {
-			dev_err(scomp->dev, "error: topology ABI is more recent than kernel\n");
-			return -EINVAL;
-		}
-	}
+	if (ipc_tplg_ops->parse_manifest)
+		return ipc_tplg_ops->parse_manifest(scomp, index, man);
 
 	return 0;
 }
-- 
2.25.1


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

* [PATCH 21/23] ASoC: SOF: ipc4-topology: Add support for SSP/DMIC DAI's
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
                   ` (19 preceding siblings ...)
  2022-06-09  3:26 ` [PATCH 20/23] ASoC: SOF: Add a new IPC op for parsing topology manifest Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 22/23] AsoC: SOF: ipc4-topology: Add dai_get_clk op Ranjani Sridharan
                   ` (2 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Bard Liao, Pierre-Louis Bossart, Ranjani Sridharan,
	broonie, Péter Ujfalusi, Jaska Uimonen

The copier config for SSP and DMIC type DAI copiers needs to be parsed
and matched with the runtime hw_config from the NHLT table. Along with
this, also add the change to set the node_id for these copier types.

Co-developed-by: Jaska Uimonen <jaska.uimonen@linux.intel.com>
Signed-off-by: Jaska Uimonen <jaska.uimonen@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
---
 sound/soc/sof/ipc4-topology.c | 148 ++++++++++++++++++++++++++++++++--
 sound/soc/sof/ipc4-topology.h |   6 ++
 2 files changed, 146 insertions(+), 8 deletions(-)

diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 27ad48990383..9f055c187b72 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -9,6 +9,7 @@
 #include <uapi/sound/sof/tokens.h>
 #include <sound/pcm_params.h>
 #include <sound/sof/ext_manifest4.h>
+#include <sound/intel-nhlt.h>
 #include "sof-priv.h"
 #include "sof-audio.h"
 #include "ipc4-priv.h"
@@ -473,14 +474,30 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
 		node_type, ipc4_copier->dai_type, ipc4_copier->dai_index);
 
 	ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
-	ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL);
-	if (!ipc4_copier->gtw_attr) {
-		ret = -ENOMEM;
-		goto err;
-	}
 
-	ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr;
-	ipc4_copier->data.gtw_cfg.config_length = sizeof(struct sof_ipc4_gtw_attributes) >> 2;
+	switch (ipc4_copier->dai_type) {
+	case SOF_DAI_INTEL_SSP:
+		/* set SSP DAI index as the node_id */
+		ipc4_copier->data.gtw_cfg.node_id |=
+			SOF_IPC4_NODE_INDEX_INTEL_SSP(ipc4_copier->dai_index);
+		break;
+	case SOF_DAI_INTEL_DMIC:
+		/* set DMIC DAI index as the node_id */
+		ipc4_copier->data.gtw_cfg.node_id |=
+			SOF_IPC4_NODE_INDEX_INTEL_DMIC(ipc4_copier->dai_index);
+		break;
+	default:
+		ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL);
+		if (!ipc4_copier->gtw_attr) {
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr;
+		ipc4_copier->data.gtw_cfg.config_length =
+			sizeof(struct sof_ipc4_gtw_attributes) >> 2;
+		break;
+	}
 
 	dai->scomp = scomp;
 	dai->private = ipc4_copier;
@@ -516,7 +533,9 @@ static void sof_ipc4_widget_free_comp_dai(struct snd_sof_widget *swidget)
 	kfree(available_fmt->dma_buffer_size);
 	kfree(available_fmt->base_config);
 	kfree(available_fmt->out_audio_fmt);
-	kfree(ipc4_copier->copier_config);
+	if (ipc4_copier->dai_type != SOF_DAI_INTEL_SSP &&
+	    ipc4_copier->dai_type != SOF_DAI_INTEL_DMIC)
+		kfree(ipc4_copier->copier_config);
 	kfree(dai->private);
 	kfree(dai);
 	swidget->private = NULL;
@@ -822,6 +841,112 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
 	ida_free(&fw_module->m_ida, swidget->instance_id);
 }
 
+#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT)
+static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
+					int *sample_rate, int *channel_count, int *bit_depth)
+{
+	struct snd_soc_tplg_hw_config *hw_config;
+	struct snd_sof_dai_link *slink;
+	bool dai_link_found = false;
+	bool hw_cfg_found = false;
+	int i;
+
+	/* get current hw_config from link */
+	list_for_each_entry(slink, &sdev->dai_link_list, list) {
+		if (!strcmp(slink->link->name, dai->name)) {
+			dai_link_found = true;
+			break;
+		}
+	}
+
+	if (!dai_link_found) {
+		dev_err(sdev->dev, "%s: no DAI link found for DAI %s\n", __func__, dai->name);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < slink->num_hw_configs; i++) {
+		hw_config = &slink->hw_configs[i];
+		if (dai->current_config == le32_to_cpu(hw_config->id)) {
+			hw_cfg_found = true;
+			break;
+		}
+	}
+
+	if (!hw_cfg_found) {
+		dev_err(sdev->dev, "%s: no matching hw_config found for DAI %s\n", __func__,
+			dai->name);
+		return -EINVAL;
+	}
+
+	*bit_depth = le32_to_cpu(hw_config->tdm_slot_width);
+	*channel_count = le32_to_cpu(hw_config->tdm_slots);
+	*sample_rate = le32_to_cpu(hw_config->fsync_rate);
+
+	dev_dbg(sdev->dev, "%s: sample rate: %d sample width: %d channels: %d\n",
+		__func__, *sample_rate, *bit_depth, *channel_count);
+
+	return 0;
+}
+
+static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
+					  struct snd_pcm_hw_params *params, u32 dai_index,
+					  u32 linktype, u8 dir, u32 **dst, u32 *len)
+{
+	struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+	struct nhlt_specific_cfg *cfg;
+	int sample_rate, channel_count;
+	int bit_depth, ret;
+	u32 nhlt_type;
+
+	/* convert to NHLT type */
+	switch (linktype) {
+	case SOF_DAI_INTEL_DMIC:
+		nhlt_type = NHLT_LINK_DMIC;
+		bit_depth = params_width(params);
+		channel_count = params_channels(params);
+		sample_rate = params_rate(params);
+		break;
+	case SOF_DAI_INTEL_SSP:
+		nhlt_type = NHLT_LINK_SSP;
+		ret = snd_sof_get_hw_config_params(sdev, dai, &sample_rate, &channel_count,
+						   &bit_depth);
+		if (ret < 0)
+			return ret;
+		break;
+	default:
+		return 0;
+	}
+
+	dev_dbg(sdev->dev, "%s: dai index %d nhlt type %d direction %d\n",
+		__func__, dai_index, nhlt_type, dir);
+
+	/* find NHLT blob with matching params */
+	cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, dai_index, nhlt_type,
+					   bit_depth, bit_depth, channel_count, sample_rate,
+					   dir, 0);
+
+	if (!cfg) {
+		dev_err(sdev->dev,
+			"no matching blob for sample rate: %d sample width: %d channels: %d\n",
+			sample_rate, bit_depth, channel_count);
+		return -EINVAL;
+	}
+
+	/* config length should be in dwords */
+	*len = cfg->size >> 2;
+	*dst = (u32 *)cfg->caps;
+
+	return 0;
+}
+#else
+static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai,
+					  struct snd_pcm_hw_params *params, u32 dai_index,
+					  u32 linktype, u8 dir, u32 **dst, u32 *len)
+{
+	return 0;
+}
+#endif
+
 static int
 sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
 			       struct snd_pcm_hw_params *fe_params,
@@ -906,6 +1031,13 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
 
 		ref_params = pipeline_params;
 
+		ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, fe_params, ipc4_copier->dai_index,
+						     ipc4_copier->dai_type, dir,
+						     &ipc4_copier->copier_config,
+						     &copier_data->gtw_cfg.config_length);
+		if (ret < 0)
+			return ret;
+
 		break;
 	}
 	default:
diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h
index 0cadf04efa6a..64d836f05bad 100644
--- a/sound/soc/sof/ipc4-topology.h
+++ b/sound/soc/sof/ipc4-topology.h
@@ -31,6 +31,12 @@
 #define SOF_IPC4_NODE_INDEX(x)	((x) & SOF_IPC4_NODE_INDEX_MASK)
 #define SOF_IPC4_NODE_TYPE(x)  ((x) << 8)
 
+/* Node ID for SSP type DAI copiers */
+#define SOF_IPC4_NODE_INDEX_INTEL_SSP(x) (((x) & 0xf) << 4)
+
+/* Node ID for DMIC type DAI copiers */
+#define SOF_IPC4_NODE_INDEX_INTEL_DMIC(x) (((x) & 0x7) << 5)
+
 #define SOF_IPC4_GAIN_ALL_CHANNELS_MASK 0xffffffff
 #define SOF_IPC4_VOL_ZERO_DB	0x7fffffff
 
-- 
2.25.1


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

* [PATCH 22/23] AsoC: SOF: ipc4-topology: Add dai_get_clk op
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
                   ` (20 preceding siblings ...)
  2022-06-09  3:26 ` [PATCH 21/23] ASoC: SOF: ipc4-topology: Add support for SSP/DMIC DAI's Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-09  3:26 ` [PATCH 23/23] ASoC: SOF: IPC4: add sdw blob Ranjani Sridharan
  2022-06-13 17:13 ` [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Mark Brown
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Péter Ujfalusi, Ranjani Sridharan,
	Pierre-Louis Bossart, broonie, Bard Liao

Define and set the dai_get_clk_op for IPC4.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
---
 sound/soc/sof/ipc4-topology.c | 58 +++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 9f055c187b72..d5cb08ec1af1 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -1511,6 +1511,63 @@ static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index,
 	return 0;
 }
 
+static int sof_ipc4_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type)
+{
+	struct sof_ipc4_copier *ipc4_copier = dai->private;
+	struct snd_soc_tplg_hw_config *hw_config;
+	struct snd_sof_dai_link *slink;
+	bool dai_link_found = false;
+	bool hw_cfg_found = false;
+	int i;
+
+	if (!ipc4_copier)
+		return 0;
+
+	list_for_each_entry(slink, &sdev->dai_link_list, list) {
+		if (!strcmp(slink->link->name, dai->name)) {
+			dai_link_found = true;
+			break;
+		}
+	}
+
+	if (!dai_link_found) {
+		dev_err(sdev->dev, "no DAI link found for DAI %s\n", dai->name);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < slink->num_hw_configs; i++) {
+		hw_config = &slink->hw_configs[i];
+		if (dai->current_config == le32_to_cpu(hw_config->id)) {
+			hw_cfg_found = true;
+			break;
+		}
+	}
+
+	if (!hw_cfg_found) {
+		dev_err(sdev->dev, "no matching hw_config found for DAI %s\n", dai->name);
+		return -EINVAL;
+	}
+
+	switch (ipc4_copier->dai_type) {
+	case SOF_DAI_INTEL_SSP:
+		switch (clk_type) {
+		case SOF_DAI_CLK_INTEL_SSP_MCLK:
+			return le32_to_cpu(hw_config->mclk_rate);
+		case SOF_DAI_CLK_INTEL_SSP_BCLK:
+			return le32_to_cpu(hw_config->bclk_rate);
+		default:
+			dev_err(sdev->dev, "Invalid clk type for SSP %d\n", clk_type);
+			break;
+		}
+		break;
+	default:
+		dev_err(sdev->dev, "DAI type %d not supported yet!\n", ipc4_copier->dai_type);
+		break;
+	}
+
+	return -EINVAL;
+}
+
 static enum sof_tokens host_token_list[] = {
 	SOF_COMP_TOKENS,
 	SOF_AUDIO_FMT_NUM_TOKENS,
@@ -1597,4 +1654,5 @@ const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
 	.route_free = sof_ipc4_route_free,
 	.dai_config = sof_ipc4_dai_config,
 	.parse_manifest = sof_ipc4_parse_manifest,
+	.dai_get_clk = sof_ipc4_dai_get_clk,
 };
-- 
2.25.1


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

* [PATCH 23/23] ASoC: SOF: IPC4: add sdw blob
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
                   ` (21 preceding siblings ...)
  2022-06-09  3:26 ` [PATCH 22/23] AsoC: SOF: ipc4-topology: Add dai_get_clk op Ranjani Sridharan
@ 2022-06-09  3:26 ` Ranjani Sridharan
  2022-06-13 17:13 ` [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Mark Brown
  23 siblings, 0 replies; 25+ messages in thread
From: Ranjani Sridharan @ 2022-06-09  3:26 UTC (permalink / raw)
  To: alsa-devel
  Cc: tiwai, Ranjani Sridharan, Pierre-Louis Bossart, broonie,
	Rander Wang, Bard Liao

From: Bard Liao <yung-chuan.liao@linux.intel.com>

Add IPC4 SoundWire blob. It includes a common IPC4 gateway and a multiple
ALH configuration struct which is used for storing the aggregated
SoundWire stream information.

Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Rander Wang <rander.wang@intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
---
 sound/soc/sof/ipc4-topology.c | 44 +++++++++++++++++++++++++++++++++++
 sound/soc/sof/ipc4-topology.h | 25 ++++++++++++++++++++
 2 files changed, 69 insertions(+)

diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index d5cb08ec1af1..cb0f0823b8eb 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -476,6 +476,20 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
 	ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type);
 
 	switch (ipc4_copier->dai_type) {
+	case SOF_DAI_INTEL_ALH:
+	{
+		struct sof_ipc4_alh_configuration_blob *blob;
+
+		blob = kzalloc(sizeof(*blob), GFP_KERNEL);
+		if (!blob) {
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		ipc4_copier->copier_config = (uint32_t *)blob;
+		ipc4_copier->data.gtw_cfg.config_length = sizeof(*blob) >> 2;
+		break;
+	}
 	case SOF_DAI_INTEL_SSP:
 		/* set SSP DAI index as the node_id */
 		ipc4_copier->data.gtw_cfg.node_id |=
@@ -1053,6 +1067,36 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
 	if (ret < 0)
 		return ret;
 
+	switch (swidget->id) {
+	case snd_soc_dapm_dai_in:
+	case snd_soc_dapm_dai_out:
+	{
+		/*
+		 * Only SOF_DAI_INTEL_ALH needs copier_data to set blob.
+		 * That's why only ALH dai's blob is set after sof_ipc4_init_audio_fmt
+		 */
+		if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) {
+			struct sof_ipc4_alh_configuration_blob *blob;
+			u32 ch_map;
+			int i;
+
+			blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
+			/* TODO: add aggregation mode support */
+			blob->alh_cfg.count = 1;
+			blob->alh_cfg.mapping[0].alh_id = copier_data->gtw_cfg.node_id;
+			blob->gw_attr.lp_buffer_alloc = 0;
+
+			/* Get channel_mask from ch_map */
+			ch_map = copier_data->base_config.audio_fmt.ch_map;
+			for (i = 0; ch_map; i++) {
+				if ((ch_map & 0xf) != 0xf)
+					blob->alh_cfg.mapping[0].channel_mask |= BIT(i);
+				ch_map >>= 4;
+			}
+		}
+	}
+	}
+
 	/* modify the input params for the next widget */
 	fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT);
 	out_sample_valid_bits =
diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h
index 64d836f05bad..1a9c0627bae9 100644
--- a/sound/soc/sof/ipc4-topology.h
+++ b/sound/soc/sof/ipc4-topology.h
@@ -40,6 +40,8 @@
 #define SOF_IPC4_GAIN_ALL_CHANNELS_MASK 0xffffffff
 #define SOF_IPC4_VOL_ZERO_DB	0x7fffffff
 
+#define ALH_MAX_NUMBER_OF_GTW   16
+
 /**
  * struct sof_ipc4_pipeline - pipeline config data
  * @priority: Priority of this pipeline
@@ -112,6 +114,29 @@ struct sof_ipc4_gtw_attributes {
 	uint32_t rsvd : 30;
 };
 
+/** struct sof_ipc4_alh_multi_gtw_cfg: ALH gateway cfg data
+ * @count: Number of streams (valid items in mapping array)
+ * @alh_id: ALH stream id of a single ALH stream aggregated
+ * @channel_mask: Channel mask
+ * @mapping: ALH streams
+ */
+struct sof_ipc4_alh_multi_gtw_cfg {
+	uint32_t count;
+	struct {
+		uint32_t alh_id;
+		uint32_t channel_mask;
+	} mapping[ALH_MAX_NUMBER_OF_GTW];
+} __packed;
+
+/** struct sof_ipc4_alh_configuration_blob: ALH blob
+ * @gw_attr: Gateway attributes
+ * @alh_cfg: ALH configuration data
+ */
+struct sof_ipc4_alh_configuration_blob {
+	struct sof_ipc4_gtw_attributes gw_attr;
+	struct sof_ipc4_alh_multi_gtw_cfg alh_cfg;
+};
+
 /**
  * struct sof_ipc4_copier - copier config data
  * @data: IPC copier data
-- 
2.25.1


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

* Re: [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops
  2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
                   ` (22 preceding siblings ...)
  2022-06-09  3:26 ` [PATCH 23/23] ASoC: SOF: IPC4: add sdw blob Ranjani Sridharan
@ 2022-06-13 17:13 ` Mark Brown
  23 siblings, 0 replies; 25+ messages in thread
From: Mark Brown @ 2022-06-13 17:13 UTC (permalink / raw)
  To: ranjani.sridharan, alsa-devel; +Cc: tiwai

On Wed, 8 Jun 2022 20:26:20 -0700, Ranjani Sridharan wrote:
> This set of patches includes changes to add the topology, control and
> PCM ops for IPC4. It also includes a couple of patches to set the IPC4
> BE DAI trigger ops for SSP/DMIC/HDA type DAI's.
> 
> Bard Liao (1):
>   ASoC: SOF: IPC4: add sdw blob
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next

Thanks!

[01/23] ASoC: SOF: Add topology tokens for IPC4
        commit: bd10cd5ec54616a488d0bda695f78694ad79f779
[02/23] ASoC: SOF: IPC4: Introduce topology ops
        commit: 90e891551fb4949daeb3df20d43e7da838ef89a3
[03/23] ASoC: SOF: ipc4-topology: Add support for parsing AIF_IN/AIF_OUT widgets
        commit: 2cabd02b60901f4ceda4daf8c194905259797702
[04/23] ASoC: SOF: ipc4-topology: Add support for parsing DAI_IN/DAI_OUT widgets
        commit: abfb536bd116d3148e92bf38255fc0989ca9b7d4
[05/23] ASoC: SOF: ipc4-topology: Add prepare op for AIF type widgets
        commit: 904c48c40c66c524df90fb660bdbc514ed802e67
[06/23] ASoC: SOF: ipc4-topology: Add prepare op for DAI type widgets
        commit: acf525942077213e9bc00eee8a73af360ab2fc08
[07/23] ASoC: SOF: ipc4-topology: Add support for parsing and preparing pga widgets
        commit: 4f838ab2081260119677df3ba94dbbd4f8cb7183
[08/23] ASoC: SOF: ipc4-topology: Add support for parsing mixer widgets
        commit: 4d4ba014ac4b3772ed39c15cd2ceacbb071c26f6
[09/23] ASoC: SOF: ipc4-topology: Add control_setup op
        commit: d97964f870786389f4c399a507ffa5d1ebf2a9e4
[10/23] ASoC: SOF: ipc4-topology: Add control IO ops
        commit: 955e84fc0b6df6cfb95ee6f569be809af49d8287
[11/23] ASoC: SOF: IPC4: Add pcm ops
        commit: e75e5db8f8ac5b9d4e8968060822bed4671f22ec
[12/23] ASoC: SOF: ipc4-topology: Add widget_setup/widget_free ops
        commit: 6e9257a13c75b2e4fc33477f9de4912fdfae81e1
[13/23] ASoC: SOF: ipc4-topology: Add route_setup/route_free ops
        commit: 3acd527089463742a3dd95e274d53c2fdd834716
[14/23] ASoC: SOF: ipc4-topology: Add the dai_config op
        commit: acf48a1f76b887f6a63f3c91eedac80b38341c05
[15/23] ASoC: SOF: ipc4-pcm: Expose sof_ipc4_set_pipeline_state()
        commit: d0c0d5bf944b13b4e293746eb655f1c2caf67231
[16/23] ASoC: SOF: IPC4: set the BE DAI ops
        commit: 4c30004a7c6920c66a08c1aa16481c28202eefd0
[17/23] ASoC: SOF: Add ops_free
        commit: bc433fd76faefb8484f5bc653d846043822a2d35
[18/23] ASoC: SOF: Intel: hda: init NHLT for IPC4
        commit: 1da51943725f29000ae4d2be3b3b4bf8309d99a2
[19/23] ASoC: SOF: Add two new structures for topology manifest data
        commit: 4453d24d10fdd9e40c84673e3eda7701055081ea
[20/23] ASoC: SOF: Add a new IPC op for parsing topology manifest
        commit: 323aa1f093e6113f78a8ae808c6c097663d8cb4c
[21/23] ASoC: SOF: ipc4-topology: Add support for SSP/DMIC DAI's
        commit: aa84ffb721587d134702a1932f2c8793e8709df4
[22/23] AsoC: SOF: ipc4-topology: Add dai_get_clk op
        commit: 9e2b5d33fec938ea2518735f2b66313cab89bb61
[23/23] ASoC: SOF: IPC4: add sdw blob
        commit: a45a4d4390b7a562f8edc3518ba6cd2ad17be5bc

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

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

end of thread, other threads:[~2022-06-13 17:14 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-09  3:26 [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 01/23] ASoC: SOF: Add topology tokens for IPC4 Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 02/23] ASoC: SOF: IPC4: Introduce topology ops Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 03/23] ASoC: SOF: ipc4-topology: Add support for parsing AIF_IN/AIF_OUT widgets Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 04/23] ASoC: SOF: ipc4-topology: Add support for parsing DAI_IN/DAI_OUT widgets Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 05/23] ASoC: SOF: ipc4-topology: Add prepare op for AIF type widgets Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 06/23] ASoC: SOF: ipc4-topology: Add prepare op for DAI " Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 07/23] ASoC: SOF: ipc4-topology: Add support for parsing and preparing pga widgets Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 08/23] ASoC: SOF: ipc4-topology: Add support for parsing mixer widgets Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 09/23] ASoC: SOF: ipc4-topology: Add control_setup op Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 10/23] ASoC: SOF: ipc4-topology: Add control IO ops Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 11/23] ASoC: SOF: IPC4: Add pcm ops Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 12/23] ASoC: SOF: ipc4-topology: Add widget_setup/widget_free ops Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 13/23] ASoC: SOF: ipc4-topology: Add route_setup/route_free ops Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 14/23] ASoC: SOF: ipc4-topology: Add the dai_config op Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 15/23] ASoC: SOF: ipc4-pcm: Expose sof_ipc4_set_pipeline_state() Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 16/23] ASoC: SOF: IPC4: set the BE DAI ops Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 17/23] ASoC: SOF: Add ops_free Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 18/23] ASoC: SOF: Intel: hda: init NHLT for IPC4 Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 19/23] ASoC: SOF: Add two new structures for topology manifest data Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 20/23] ASoC: SOF: Add a new IPC op for parsing topology manifest Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 21/23] ASoC: SOF: ipc4-topology: Add support for SSP/DMIC DAI's Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 22/23] AsoC: SOF: ipc4-topology: Add dai_get_clk op Ranjani Sridharan
2022-06-09  3:26 ` [PATCH 23/23] ASoC: SOF: IPC4: add sdw blob Ranjani Sridharan
2022-06-13 17:13 ` [PATCH 00/23] ASoC: SOF: IPC4: Add topology, control and PCM ops Mark Brown

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.