diff mbox

[RFC,2/7] ASoC: hda: add helper to configure module params

Message ID 1429390653-8194-3-git-send-email-vinod.koul@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Vinod Koul April 18, 2015, 8:57 p.m. UTC
From: Jeeja KP <jeeja.kp@intel.com>

This add helper functions to create module
parameter for module IPC msg

Signed-off-by: Jeeja KP <jeeja.kp@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
---
 sound/soc/hda/hda_dsp_controls.h |  338 ++++++++++++++++++++++++++++++++
 sound/soc/hda/hda_soc_dsp.c      |  395 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 733 insertions(+)
 create mode 100644 sound/soc/hda/hda_dsp_controls.h

Comments

Mark Brown April 24, 2015, 5:38 p.m. UTC | #1
On Sun, Apr 19, 2015 at 02:27:28AM +0530, Vinod Koul wrote:
> From: Jeeja KP <jeeja.kp@intel.com>
> 
> This add helper functions to create module
> parameter for module IPC msg

This feels like it's abstracting between two different driver internal
formats but it's not entirely clear to me.  I'm lacking some big picture
stuff here.
Vinod Koul April 26, 2015, 2:06 p.m. UTC | #2
On Fri, Apr 24, 2015 at 06:38:30PM +0100, Mark Brown wrote:
> On Sun, Apr 19, 2015 at 02:27:28AM +0530, Vinod Koul wrote:
> > From: Jeeja KP <jeeja.kp@intel.com>
> > 
> > This add helper functions to create module
> > parameter for module IPC msg
> 
> This feels like it's abstracting between two different driver internal
> formats but it's not entirely clear to me.  I'm lacking some big picture
> stuff here.
Okay, let me try :)

So before this we had posted SKL base PCM driver which was doing HDA stuff
only. Earlier this week you reviewed the SST-IPC driver series, that was
sending IPCs to DSP.
The other series you reviewed with this invokes those IPCs from SKL platform
driver. This series is about DAPM widget handlers and driver changes for
handling DSP.

The SKL supports HDA + DSP and HDA/I2S codecs.

We have one more series which will be missing link. Since we use the
topology/DFW for defining the widgets and map, they are not coded in driver.
That will be sent once topology patches are accepted

Thanks for reviewing the RFCs, I will rework the series and post them in
sequence which would be:
- SKL PCM driver first
- ASoC bus handling wrapper code
- IPC driver
- SKL dapm widget handling and aDSP support
- lastly support for topology to load the DAIs/widgets/map

One more would be ASoC HDA codecs but that can merged independent of these

The core HDA changes are mostly done so that dependency is no longer issue.
Though that code is targeted for next merge window, I think we need to
merge topic/hda from Takashi's tree to yours as well or whatever way you
both feel comfortable..

Do let me know if you have more questions, yes that is a lot of code coming
you way

Thanks
diff mbox

Patch

