dsp: Update ADM driver to support 32 ch

ADM supports now up to 32 channels. Extend the
ADM Channel map structures from 8 to 32
channels.

Change-Id: I87b3e4cce850af92467b139da9df67fcdafaf0b0
Signed-off-by: Dieter Luecking <dieterl@codeaurora.org>
Signed-off-by: Mangesh Kunchamwar <mangeshk@codeaurora.org>
Signed-off-by: Dhanalakshmi Siddani <dsiddani@codeaurora.org>
diff --git a/dsp/q6adm.c b/dsp/q6adm.c
index c313fdc..3877b1b 100644
--- a/dsp/q6adm.c
+++ b/dsp/q6adm.c
@@ -23,6 +23,7 @@
 #include <dsp/q6adm-v2.h>
 #include <dsp/q6audio-v2.h>
 #include <dsp/q6afe-v2.h>
+#include <dsp/q6core.h>
 #include <dsp/audio_cal_utils.h>
 #include <ipc/apr.h>
 #include "adsp_err.h"
@@ -105,24 +106,32 @@
 	int num_ec_ref_rx_chans;
 	int ec_ref_rx_bit_width;
 	int ec_ref_rx_sampling_rate;
+
+	int native_mode;
 };
 
 static struct adm_ctl			this_adm;
 
 struct adm_multi_ch_map {
 	bool set_channel_map;
-	char channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
+	char channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL_V8];
 };
 
 #define ADM_MCH_MAP_IDX_PLAYBACK 0
 #define ADM_MCH_MAP_IDX_REC 1
 static struct adm_multi_ch_map multi_ch_maps[2] = {
-							{ false,
-							{0, 0, 0, 0, 0, 0, 0, 0}
-							},
-							{ false,
-							{0, 0, 0, 0, 0, 0, 0, 0}
-							}
+			{ false,
+			{0, 0, 0, 0, 0, 0, 0, 0,
+			 0, 0, 0, 0, 0, 0, 0, 0,
+			 0, 0, 0, 0, 0, 0, 0, 0,
+			 0, 0, 0, 0, 0, 0, 0, 0}
+			},
+			{ false,
+			{0, 0, 0, 0, 0, 0, 0, 0,
+			 0, 0, 0, 0, 0, 0, 0, 0,
+			 0, 0, 0, 0, 0, 0, 0, 0,
+			 0, 0, 0, 0, 0, 0, 0, 0}
+			}
 };
 
 static struct adm_multi_ch_map port_channel_map[AFE_MAX_PORTS];
@@ -1423,7 +1432,7 @@
 	}
 
 	memcpy(multi_ch_maps[idx].channel_mapping, channel_map,
-		PCM_FORMAT_MAX_NUM_CHANNEL);
+			PCM_FORMAT_MAX_NUM_CHANNEL_V8);
 	multi_ch_maps[idx].set_channel_map = true;
 
 	return 0;
@@ -1454,7 +1463,7 @@
 
 	if (multi_ch_maps[idx].set_channel_map) {
 		memcpy(channel_map, multi_ch_maps[idx].channel_mapping,
-		       PCM_FORMAT_MAX_NUM_CHANNEL);
+				PCM_FORMAT_MAX_NUM_CHANNEL_V8);
 	}
 
 	return 0;
@@ -1622,6 +1631,7 @@
 			case ADM_CMD_DEVICE_OPEN_V5:
 			case ADM_CMD_DEVICE_CLOSE_V5:
 			case ADM_CMD_DEVICE_OPEN_V6:
+			case ADM_CMD_DEVICE_OPEN_V8:
 				pr_debug("%s: Basic callback received, wake up.\n",
 					__func__);
 				atomic_set(&this_adm.copp.stat[port_idx]
@@ -1718,8 +1728,10 @@
 
 		switch (data->opcode) {
 		case ADM_CMDRSP_DEVICE_OPEN_V5:
-		case ADM_CMDRSP_DEVICE_OPEN_V6: {
-			struct adm_cmd_rsp_device_open_v5 *open = NULL;
+		case ADM_CMDRSP_DEVICE_OPEN_V6:
+		case ADM_CMDRSP_DEVICE_OPEN_V8: {
+			struct adm_cmd_rsp_device_open_v5 *open =
+			(struct adm_cmd_rsp_device_open_v5 *)data->payload;
 
 			if (data->payload_size <
 				sizeof(struct adm_cmd_rsp_device_open_v5)) {
@@ -2643,6 +2655,225 @@
 	return rc;
 }
 
+static int adm_arrange_mch_map_v8(
+		struct adm_device_endpoint_payload *ep_payload,
+		int path,
+		int channel_mode)
+{
+	int rc = 0, idx;
+
+	memset(ep_payload->dev_channel_mapping,
+			0, PCM_FORMAT_MAX_NUM_CHANNEL_V8);
+	switch (path) {
+	case ADM_PATH_PLAYBACK:
+		idx = ADM_MCH_MAP_IDX_PLAYBACK;
+		break;
+	case ADM_PATH_LIVE_REC:
+	case ADM_PATH_NONLIVE_REC:
+		idx = ADM_MCH_MAP_IDX_REC;
+		break;
+	default:
+		goto non_mch_path;
+	};
+
+	if ((ep_payload->dev_num_channel > 2) &&
+			multi_ch_maps[idx].set_channel_map) {
+		memcpy(ep_payload->dev_channel_mapping,
+			multi_ch_maps[idx].channel_mapping,
+			PCM_FORMAT_MAX_NUM_CHANNEL_V8);
+	} else {
+		if (channel_mode == 1) {
+			ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FC;
+		} else if (channel_mode == 2) {
+			ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+			ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+		} else if (channel_mode == 3) {
+			ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+			ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+			ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_FC;
+		} else if (channel_mode == 4) {
+			ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+			ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+			ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LS;
+			ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_RS;
+		} else if (channel_mode == 5) {
+			ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+			ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+			ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_FC;
+			ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_LS;
+			ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_RS;
+		} else if (channel_mode == 6) {
+			ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+			ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+			ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+			ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_FC;
+			ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_LS;
+			ep_payload->dev_channel_mapping[5] = PCM_CHANNEL_RS;
+		} else if (channel_mode == 7) {
+			ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+			ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+			ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_FC;
+			ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_LFE;
+			ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_LB;
+			ep_payload->dev_channel_mapping[5] = PCM_CHANNEL_RB;
+			ep_payload->dev_channel_mapping[6] = PCM_CHANNEL_CS;
+		} else if (channel_mode == 8) {
+			ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+			ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+			ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+			ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_FC;
+			ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_LS;
+			ep_payload->dev_channel_mapping[5] = PCM_CHANNEL_RS;
+			ep_payload->dev_channel_mapping[6] = PCM_CHANNEL_LB;
+			ep_payload->dev_channel_mapping[7] = PCM_CHANNEL_RB;
+		} else if (channel_mode == 10) {
+			ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+			ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+			ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+			ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_FC;
+			ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_LB;
+			ep_payload->dev_channel_mapping[5] = PCM_CHANNEL_RB;
+			ep_payload->dev_channel_mapping[6] = PCM_CHANNEL_LS;
+			ep_payload->dev_channel_mapping[7] = PCM_CHANNEL_RS;
+			ep_payload->dev_channel_mapping[8] = PCM_CHANNEL_TFL;
+			ep_payload->dev_channel_mapping[9] = PCM_CHANNEL_TFR;
+		} else if (channel_mode == 12) {
+			ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+			ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+			ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+			ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_FC;
+			ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_LB;
+			ep_payload->dev_channel_mapping[5] = PCM_CHANNEL_RB;
+			ep_payload->dev_channel_mapping[6] = PCM_CHANNEL_LS;
+			ep_payload->dev_channel_mapping[7] = PCM_CHANNEL_RS;
+			ep_payload->dev_channel_mapping[8] = PCM_CHANNEL_TFL;
+			ep_payload->dev_channel_mapping[9] = PCM_CHANNEL_TFR;
+			ep_payload->dev_channel_mapping[10] = PCM_CHANNEL_TSL;
+			ep_payload->dev_channel_mapping[11] = PCM_CHANNEL_TSR;
+		} else if (channel_mode == 16) {
+			ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+			ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+			ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+			ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_FC;
+			ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_LB;
+			ep_payload->dev_channel_mapping[5] = PCM_CHANNEL_RB;
+			ep_payload->dev_channel_mapping[6] = PCM_CHANNEL_LS;
+			ep_payload->dev_channel_mapping[7] = PCM_CHANNEL_RS;
+			ep_payload->dev_channel_mapping[8] = PCM_CHANNEL_TFL;
+			ep_payload->dev_channel_mapping[9] = PCM_CHANNEL_TFR;
+			ep_payload->dev_channel_mapping[10] = PCM_CHANNEL_TSL;
+			ep_payload->dev_channel_mapping[11] = PCM_CHANNEL_TSR;
+			ep_payload->dev_channel_mapping[12] = PCM_CHANNEL_FLC;
+			ep_payload->dev_channel_mapping[13] = PCM_CHANNEL_FRC;
+			ep_payload->dev_channel_mapping[14] = PCM_CHANNEL_RLC;
+			ep_payload->dev_channel_mapping[15] = PCM_CHANNEL_RRC;
+		} else {
+			pr_err("%s: invalid num_chan %d\n", __func__,
+				channel_mode);
+			rc = -EINVAL;
+			goto inval_ch_mod;
+		}
+	}
+
+non_mch_path:
+inval_ch_mod:
+	return rc;
+}
+
+static int adm_arrange_mch_ep2_map_v8(
+		struct adm_device_endpoint_payload *ep_payload,
+		int channel_mode)
+{
+	int rc = 0;
+
+	memset(ep_payload->dev_channel_mapping, 0,
+	       PCM_FORMAT_MAX_NUM_CHANNEL_V8);
+
+	if (channel_mode == 1) {
+		ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FC;
+	} else if (channel_mode == 2) {
+		ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+		ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+	} else if (channel_mode == 3) {
+		ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+		ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+		ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_FC;
+	} else if (channel_mode == 4) {
+		ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+		ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+		ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LS;
+		ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_RS;
+	} else if (channel_mode == 5) {
+		ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+		ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+		ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_FC;
+		ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_LS;
+		ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_RS;
+	} else if (channel_mode == 6) {
+		ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+		ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+		ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+		ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_FC;
+		ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_LS;
+		ep_payload->dev_channel_mapping[5] = PCM_CHANNEL_RS;
+	} else if (channel_mode == 8) {
+		ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+		ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+		ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+		ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_FC;
+		ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_LS;
+		ep_payload->dev_channel_mapping[5] = PCM_CHANNEL_RS;
+		ep_payload->dev_channel_mapping[6] = PCM_CHANNEL_LB;
+		ep_payload->dev_channel_mapping[7] = PCM_CHANNEL_RB;
+	}  else if (channel_mode == 10) {
+		ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+		ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+		ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+		ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_FC;
+		ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_LS;
+		ep_payload->dev_channel_mapping[5] = PCM_CHANNEL_RS;
+		ep_payload->dev_channel_mapping[6] = PCM_CHANNEL_LB;
+		ep_payload->dev_channel_mapping[7] = PCM_CHANNEL_RB;
+		ep_payload->dev_channel_mapping[8] = PCM_CHANNEL_CS;
+		ep_payload->dev_channel_mapping[9] = PCM_CHANNELS;
+	} else if (channel_mode == 12) {
+		ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+		ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+		ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+		ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_FC;
+		ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_LS;
+		ep_payload->dev_channel_mapping[5] = PCM_CHANNEL_RS;
+		ep_payload->dev_channel_mapping[6] = PCM_CHANNEL_LB;
+		ep_payload->dev_channel_mapping[7] = PCM_CHANNEL_RB;
+		ep_payload->dev_channel_mapping[8] = PCM_CHANNEL_TFL;
+		ep_payload->dev_channel_mapping[9] = PCM_CHANNEL_TFR;
+		ep_payload->dev_channel_mapping[10] = PCM_CHANNEL_TSL;
+		ep_payload->dev_channel_mapping[11] = PCM_CHANNEL_TSR;
+	} else if (channel_mode == 16) {
+		ep_payload->dev_channel_mapping[0] = PCM_CHANNEL_FL;
+		ep_payload->dev_channel_mapping[1] = PCM_CHANNEL_FR;
+		ep_payload->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+		ep_payload->dev_channel_mapping[3] = PCM_CHANNEL_FC;
+		ep_payload->dev_channel_mapping[4] = PCM_CHANNEL_LS;
+		ep_payload->dev_channel_mapping[5] = PCM_CHANNEL_RS;
+		ep_payload->dev_channel_mapping[6] = PCM_CHANNEL_LB;
+		ep_payload->dev_channel_mapping[7] = PCM_CHANNEL_RB;
+		ep_payload->dev_channel_mapping[8] = PCM_CHANNEL_CS;
+		ep_payload->dev_channel_mapping[9] = PCM_CHANNELS;
+		ep_payload->dev_channel_mapping[10] = PCM_CHANNEL_CVH;
+		ep_payload->dev_channel_mapping[11] = PCM_CHANNEL_MS;
+		ep_payload->dev_channel_mapping[12] = PCM_CHANNEL_FLC;
+		ep_payload->dev_channel_mapping[13] = PCM_CHANNEL_FRC;
+		ep_payload->dev_channel_mapping[14] = PCM_CHANNEL_RLC;
+		ep_payload->dev_channel_mapping[15] = PCM_CHANNEL_RRC;
+	} else {
+		pr_err("%s: invalid num_chan %d\n", __func__,
+			channel_mode);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
 /**
  * adm_open -
  *        command to send ADM open
@@ -2665,10 +2896,17 @@
 {
 	struct adm_cmd_device_open_v5	open;
 	struct adm_cmd_device_open_v6	open_v6;
+	struct adm_cmd_device_open_v8	open_v8;
+	struct adm_device_endpoint_payload ep1_payload;
+	struct adm_device_endpoint_payload ep2_payload;
+	int ep1_payload_size = 0;
+	int ep2_payload_size = 0;
 	int ret = 0;
 	int port_idx, flags;
 	int copp_idx = -1;
 	int tmp_port = q6audio_get_port_id(port_id);
+	void *adm_params = NULL;
+	int param_size;
 
 	pr_debug("%s:port %#x path:%d rate:%d mode:%d perf_mode:%d,topo_id %d\n",
 		 __func__, port_id, path, rate, channel_mode, perf_mode,
@@ -2680,6 +2918,11 @@
 		pr_err("%s: Invalid port_id 0x%x\n", __func__, port_id);
 		return -EINVAL;
 	}
+	if (channel_mode <= 0 || channel_mode > 32) {
+		pr_err("%s: Invalid channel number 0x%x\n",
+				__func__, channel_mode);
+		return -EINVAL;
+	}
 
 	if (this_adm.apr == NULL) {
 		this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
@@ -2776,111 +3019,241 @@
 	if (atomic_read(&this_adm.copp.cnt[port_idx][copp_idx]) == 0) {
 		pr_debug("%s: open ADM: port_idx: %d, copp_idx: %d\n", __func__,
 			 port_idx, copp_idx);
-	if ((topology == SRS_TRUMEDIA_TOPOLOGY_ID) &&
-	     perf_mode == LEGACY_PCM_MODE) {
-		int res;
+		if ((topology == SRS_TRUMEDIA_TOPOLOGY_ID) &&
+		      perf_mode == LEGACY_PCM_MODE) {
+			int res;
 
-		atomic_set(&this_adm.mem_map_index, ADM_SRS_TRUMEDIA);
-		msm_dts_srs_tm_ion_memmap(&this_adm.outband_memmap);
-		res = adm_memory_map_regions(&this_adm.outband_memmap.paddr, 0,
-		(uint32_t *)&this_adm.outband_memmap.size, 1);
-		if (res < 0) {
-			pr_err("%s: SRS adm_memory_map_regions failed ! addr = 0x%pK, size = %d\n",
-			 __func__, (void *)this_adm.outband_memmap.paddr,
-		(uint32_t)this_adm.outband_memmap.size);
-		}
-	}
-		open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
-						   APR_HDR_LEN(APR_HDR_SIZE),
-						   APR_PKT_VER);
-		open.hdr.pkt_size = sizeof(open);
-		open.hdr.src_svc = APR_SVC_ADM;
-		open.hdr.src_domain = APR_DOMAIN_APPS;
-		open.hdr.src_port = tmp_port;
-		open.hdr.dest_svc = APR_SVC_ADM;
-		open.hdr.dest_domain = APR_DOMAIN_ADSP;
-		open.hdr.dest_port = tmp_port;
-		open.hdr.token = port_idx << 16 | copp_idx;
-		open.hdr.opcode = ADM_CMD_DEVICE_OPEN_V5;
-		open.flags = flags;
-		open.mode_of_operation = path;
-		open.endpoint_id_1 = tmp_port;
-		open.endpoint_id_2 = 0xFFFF;
-
-		if (this_adm.ec_ref_rx && (path != 1) &&
-		    (afe_get_port_type(tmp_port) == MSM_AFE_PORT_TYPE_TX)) {
-			open.endpoint_id_2 = this_adm.ec_ref_rx;
-			this_adm.ec_ref_rx = -1;
+			atomic_set(&this_adm.mem_map_index, ADM_SRS_TRUMEDIA);
+			msm_dts_srs_tm_ion_memmap(&this_adm.outband_memmap);
+			res = adm_memory_map_regions(
+					&this_adm.outband_memmap.paddr, 0,
+			(uint32_t *)&this_adm.outband_memmap.size, 1);
+			if (res < 0) {
+				pr_err("%s: SRS adm_memory_map_regions failed! addr = 0x%pK, size = %d\n",
+					__func__,
+					(void *)this_adm.outband_memmap.paddr,
+					(uint32_t)this_adm.outband_memmap.size);
+			}
 		}
 
-		open.topology_id = topology;
 
-		open.dev_num_channel = channel_mode & 0x00FF;
-		open.bit_width = bit_width;
-		WARN_ON((perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) &&
-			(rate != ULL_SUPPORTED_SAMPLE_RATE));
-		open.sample_rate  = rate;
+		if (q6core_get_avcs_api_version_per_service(
+				APRV2_IDS_SERVICE_ID_ADSP_ADM_V) >=
+					ADSP_ADM_API_VERSION_V3) {
+			memset(&open_v8, 0, sizeof(open_v8));
+			memset(&ep1_payload, 0, sizeof(ep1_payload));
+			memset(&ep2_payload, 0, sizeof(ep2_payload));
 
-		ret = adm_arrange_mch_map(&open, path, channel_mode,
-					  port_idx);
+			open_v8.hdr.hdr_field = APR_HDR_FIELD(
+					APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE),
+					APR_PKT_VER);
+			open_v8.hdr.src_svc = APR_SVC_ADM;
+			open_v8.hdr.src_domain = APR_DOMAIN_APPS;
+			open_v8.hdr.src_port = tmp_port;
+			open_v8.hdr.dest_svc = APR_SVC_ADM;
+			open_v8.hdr.dest_domain = APR_DOMAIN_ADSP;
+			open_v8.hdr.dest_port = tmp_port;
+			open_v8.hdr.token = port_idx << 16 | copp_idx;
+			open_v8.hdr.opcode = ADM_CMD_DEVICE_OPEN_V8;
 
-		if (ret)
-			return ret;
-
-		pr_debug("%s: port_id=0x%x rate=%d topology_id=0x%X\n",
-			__func__, open.endpoint_id_1, open.sample_rate,
-			open.topology_id);
-
-		atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
-
-		if ((this_adm.num_ec_ref_rx_chans != 0) && (path != 1) &&
-			(open.endpoint_id_2 != 0xFFFF)) {
-			memset(&open_v6, 0,
-				sizeof(struct adm_cmd_device_open_v6));
-			memcpy(&open_v6, &open,
-				sizeof(struct adm_cmd_device_open_v5));
-			open_v6.hdr.opcode = ADM_CMD_DEVICE_OPEN_V6;
-			open_v6.hdr.pkt_size = sizeof(open_v6);
-			open_v6.dev_num_channel_eid2 =
-				this_adm.num_ec_ref_rx_chans;
-			this_adm.num_ec_ref_rx_chans = 0;
-
-			if (this_adm.ec_ref_rx_bit_width != 0) {
-				open_v6.bit_width_eid2 =
-					this_adm.ec_ref_rx_bit_width;
-				this_adm.ec_ref_rx_bit_width = 0;
+			if (this_adm.native_mode != 0) {
+				open_v8.flags = flags |
+					(this_adm.native_mode << 11);
+				this_adm.native_mode = 0;
 			} else {
-				open_v6.bit_width_eid2 = bit_width;
+				open_v8.flags = flags;
+			}
+			open_v8.mode_of_operation = path;
+			open_v8.endpoint_id_1 = tmp_port;
+			open_v8.endpoint_id_2 = 0xFFFF;
+			open_v8.endpoint_id_3 = 0xFFFF;
+
+			if (this_adm.ec_ref_rx && (path != 1)) {
+				open_v8.endpoint_id_2 = this_adm.ec_ref_rx;
+				this_adm.ec_ref_rx = -1;
 			}
 
-			if (this_adm.ec_ref_rx_sampling_rate != 0) {
-				open_v6.sample_rate_eid2 =
-					this_adm.ec_ref_rx_sampling_rate;
-				this_adm.ec_ref_rx_sampling_rate = 0;
-			} else {
-				open_v6.sample_rate_eid2 = rate;
-			}
+			open_v8.topology_id = topology;
+			open_v8.reserved = 0;
 
-			pr_debug("%s: eid2_channels=%d eid2_bit_width=%d eid2_rate=%d\n",
-				__func__, open_v6.dev_num_channel_eid2,
-				open_v6.bit_width_eid2,
-				open_v6.sample_rate_eid2);
-
-			ret = adm_arrange_mch_ep2_map(&open_v6,
-				open_v6.dev_num_channel_eid2);
-
+			/* variable endpoint payload */
+			ep1_payload.dev_num_channel = channel_mode & 0x00FF;
+			ep1_payload.bit_width = bit_width;
+			ep1_payload.sample_rate  = rate;
+			ret = adm_arrange_mch_map_v8(&ep1_payload, path,
+					channel_mode);
 			if (ret)
 				return ret;
 
-			ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open_v6);
+			pr_debug("%s: port_id=0x%x %x %x topology_id=0x%X flags %x ref_ch %x\n",
+				__func__, open_v8.endpoint_id_1,
+				open_v8.endpoint_id_2,
+				open_v8.endpoint_id_3,
+				open_v8.topology_id,
+				open_v8.flags,
+				this_adm.num_ec_ref_rx_chans);
+
+			ep1_payload_size = 8 +
+				roundup(ep1_payload.dev_num_channel, 4);
+			param_size = sizeof(struct adm_cmd_device_open_v8)
+				+ ep1_payload_size;
+			atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+
+			if ((this_adm.num_ec_ref_rx_chans != 0) && (path != 1)
+				&& (open_v8.endpoint_id_2 != 0xFFFF)) {
+				ep2_payload.dev_num_channel =
+					this_adm.num_ec_ref_rx_chans;
+				this_adm.num_ec_ref_rx_chans = 0;
+
+				if (this_adm.ec_ref_rx_bit_width != 0) {
+					ep2_payload.bit_width =
+						this_adm.ec_ref_rx_bit_width;
+					this_adm.ec_ref_rx_bit_width = 0;
+				} else {
+					ep2_payload.bit_width = bit_width;
+				}
+
+				if (this_adm.ec_ref_rx_sampling_rate != 0) {
+					ep2_payload.sample_rate =
+					this_adm.ec_ref_rx_sampling_rate;
+					this_adm.ec_ref_rx_sampling_rate = 0;
+				} else {
+					ep2_payload.sample_rate = rate;
+				}
+
+				pr_debug("%s: adm open_v8 eid2_channels=%d eid2_bit_width=%d eid2_rate=%d\n",
+					__func__,
+					ep2_payload.dev_num_channel,
+					ep2_payload.bit_width,
+					ep2_payload.sample_rate);
+
+				ret = adm_arrange_mch_ep2_map_v8(&ep2_payload,
+					ep2_payload.dev_num_channel);
+
+				if (ret)
+					return ret;
+				ep2_payload_size = 8 +
+					roundup(ep2_payload.dev_num_channel, 4);
+				param_size += ep2_payload_size;
+			}
+
+			adm_params = kzalloc(param_size, GFP_KERNEL);
+			if (!adm_params)
+				return -ENOMEM;
+			open_v8.hdr.pkt_size = param_size;
+			memcpy(adm_params, &open_v8, sizeof(open_v8));
+			memcpy(adm_params + sizeof(open_v8),
+					(void *)&ep1_payload,
+					ep1_payload_size);
+			memcpy(adm_params + sizeof(open_v8)
+					+ ep1_payload_size,
+					(void *)&ep2_payload,
+					ep2_payload_size);
+
+			ret = apr_send_pkt(this_adm.apr,
+					(uint32_t *)adm_params);
+			if (ret < 0) {
+				pr_err("%s: port_id: 0x%x for[0x%x] failed %d for open_v8\n",
+					__func__, tmp_port, port_id, ret);
+				return -EINVAL;
+			}
+			kfree(adm_params);
 		} else {
-			ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
+
+			open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE),
+				APR_PKT_VER);
+			open.hdr.pkt_size = sizeof(open);
+			open.hdr.src_svc = APR_SVC_ADM;
+			open.hdr.src_domain = APR_DOMAIN_APPS;
+			open.hdr.src_port = tmp_port;
+			open.hdr.dest_svc = APR_SVC_ADM;
+			open.hdr.dest_domain = APR_DOMAIN_ADSP;
+			open.hdr.dest_port = tmp_port;
+			open.hdr.token = port_idx << 16 | copp_idx;
+			open.hdr.opcode = ADM_CMD_DEVICE_OPEN_V5;
+			open.flags = flags;
+			open.mode_of_operation = path;
+			open.endpoint_id_1 = tmp_port;
+			open.endpoint_id_2 = 0xFFFF;
+
+			if (this_adm.ec_ref_rx && (path != 1)) {
+				open.endpoint_id_2 = this_adm.ec_ref_rx;
+				this_adm.ec_ref_rx = -1;
+			}
+
+			open.topology_id = topology;
+
+			open.dev_num_channel = channel_mode & 0x00FF;
+			open.bit_width = bit_width;
+			WARN_ON((perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) &&
+				(rate != ULL_SUPPORTED_SAMPLE_RATE));
+			open.sample_rate  = rate;
+
+			ret = adm_arrange_mch_map(&open, path, channel_mode,
+						  port_idx);
+			if (ret)
+				return ret;
+
+			pr_debug("%s: port_id=0x%x rate=%d topology_id=0x%X\n",
+				__func__, open.endpoint_id_1, open.sample_rate,
+				open.topology_id);
+
+			atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1);
+
+			if ((this_adm.num_ec_ref_rx_chans != 0) &&
+				(path != 1) && (open.endpoint_id_2 != 0xFFFF)) {
+				memset(&open_v6, 0,
+					sizeof(struct adm_cmd_device_open_v6));
+				memcpy(&open_v6, &open,
+					sizeof(struct adm_cmd_device_open_v5));
+				open_v6.hdr.opcode = ADM_CMD_DEVICE_OPEN_V6;
+				open_v6.hdr.pkt_size = sizeof(open_v6);
+				open_v6.dev_num_channel_eid2 =
+					this_adm.num_ec_ref_rx_chans;
+				this_adm.num_ec_ref_rx_chans = 0;
+
+				if (this_adm.ec_ref_rx_bit_width != 0) {
+					open_v6.bit_width_eid2 =
+						this_adm.ec_ref_rx_bit_width;
+					this_adm.ec_ref_rx_bit_width = 0;
+				} else {
+					open_v6.bit_width_eid2 = bit_width;
+				}
+
+				if (this_adm.ec_ref_rx_sampling_rate != 0) {
+					open_v6.sample_rate_eid2 =
+					       this_adm.ec_ref_rx_sampling_rate;
+					this_adm.ec_ref_rx_sampling_rate = 0;
+				} else {
+					open_v6.sample_rate_eid2 = rate;
+				}
+
+				pr_debug("%s: eid2_channels=%d eid2_bit_width=%d eid2_rate=%d\n",
+					__func__, open_v6.dev_num_channel_eid2,
+					open_v6.bit_width_eid2,
+					open_v6.sample_rate_eid2);
+
+				ret = adm_arrange_mch_ep2_map(&open_v6,
+					open_v6.dev_num_channel_eid2);
+
+				if (ret)
+					return ret;
+
+				ret = apr_send_pkt(this_adm.apr,
+					(uint32_t *)&open_v6);
+			} else {
+				ret = apr_send_pkt(this_adm.apr,
+					(uint32_t *)&open);
+			}
+			if (ret < 0) {
+				pr_err("%s: port_id: 0x%x for[0x%x] failed %d\n",
+					__func__, tmp_port, port_id, ret);
+				return -EINVAL;
+			}
 		}
-		if (ret < 0) {
-			pr_err("%s: port_id: 0x%x for[0x%x] failed %d\n",
-			__func__, tmp_port, port_id, ret);
-			return -EINVAL;
-		}
+
 		/* Wait for the callback with copp id */
 		ret = wait_event_timeout(this_adm.copp.wait[port_idx][copp_idx],
 			atomic_read(&this_adm.copp.stat
@@ -3252,6 +3625,22 @@
 EXPORT_SYMBOL(adm_ec_ref_rx_sampling_rate);
 
 /**
+ * adm_set_native_mode -
+ *      Set adm channel native mode.
+ *      If enabled matrix mixer will be
+ *      running in native mode for channel
+ *      configuration for this device session.
+ *
+ */
+void adm_set_native_mode(int mode)
+{
+	this_adm.native_mode = mode;
+	pr_debug("%s: enable native_mode :%d\n",
+		__func__, this_adm.native_mode);
+}
+EXPORT_SYMBOL(adm_set_native_mode);
+
+/**
  * adm_close -
  *        command to close ADM copp
  *