diff --git a/sound/soc/hda/hda_dsp_controls.h b/sound/soc/hda/hda_dsp_controls.h
new file mode 100644
index 000000000000..6bd83db94009
--- /dev/null
+++ b/sound/soc/hda/hda_dsp_controls.h
@@ -0,0 +1,338 @@ 
+/*
+ *  soc-hda-controls.h - Intel HDA Platform controls header file
+ *
+ *  Copyright (C) 2014-15 Intel Corp
+ *  Author: Jeeja KP <jeeja.kp@intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+
+#ifndef __SOC_HDA_DSP_CONTROLS_H__
+#define __SOC_HDA_DSP_CONTROLS_H__
+
+#include <linux/types.h>
+
+#define BITS_PER_BYTE 8
+
+/* Maximum number of coefficients up down mixer module */
+#define UP_DOWN_MIXER_MAX_COEFF		6
+
+enum ssth_channel_index {
+	SSTH_CHANNEL_LEFT = 0,
+	SSTH_CHANNEL_CENTER = 1,
+	SSTH_CHANNEL_RIGHT = 2,
+	SSTH_CHANNEL_LEFT_SURROUND = 3,
+	SSTH_CHANNEL_CENTER_SURROUND = 3,
+	SSTH_CHANNEL_RIGHT_SURROUND = 4,
+	SSTH_CHANNEL_LFE = 7,
+	SSTH_CHANNEL_INVALID = 0xF,
+};
+
+enum ssth_channel_config {
+	SSTH_CHANNEL_CONFIG_MONO = 0, /* One channel only. */
+	SSTH_CHANNEL_CONFIG_STEREO = 1, /* L & R. */
+	SSTH_CHANNEL_CONFIG_2_1 = 2, /* L, R & LFE; PCM only. */
+	SSTH_CHANNEL_CONFIG_3_0 = 3, /* L, C & R; MP3 & AAC only. */
+	SSTH_CHANNEL_CONFIG_3_1 = 4, /* L, C, R & LFE; PCM only. */
+	SSTH_CHANNEL_CONFIG_QUATRO = 5, /* L, R, Ls & Rs; PCM only. */
+	SSTH_CHANNEL_CONFIG_4_0 = 6, /* L, C, R & Cs; MP3 & AAC only. */
+	SSTH_CHANNEL_CONFIG_5_0 = 7, /* L, C, R, Ls & Rs. */
+	SSTH_CHANNEL_CONFIG_5_1 = 8, /* L, C, R, Ls, Rs & LFE. */
+	SSTH_CHANNEL_CONFIG_DUAL_MONO = 9, /* One channel replicated in two. */
+	SSTH_CHANNEL_CONFIG_I2S_DUAL_STEREO_0 = 10, /* Stereo(L,R) in 4 slots,
+						    1st stream:[ L, R, -, - ]
+						    */
+	SSTH_CHANNEL_CONFIG_I2S_DUAL_STEREO_1 = 11, /* Stereo(L,R) in 4 slots,
+						    2nd stream:[ -, -, L, R ]
+						    */
+	SSTH_CHANNEL_CONFIG_INVALID
+};
+
+enum ssth_bitdepth {
+	SSTH_DEPTH_8BIT = 8,
+	SSTH_DEPTH_16BIT = 16,
+	SSTH_DEPTH_24BIT = 24, /**< Default. */
+	SSTH_DEPTH_32BIT = 32,
+	SSTH_DEPTH_INVALID
+};
+
+enum ssth_interleaving_style {
+	SSTH_INTERLEAVING_PER_CHANNEL = 0, /* [s1_ch1...s1_chN,...,sM_ch1...sM_chN] */
+	SSTH_INTERLEAVING_PER_SAMPLE = 1, /* [s1_ch1...sM_ch1,...,s1_chN...sM_chN] */
+};
+
+enum ssth_sampling_frequency {
+	SSTH_FS_8000HZ = 8000,
+	SSTH_FS_11025HZ = 11025,
+	SSTH_FS_12000HZ = 12000, /** Mp3, AAC, SRC only. */
+	SSTH_FS_16000HZ = 16000,
+	SSTH_FS_22050HZ = 22050,
+	SSTH_FS_24000HZ = 24000, /** Mp3, AAC, SRC only. */
+	SSTH_FS_32000HZ = 32000,
+	SSTH_FS_44100HZ = 44100,
+	SSTH_FS_48000HZ = 48000, /**< Default. */
+	SSTH_FS_64000HZ = 64000, /** AAC, SRC only. */
+	SSTH_FS_88200HZ = 88200, /** AAC, SRC only. */
+	SSTH_FS_96000HZ = 96000, /** AAC, SRC only. */
+	SSTH_FS_128000HZ = 128000, /** SRC only. */
+	SSTH_FS_176400HZ = 176400, /** SRC only. */
+	SSTH_FS_192000HZ = 192000, /** SRC only. */
+	SSTH_FS_INVALID
+};
+
+enum ssth_widget_type {
+	SSTH_WIDGET_VMIXER = 1,
+	SSTH_WIDGET_MIXER = 2,
+	SSTH_WIDGET_PGA = 3,
+	SSTH_WIDGET_MUX = 4
+};
+
+struct ssth_audio_data_format {
+	enum ssth_sampling_frequency sampling_frequency;
+	enum ssth_bitdepth bit_depth;
+	u32 channel_map;
+	enum ssth_channel_config channel_config;
+	enum ssth_interleaving_style interleaving_style;
+	u8 number_of_channels;
+	u8 valid_bit_depth;
+	u8 sample_type;
+	u8 reserved[1];
+} __packed;
+
+struct ssth_base_module_config {
+	u32 cps;
+	u32 ibs;
+	u32 obs;
+	u32 is_pages;
+	struct ssth_audio_data_format audio_fmt;
+};
+
+struct ssth_copiergateway_cfg {
+	u32 node_id;
+	u32 dma_buffer_size;
+	u32 config_length;
+	u32 config_data[1]; /*not mandatory; required only for DMIC/I2S */
+} __packed;
+
+struct ssth_copier_module_config {
+	struct ssth_base_module_config base_module_config;
+	struct ssth_audio_data_format out_fmt;
+	u32 cpr_feature_mask;
+	struct ssth_copiergateway_cfg gtw_cfg;
+} __packed;
+
+struct ssth_src_config {
+	enum ssth_sampling_frequency s_freq;
+} __packed;
+
+struct ssth_src_module_config {
+	struct ssth_base_module_config base_module_config;
+	struct ssth_src_config src_config;
+} __packed;
+
+struct ssth_up_down_mixer_module_config {
+	struct ssth_base_module_config base_module_config;
+	enum ssth_channel_config out_channel_config;
+	/* This should be set to 1 if user coefficients are required */
+	u32 coeff_sel;
+	/* Pass the user coeff in this array */
+	s32 coeff[UP_DOWN_MIXER_MAX_COEFF];
+} __packed;
+
+enum ssth_dma_type {
+	SSTH_DMA_TYPE_HDA_HOST_OUTPUT_CLASS = 0,
+	SSTH_DMA_TYPE_HDA_HOST_INPUT_CLASS = 1,
+	SSTH_DMA_TYPE_HDA_HOST_INOUT_CLASS = 2,
+	SSTH_DMA_TYPE_HDA_LINK_OUTPUT_CLASS = 8,
+	SSTH_DMA_TYPE_HDA_LINK_INPUT_CLASS = 9,
+	SSTH_DMA_TYPE_HDA_LINK_INOUT_CLASS = 0xA,
+	SSTH_DMA_TYPE_DMIC_LINK_INPUT_CLASS = 0xB,
+	SSTH_DMA_TYPE_I2S_LINK_OUTPUT_CLASS = 0xC,
+	SSTH_DMA_TYPE_I2S_LINK_INPUT_CLASS = 0xD,
+};
+
+union ssth_ssp_dma_node {
+	u8 val;
+	struct {
+		u8 dual_mono:1;
+		u8 time_slot:3;
+		u8 i2s_instance:4;
+	} dma_node;
+};
+
+union ssth_connector_node_id {
+	u32 val;
+	struct {
+		u32 dma_id:8; /* DMA engine ID */
+		u32 dma_type:4;
+		u32 rsvd:20;
+	} node;
+};
+
+enum ssth_fw_pipeline_type {
+	SSTH_PIPELINE_TYPE_DECODE = 0,
+	SSTH_PIPELINE_TYPE_MIXER = 1,
+	SSTH_PIPELINE_TYPE_REFERENCE = 2,
+	SSTH_PIPELINE_TYPE_CAPTURE = 3
+};
+
+enum ssth_core_affinity {
+	SSTH_AFFINITY_CORE_0 = 0,
+	SSTH_AFFINITY_CORE_1,
+	SSTH_AFFINITY_CORE_MAX
+};
+
+struct ssth_module_format {
+	u32 channels;
+	u32 sampling_freq;
+	u32 bit_depth;
+	u32 valid_bit_depth;
+	u32 channel_config;
+};
+
+struct ssth_module_instance_id {
+	u32 module_id;
+	u32 instance_id;
+};
+
+struct ssth_specific_config {
+	u32 caps_size;
+	u32 *caps;
+};
+
+enum ssth_pipe_state {
+	SSTH_PIPE_STATE_INVALID = 0,
+	SSTH_PIPE_STATE_CREATED = 1,
+	SSTH_PIPE_STATE_PAUSED = 2,
+	SSTH_PIPE_STATE_STARTED = 3
+};
+
+struct ssth_pipe_module {
+	struct snd_soc_dapm_widget *w;
+	struct list_head node;
+};
+
+struct ssth_pipe {
+	u8 ppl_id;
+	u8 pipe_priority;
+	u16 conn_type;
+	u32 memory_pages;
+	enum ssth_pipe_state state;
+	struct list_head w_list;
+};
+
+enum ssth_module_state {
+	SSTH_MODULE_STATE_UNINIT = 0,
+	SSTH_MODULE_STATE_INIT_DONE = 1,
+	SSTH_MODULE_STATE_LOADED = 2,
+	SSTH_MODULE_STATE_UNLOADED = 3,
+	SSTH_MODULE_STATE_BIND_DONE = 4
+};
+
+enum ssth_module_type {
+	SSTH_BASE_FW_MODULE = 0,
+	SSTH_BASE_MIX_IN_MODULE,
+	SSTH_BASE_MIX_OUT_MODULE,
+	SSTH_COPIER_MODULE,
+	SSTH_UPDWMIX_MODULE,
+	SSTH_SRCINT_MODULE,
+	SSTH_MAX_MODULE
+};
+
+enum ssth_dev_type {
+	SSTH_DEVICE_BT = 0x0,
+	SSTH_DEVICE_DMIC = 0x1,
+	SSTH_DEVICE_I2S = 0x2,
+	SSTH_DEVICE_SLIMBUS = 0x3,
+	SSTH_DEVICE_HDALINK = 0x4,
+	SSTH_DEVICE_NONE
+};
+
+enum ssth_pipe_conn_type {
+	SSTH_PIPE_CONN_TYPE_NONE = 0,
+	SSTH_PIPE_CONN_TYPE_FE,
+	SSTH_PIPE_CONN_TYPE_BE
+};
+
+enum ssth_module_conn_type {
+	SSTH_CONN_NONE = 0,
+	SSTH_CONN_SOURCE = 1,
+	SSTH_CONN_SINK = 2
+};
+
+struct ssth_sink_module {
+	struct list_head node;
+	struct ssth_module_instance_id id;
+	u8 in_queue;
+};
+
+struct ssth_module_config {
+	struct ssth_module_instance_id id;
+	struct ssth_module_format in_fmt;
+	struct ssth_module_format out_fmt;
+	u8 max_in_queue;
+	u8 max_out_queue;
+	u8 in_queue_mask;
+	u8 out_queue_mask;
+	u8 in_queue;
+	u8 out_queue;
+	u32 mcps;
+	u32 ibs;
+	u32 obs;
+	u8 is_loadable;
+	u8 core_id;
+	u8 conn_type;
+	u8 dev_type;
+	u8 dma_id;
+	u8 time_slot;
+	u32 params_fixup;
+	u32 converter;
+	struct list_head sink_list;
+	enum ssth_module_conn_type  hw_conn_type;
+	enum ssth_module_state m_state;
+	struct ssth_pipe *pipe;
+	struct ssth_specific_config formats_config;
+};
+
+/* Event types goes here */
+/* Reserve event type 0 for no event handlers */
+enum ssth_event_types {
+	HDA_SST_EVENT_TYPE_NONE = 0,
+	HDA_SST_SET_MIXER,
+	HDA_SST_SET_MUX,
+	HDA_SST_SET_VMIXER,
+	HDA_SST_SET_PGA
+};
+
+struct hda_sst_algo_data {
+	u32 max;
+	char *params;
+};
+
+struct ssth_pipeline {
+	struct ssth_pipe *pipe;
+	struct list_head node;
+};
+
+int ssth_create_pipeline(struct ssth_lib *ctx, struct ssth_pipe *pipe);
+int ssth_run_pipe(struct ssth_lib *ctx, struct ssth_pipe *pipe);
+int ssth_pause_pipe(struct ssth_lib *ctx, struct ssth_pipe *pipe);
+int ssth_delete_pipe(struct ssth_lib *ctx, struct ssth_pipe *pipe);
+int ssth_stop_pipe(struct ssth_lib *ctx, struct ssth_pipe *pipe);
+int ssth_init_module(struct ssth_lib *ctx, struct ssth_module_config *module_config,
+	struct hda_sst_algo_data *ac);
+int ssth_bind_unbind_modules(struct ssth_lib *ctx, struct ssth_module_config
+	*src_module, struct ssth_module_config *dst_module, bool bind);
+enum ssth_bitdepth ssth_get_bit_depth(struct snd_pcm_hw_params *params);
+#endif
diff --git a/sound/soc/hda/hda_soc_dsp.c b/sound/soc/hda/hda_soc_dsp.c
index 3fa033ecaa90..fea47645368e 100644
--- a/sound/soc/hda/hda_soc_dsp.c
+++ b/sound/soc/hda/hda_soc_dsp.c
@@ -28,6 +28,7 @@ 
 #include <sound/soc-hda-sst-dsp.h>
 #include <sound/soc-hda-sst-ipc.h>
 #include "hda_skl.h"
+#include "hda_dsp_controls.h"
 
 int ssth_dsp_register(struct hda_soc_bus *schip)
 {
@@ -60,3 +61,397 @@  void ssth_dsp_unregister(struct hda_soc_bus *schip)
 	if (schip->dsp->mmio_base)
 		iounmap(schip->dsp->mmio_base);
 }
+
+enum ssth_bitdepth ssth_get_bit_depth(struct snd_pcm_hw_params *params)
+{
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		return SSTH_DEPTH_8BIT;
+
+	case SNDRV_PCM_FORMAT_S16_LE:
+		return SSTH_DEPTH_16BIT;
+
+	case SNDRV_PCM_FORMAT_S24_LE:
+		return SSTH_DEPTH_24BIT;
+
+	case SNDRV_PCM_FORMAT_S32_LE:
+		return SSTH_DEPTH_32BIT;
+	default:
+		return SSTH_DEPTH_INVALID;
+	}
+}
+
+static u32 hda_sst_create_channel_map(enum ssth_channel_config channel_config)
+{
+	u32 config;
+
+	switch (channel_config) {
+	case SSTH_CHANNEL_CONFIG_MONO:
+		config =  (0xFFFFFFF0 | SSTH_CHANNEL_CENTER);
+	break;
+
+	case SSTH_CHANNEL_CONFIG_STEREO:
+		config = (0xFFFFFF00 | SSTH_CHANNEL_LEFT
+			| (SSTH_CHANNEL_RIGHT << 4));
+	break;
+
+	case SSTH_CHANNEL_CONFIG_2_1:
+		config = (0xFFFFF000 | SSTH_CHANNEL_LEFT
+			| (SSTH_CHANNEL_RIGHT << 4)
+			| (SSTH_CHANNEL_LFE << 8));
+	break;
+
+	case SSTH_CHANNEL_CONFIG_3_0:
+		config =  (0xFFFFF000 | SSTH_CHANNEL_LEFT
+			| (SSTH_CHANNEL_CENTER << 4)
+			| (SSTH_CHANNEL_RIGHT << 8));
+	break;
+
+	case SSTH_CHANNEL_CONFIG_3_1:
+		config = (0xFFFF0000 | SSTH_CHANNEL_LEFT
+			| (SSTH_CHANNEL_CENTER << 4)
+			| (SSTH_CHANNEL_RIGHT << 8)
+			| (SSTH_CHANNEL_LFE << 12));
+	break;
+
+	case SSTH_CHANNEL_CONFIG_QUATRO:
+		config = (0xFFFF0000 | SSTH_CHANNEL_LEFT
+			| (SSTH_CHANNEL_RIGHT << 4)
+			| (SSTH_CHANNEL_LEFT_SURROUND << 8)
+			| (SSTH_CHANNEL_RIGHT_SURROUND << 12));
+	break;
+
+	case SSTH_CHANNEL_CONFIG_4_0:
+		config = (0xFFFF0000 | SSTH_CHANNEL_LEFT
+			| (SSTH_CHANNEL_CENTER << 4)
+			| (SSTH_CHANNEL_RIGHT << 8)
+			| (SSTH_CHANNEL_CENTER_SURROUND << 12));
+	break;
+
+	case SSTH_CHANNEL_CONFIG_5_0:
+		config = (0xFFF00000 | SSTH_CHANNEL_LEFT
+			| (SSTH_CHANNEL_CENTER << 4)
+			| (SSTH_CHANNEL_RIGHT << 8)
+			| (SSTH_CHANNEL_LEFT_SURROUND << 12)
+			| (SSTH_CHANNEL_RIGHT_SURROUND << 16));
+	break;
+
+	case SSTH_CHANNEL_CONFIG_5_1:
+		config = (0xFF000000 | SSTH_CHANNEL_CENTER
+			| (SSTH_CHANNEL_LEFT << 4)
+			| (SSTH_CHANNEL_RIGHT << 8)
+			| (SSTH_CHANNEL_LEFT_SURROUND << 12)
+			| (SSTH_CHANNEL_RIGHT_SURROUND << 16)
+			| (SSTH_CHANNEL_LFE << 20));
+	break;
+
+	case SSTH_CHANNEL_CONFIG_DUAL_MONO:
+		config = (0xFFFFFF00 | SSTH_CHANNEL_LEFT
+			| (SSTH_CHANNEL_LEFT << 4));
+	break;
+
+	case SSTH_CHANNEL_CONFIG_I2S_DUAL_STEREO_0:
+		config = (0xFFFFFF00 | SSTH_CHANNEL_LEFT
+			| (SSTH_CHANNEL_RIGHT << 4));
+	break;
+
+	case SSTH_CHANNEL_CONFIG_I2S_DUAL_STEREO_1:
+		config = (0xFFFF00FF | (SSTH_CHANNEL_LEFT << 8)
+			| (SSTH_CHANNEL_RIGHT << 12));
+	break;
+	default:
+		config =  0xFFFFFFFF;
+	}
+	return config;
+}
+
+/*
+ * Fills in base_module_config structure .
+ * base_module_config is sent as input buffer with INIT_INSTANCE IPC msg
+ */
+static void ssth_set_base_module_format(struct ssth_lib *ctx,
+	struct ssth_module_config *mconfig,
+	struct ssth_base_module_config *base_module_config)
+{
+	struct ssth_module_format *format = &mconfig->in_fmt;
+
+	base_module_config->audio_fmt.number_of_channels =
+		(u8)format->channels;
+
+	base_module_config->audio_fmt.sampling_frequency = format->sampling_freq;
+	base_module_config->audio_fmt.bit_depth = format->bit_depth;
+	base_module_config->audio_fmt.valid_bit_depth = format->valid_bit_depth;
+	base_module_config->audio_fmt.channel_config = format->channel_config;
+
+	dev_dbg(ctx->dev, "bit_depth=%x valid_bd=%x ch_config=%x\n", format->bit_depth,
+			format->valid_bit_depth, format->channel_config);
+
+	base_module_config->audio_fmt.channel_map =
+		hda_sst_create_channel_map(
+			base_module_config->audio_fmt.channel_config);
+
+	base_module_config->audio_fmt.interleaving_style =
+		SSTH_INTERLEAVING_PER_CHANNEL;
+
+	base_module_config->cps = mconfig->mcps;
+	base_module_config->ibs = mconfig->ibs;
+	base_module_config->obs = mconfig->obs;
+	base_module_config->is_pages = 0;
+
+}
+
+/*
+ * Copies copier capabilities into copier module and updates copier module
+ * config size.
+ */
+static void ssth_copy_copier_caps(struct ssth_module_config *mconfig,
+	struct ssth_copier_module_config *cpr_mconfig)
+{
+	if (mconfig->formats_config.caps_size == 0)
+		return;
+
+	memcpy(cpr_mconfig->gtw_cfg.config_data,
+		mconfig->formats_config.caps,
+		mconfig->formats_config.caps_size);
+
+	cpr_mconfig->gtw_cfg.config_length =
+		 (mconfig->formats_config.caps_size) / 4;
+}
+
+static void ssth_setup_cpr_gateway_cfg(struct ssth_lib *ctx,
+	struct ssth_module_config *mconfig,
+	struct ssth_copier_module_config *cpr_mconfig)
+{
+	union ssth_connector_node_id node_id = {0};
+
+	switch (mconfig->dev_type) {
+	case SSTH_DEVICE_BT:
+		node_id.node.dma_type =
+			(SSTH_CONN_SOURCE == mconfig->conn_type) ?
+			SSTH_DMA_TYPE_I2S_LINK_OUTPUT_CLASS :
+			SSTH_DMA_TYPE_I2S_LINK_INPUT_CLASS;
+		node_id.node.dma_id = mconfig->dma_id;
+		break;
+
+	case SSTH_DEVICE_I2S:
+		node_id.node.dma_type =
+			(SSTH_CONN_SOURCE == mconfig->conn_type) ?
+			SSTH_DMA_TYPE_I2S_LINK_OUTPUT_CLASS :
+			SSTH_DMA_TYPE_I2S_LINK_INPUT_CLASS;
+		node_id.node.dma_id = mconfig->dma_id +
+					 (mconfig->time_slot << 1);
+		break;
+
+	case SSTH_DEVICE_DMIC:
+		node_id.node.dma_type = SSTH_DMA_TYPE_DMIC_LINK_INPUT_CLASS;
+		node_id.node.dma_id = mconfig->dma_id +
+					 (mconfig->time_slot);
+		break;
+
+	case SSTH_DEVICE_HDALINK:
+		node_id.node.dma_type =
+			(SSTH_CONN_SOURCE == mconfig->conn_type) ?
+			SSTH_DMA_TYPE_HDA_LINK_OUTPUT_CLASS :
+			SSTH_DMA_TYPE_HDA_LINK_INPUT_CLASS;
+		node_id.node.dma_id = mconfig->dma_id;
+		break;
+	
+	default:
+		node_id.node.dma_type =
+			(SSTH_CONN_SOURCE == mconfig->conn_type) ?
+			SSTH_DMA_TYPE_HDA_HOST_OUTPUT_CLASS :
+			SSTH_DMA_TYPE_HDA_HOST_INPUT_CLASS;
+		node_id.node.dma_id = mconfig->dma_id;
+		break;
+	}
+
+	cpr_mconfig->gtw_cfg.node_id = node_id.val;
+
+	if (SSTH_CONN_SOURCE == mconfig->conn_type)
+		cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->obs;
+	else
+		cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->ibs;
+	cpr_mconfig->cpr_feature_mask = 0;
+	cpr_mconfig->gtw_cfg.config_length  = 0;
+
+	ssth_copy_copier_caps(mconfig, cpr_mconfig);
+	dev_dbg(ctx->dev, "Copier module config:\n");
+	dev_dbg(ctx->dev, "length: 0x%x\n", cpr_mconfig->gtw_cfg.config_length);
+}
+
+static void ssth_setup_cpr_out_format(struct ssth_lib *ctx,
+	struct ssth_module_config *mconfig,
+	struct ssth_copier_module_config *cpr_mconfig)
+{
+	struct ssth_module_format *format = &mconfig->out_fmt;
+
+	cpr_mconfig->out_fmt.number_of_channels =
+		(u8)format->channels;
+
+	cpr_mconfig->out_fmt.sampling_frequency = format->sampling_freq;
+
+	cpr_mconfig->out_fmt.bit_depth = format->bit_depth;
+
+	cpr_mconfig->out_fmt.valid_bit_depth = format->valid_bit_depth;
+
+	cpr_mconfig->out_fmt.channel_config = format->channel_config;
+
+	cpr_mconfig->out_fmt.channel_map =
+		hda_sst_create_channel_map(cpr_mconfig->out_fmt.channel_config);
+	cpr_mconfig->out_fmt.interleaving_style = SSTH_INTERLEAVING_PER_CHANNEL;
+
+
+	dev_dbg(ctx->dev, "copier out format chan=%d fre=%d bitdepth=%d\n",
+		cpr_mconfig->out_fmt.number_of_channels,
+		 format->sampling_freq, format->bit_depth);
+}
+
+static int ssth_set_src_format(struct ssth_lib *ctx,
+	struct ssth_module_config *mconfig,
+	struct ssth_src_module_config *src_mconfig)
+{
+	struct ssth_module_format *fmt = &mconfig->out_fmt;
+
+	ssth_set_base_module_format(ctx,
+		mconfig,
+		(struct ssth_base_module_config *)src_mconfig);
+
+	src_mconfig->src_config.s_freq = fmt->sampling_freq;
+
+	return 0;
+}
+
+static int ssth_set_updown_mixer_format(struct ssth_lib *ctx,
+	struct ssth_module_config *mconfig,
+	struct ssth_up_down_mixer_module_config *mixer_mconfig)
+{
+	int i = 0;
+	struct ssth_module_format *fmt = &mconfig->out_fmt;
+
+	ssth_set_base_module_format(ctx,
+		mconfig,
+		(struct ssth_base_module_config *)mixer_mconfig);
+	mixer_mconfig->out_channel_config = fmt->channel_config;
+
+
+	/* Select F/W defatult coefficient */
+	mixer_mconfig->coeff_sel = 0x0;
+
+	/* User coeff, dont care since we are selecting F/W defaults */
+	for (i = 0; i < UP_DOWN_MIXER_MAX_COEFF; i++)
+		mixer_mconfig->coeff[i] = 0xDEADBEEF;
+
+	return 0;
+}
+
+/*
+ * copier_module_config is sent as input buffer with INIT_INSTANCE IPC msg
+ */
+static int ssth_set_copier_format(struct ssth_lib *ctx,
+	struct ssth_module_config *mconfig,
+	struct ssth_copier_module_config *cpr_mconfig)
+{
+	int ret = 0;
+
+	ssth_set_base_module_format(ctx,
+		mconfig,
+		(struct ssth_base_module_config *)cpr_mconfig);
+
+	ssth_setup_cpr_out_format(ctx, mconfig, cpr_mconfig);
+	ssth_setup_cpr_gateway_cfg(ctx, mconfig, cpr_mconfig);
+
+	return ret;
+}
+
+static u16 ssth_get_module_param_size(struct ssth_lib *ctx,
+	struct ssth_module_config *mconfig)
+{
+	u16 param_size = 0;
+
+	if (mconfig->id.module_id == SSTH_COPIER_MODULE) {
+		param_size = sizeof(struct ssth_copier_module_config);
+		param_size += mconfig->formats_config.caps_size;
+		return param_size;
+	} else if (mconfig->id.module_id == SSTH_SRCINT_MODULE)
+		return sizeof(struct ssth_src_module_config);
+	else if (mconfig->id.module_id == SSTH_UPDWMIX_MODULE)
+		return sizeof(struct ssth_up_down_mixer_module_config);
+	else
+		return sizeof(struct ssth_base_module_config);
+	return param_size;
+}
+
+static int ssth_set_module_format(struct ssth_lib *ctx,
+	struct ssth_module_config *module_config,
+	u16 *module_config_size,
+	void **param_data)
+{
+	u16 param_size;
+	int i = 0, ret = 0;
+	u32 *byte;
+
+	param_size  = ssth_get_module_param_size(ctx, module_config);
+
+	*param_data = kzalloc(param_size, GFP_KERNEL);
+
+	if (NULL == *param_data)
+		return -ENOMEM;
+
+	memset(*param_data, 0, param_size);
+
+	*module_config_size = param_size;
+
+	if (module_config->id.module_id == SSTH_COPIER_MODULE)
+		ret = ssth_set_copier_format(ctx, module_config,
+			*param_data);
+	else if (module_config->id.module_id == SSTH_SRCINT_MODULE)
+		ret =  ssth_set_src_format(ctx, module_config, *param_data);
+	else if (module_config->id.module_id == SSTH_UPDWMIX_MODULE)
+		ret =  ssth_set_updown_mixer_format(ctx, module_config,
+						 *param_data);
+	else
+		ssth_set_base_module_format(ctx, module_config, *param_data);
+
+	*module_config_size = param_size;
+
+	dev_dbg(ctx->dev, "Module type=%d config size: %d bytes\n",
+			module_config->id.module_id, param_size);
+	for (i = 0, byte = (u32 *) *param_data;
+		i < (param_size)/sizeof(u32);
+		i++, byte++) {
+		dev_dbg(ctx->dev, "0x%x: %08x\n", i, *byte);
+	}
+	return ret;
+}
+
+/*
+ * Allocates queue in the link pipeline (mix in/out module)
+ */
+static u8 ssth_alloc_queue(u8 *queue_mask, u8 max_queue, u8 queue_index)
+{
+	while (*queue_mask & (1llu <<  queue_index)) {
+		queue_index++;
+		if (queue_index  == max_queue) {
+			queue_index = 0;
+			*queue_mask = 0;
+			break;
+		}
+	}
+
+	*queue_mask |= (1llu <<  queue_index);
+
+	return queue_index;
+}
+
+static int ssth_free_queue(u8 *queue_mask, u8 queue_index)
+{
+	if (queue_index > 0)
+		*queue_mask &= ~(queue_index);
+	else
+		 *queue_mask &= queue_index;
+	if (queue_index > 0)
+		return queue_index - 1;
+	else
+		return queue_index;
+}