Browse Source

lsm: add support for ADSP multi stage VA

Enhance APIs to get instance id and stage info from userspace,
required for multi-stage Voice Activation in ADSP.

Change-Id: Ie39a3d002a56fb8df0c241089a50d55ef700a538
Signed-off-by: Dhananjay Kumar <[email protected]>
Dhananjay Kumar 6 years ago
parent
commit
ce6ec5fcf2
4 changed files with 757 additions and 364 deletions
  1. 367 198
      asoc/msm-lsm-client.c
  2. 346 157
      dsp/q6lsm.c
  3. 1 0
      include/dsp/apr_audio-v2.h
  4. 43 9
      include/dsp/q6lsm.h

+ 367 - 198
asoc/msm-lsm-client.c

@@ -42,6 +42,9 @@
 #define LAB_BUFFER_ALLOC 1
 #define LAB_BUFFER_DEALLOC 0
 
+#define LSM_IS_LAST_STAGE(client, stage_idx) \
+	(client->num_stages == (stage_idx + 1))
+
 static struct snd_pcm_hardware msm_pcm_hardware_capture = {
 	.info =                 (SNDRV_PCM_INFO_MMAP |
 				SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -463,7 +466,7 @@ done:
 }
 
 static int msm_lsm_set_epd(struct snd_pcm_substream *substream,
-		struct lsm_params_info *p_info)
+		struct lsm_params_info_v2 *p_info)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct lsm_priv *prtd = runtime->private_data;
@@ -499,7 +502,7 @@ done:
 }
 
 static int msm_lsm_set_mode(struct snd_pcm_substream *substream,
-		struct lsm_params_info *p_info)
+		struct lsm_params_info_v2 *p_info)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct lsm_priv *prtd = runtime->private_data;
@@ -535,7 +538,7 @@ done:
 }
 
 static int msm_lsm_set_gain(struct snd_pcm_substream *substream,
-		struct lsm_params_info *p_info)
+		struct lsm_params_info_v2 *p_info)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct lsm_priv *prtd = runtime->private_data;
@@ -571,7 +574,7 @@ done:
 }
 
 static int msm_lsm_set_conf(struct snd_pcm_substream *substream,
-		struct lsm_params_info *p_info)
+		struct lsm_params_info_v2 *p_info)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct lsm_priv *prtd = runtime->private_data;
@@ -608,18 +611,17 @@ static int msm_lsm_set_conf(struct snd_pcm_substream *substream,
 }
 
 static int msm_lsm_reg_model(struct snd_pcm_substream *substream,
-		struct lsm_params_info *p_info)
+		struct lsm_params_info_v2 *p_info)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct lsm_priv *prtd = runtime->private_data;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	int rc = 0;
-	u8 *snd_model_ptr;
-	size_t offset;
+	struct lsm_sound_model *sm = NULL;
+	size_t offset = sizeof(union param_hdrs);
 
 	rc = q6lsm_snd_model_buf_alloc(prtd->lsm_client,
-				       p_info->param_size,
-				       true);
+				       p_info->param_size, p_info);
 	if (rc) {
 		dev_err(rtd->dev,
 			"%s: snd_model buf alloc failed, size = %d\n",
@@ -633,9 +635,9 @@ static int msm_lsm_reg_model(struct snd_pcm_substream *substream,
 	 * For set_param, advance the sound model data with the
 	 * number of bytes required by param_data.
 	 */
-	snd_model_ptr = ((u8 *) prtd->lsm_client->sound_model.data) + offset;
 
-	if (copy_from_user(snd_model_ptr,
+	sm = &prtd->lsm_client->stage_cfg[p_info->stage_idx].sound_model;
+	if (copy_from_user((u8 *)sm->data + offset,
 			   p_info->param_data, p_info->param_size)) {
 		dev_err(rtd->dev,
 			"%s: copy_from_user for snd_model failed, size = %d\n",
@@ -654,12 +656,12 @@ static int msm_lsm_reg_model(struct snd_pcm_substream *substream,
 	return rc;
 
 err_copy:
-	q6lsm_snd_model_buf_free(prtd->lsm_client);
+	q6lsm_snd_model_buf_free(prtd->lsm_client, p_info);
 	return rc;
 }
 
 static int msm_lsm_dereg_model(struct snd_pcm_substream *substream,
-		struct lsm_params_info *p_info)
+		struct lsm_params_info_v2 *p_info)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct lsm_priv *prtd = runtime->private_data;
@@ -673,13 +675,13 @@ static int msm_lsm_dereg_model(struct snd_pcm_substream *substream,
 			"%s: Failed to set det_mode param, err = %d\n",
 			__func__, rc);
 
-	q6lsm_snd_model_buf_free(prtd->lsm_client);
+	q6lsm_snd_model_buf_free(prtd->lsm_client, p_info);
 
 	return rc;
 }
 
 static int msm_lsm_set_custom(struct snd_pcm_substream *substream,
-		struct lsm_params_info *p_info)
+		struct lsm_params_info_v2 *p_info)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct lsm_priv *prtd = runtime->private_data;
@@ -712,8 +714,96 @@ err_ret:
 	return rc;
 }
 
+static int msm_lsm_check_and_set_lab_controls(struct snd_pcm_substream *substream,
+			u32 enable, struct lsm_params_info_v2 *p_info)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct lsm_priv *prtd = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct lsm_hw_params *out_hw_params = &prtd->lsm_client->out_hw_params;
+	u8 chmap[out_hw_params->num_chs];
+	u32 ch_idx;
+	int rc = 0, stage_idx = p_info->stage_idx;
+
+	if (prtd->lsm_client->stage_cfg[stage_idx].lab_enable == enable) {
+		dev_dbg(rtd->dev, "%s: Lab for session %d, stage %d already %s\n",
+				__func__, prtd->lsm_client->session,
+				stage_idx, enable ? "enabled" : "disabled");
+		return rc;
+	}
+
+	rc = q6lsm_lab_control(prtd->lsm_client, enable, p_info);
+	if (rc) {
+		dev_err(rtd->dev, "%s: Failed to set lab_control param, err = %d\n",
+			__func__, rc);
+		return rc;
+	} else {
+		if (LSM_IS_LAST_STAGE(prtd->lsm_client, stage_idx)) {
+			rc = msm_lsm_lab_buffer_alloc(prtd,
+					enable ? LAB_BUFFER_ALLOC : LAB_BUFFER_DEALLOC);
+			if (rc) {
+				dev_err(rtd->dev,
+					"%s: msm_lsm_lab_buffer_alloc failed rc %d for %s\n",
+					__func__, rc, enable ? "ALLOC" : "DEALLOC");
+				return rc;
+			} else {
+				/* set client level flag based on last stage control */
+				prtd->lsm_client->lab_enable = enable;
+			}
+		}
+		if (!rc)
+			prtd->lsm_client->stage_cfg[stage_idx].lab_enable = enable;
+	}
+
+	memset(chmap, 0, out_hw_params->num_chs);
+	/*
+	 * First channel to be read from lab is always the
+	 * best channel (0xff). For second channel onwards,
+	 * the channel indices are 0, 1, .. etc
+	 */
+	chmap[0] = 0xFF;
+	for (ch_idx = 1; ch_idx < out_hw_params->num_chs; ch_idx++)
+		chmap[ch_idx] = ch_idx - 1;
+
+	rc = q6lsm_lab_out_ch_cfg(prtd->lsm_client, chmap, p_info);
+	if (rc)
+		dev_err(rtd->dev, "%s: Failed to set lab out ch cfg %d\n",
+			__func__, rc);
+
+	return rc;
+}
+
+static int msm_lsm_set_lab_control(struct snd_pcm_substream *substream,
+		struct lsm_params_info_v2 *p_info)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct lsm_priv *prtd = runtime->private_data;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_lsm_lab_control lab_ctrl;
+	int rc = 0;
+
+	if (p_info->param_size != sizeof(lab_ctrl))
+		return -EINVAL;
+
+	if (prtd->lsm_client->started) {
+		dev_err(rtd->dev, "%s: lab control sent after start\n", __func__);
+		return -EAGAIN;
+	}
+
+	if (copy_from_user(&lab_ctrl, p_info->param_data,
+			   p_info->param_size)) {
+		dev_err(rtd->dev,
+			"%s: copy_from_user failed for lab_control params, size = %d\n",
+			__func__, p_info->param_size);
+		return  -EFAULT;
+	}
+
+	rc = msm_lsm_check_and_set_lab_controls(substream, lab_ctrl.enable, p_info);
+	return rc;
+}
+
 static int msm_lsm_set_poll_enable(struct snd_pcm_substream *substream,
-		struct lsm_params_info *p_info)
+		struct lsm_params_info_v2 *p_info)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct lsm_priv *prtd = runtime->private_data;
@@ -761,7 +851,7 @@ done:
 }
 
 static int msm_lsm_set_det_event_type(struct snd_pcm_substream *substream,
-				      struct lsm_params_info *p_info)
+				      struct lsm_params_info_v2 *p_info)
 {
 	struct snd_lsm_det_event_type det_event_type;
 	struct snd_pcm_runtime *runtime = substream->runtime;
@@ -801,65 +891,68 @@ done:
 }
 
 static int msm_lsm_process_params(struct snd_pcm_substream *substream,
-		struct snd_lsm_module_params *p_data,
-		void *params)
+		struct lsm_params_info_v2 *p_info)
 {
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct lsm_priv *prtd = runtime->private_data;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct lsm_params_info *p_info;
-	int i;
 	int rc = 0;
 
-	p_info = (struct lsm_params_info *) params;
+	dev_dbg(rtd->dev,
+		"%s: mid=0x%x, pid=0x%x, iid=0x%x, stage_idx=%d, size=0x%x, type=%d\n",
+		__func__, p_info->module_id, p_info->param_id, p_info->instance_id,
+		p_info->stage_idx, p_info->param_size, p_info->param_type);
 
-	for (i = 0; i < p_data->num_params; i++) {
-		dev_dbg(rtd->dev,
-			"%s: param (%d), module_id = 0x%x, param_id = 0x%x, param_size = 0x%x, param_type = 0x%x\n",
-			__func__, i, p_info->module_id,
-			p_info->param_id, p_info->param_size,
-			p_info->param_type);
-
-		switch (p_info->param_type) {
-		case LSM_ENDPOINT_DETECT_THRESHOLD:
-			rc = msm_lsm_set_epd(substream, p_info);
-			break;
-		case LSM_OPERATION_MODE:
-			rc = msm_lsm_set_mode(substream, p_info);
-			break;
-		case LSM_GAIN:
-			rc = msm_lsm_set_gain(substream, p_info);
-			break;
-		case LSM_MIN_CONFIDENCE_LEVELS:
-			rc = msm_lsm_set_conf(substream, p_info);
-			break;
-		case LSM_REG_SND_MODEL:
-			rc = msm_lsm_reg_model(substream, p_info);
-			break;
-		case LSM_DEREG_SND_MODEL:
-			rc = msm_lsm_dereg_model(substream, p_info);
-			break;
-		case LSM_CUSTOM_PARAMS:
-			rc = msm_lsm_set_custom(substream, p_info);
-			break;
-		case LSM_POLLING_ENABLE:
-			rc = msm_lsm_set_poll_enable(substream, p_info);
-			break;
-		case LSM_DET_EVENT_TYPE:
-			rc = msm_lsm_set_det_event_type(substream, p_info);
-			break;
-		default:
-			dev_err(rtd->dev,
-				"%s: Invalid param_type %d\n",
-				__func__, p_info->param_type);
-			rc = -EINVAL;
-			break;
-		}
-		if (rc) {
-			pr_err("%s: set_param fail for param_type %d\n",
-				__func__, p_info->param_type);
-			return rc;
-		}
+	if (!prtd->lsm_client ||
+		prtd->lsm_client->num_stages <= p_info->stage_idx) {
+		dev_err(rtd->dev,
+			"%s: invalid stage_idx(%d) for client(%p) having num_stages(%d)\n",
+			__func__, p_info->stage_idx, prtd->lsm_client,
+			prtd->lsm_client ? prtd->lsm_client->num_stages : 0);
+		return -EINVAL;
+	}
 
-		p_info++;
+	switch (p_info->param_type) {
+	case LSM_ENDPOINT_DETECT_THRESHOLD:
+		rc = msm_lsm_set_epd(substream, p_info);
+		break;
+	case LSM_OPERATION_MODE:
+		rc = msm_lsm_set_mode(substream, p_info);
+		break;
+	case LSM_GAIN:
+		rc = msm_lsm_set_gain(substream, p_info);
+		break;
+	case LSM_MIN_CONFIDENCE_LEVELS:
+		rc = msm_lsm_set_conf(substream, p_info);
+		break;
+	case LSM_REG_SND_MODEL:
+		rc = msm_lsm_reg_model(substream, p_info);
+		break;
+	case LSM_DEREG_SND_MODEL:
+		rc = msm_lsm_dereg_model(substream, p_info);
+		break;
+	case LSM_CUSTOM_PARAMS:
+		rc = msm_lsm_set_custom(substream, p_info);
+		break;
+	case LSM_POLLING_ENABLE:
+		rc = msm_lsm_set_poll_enable(substream, p_info);
+		break;
+	case LSM_DET_EVENT_TYPE:
+		rc = msm_lsm_set_det_event_type(substream, p_info);
+		break;
+	case LSM_LAB_CONTROL:
+		rc = msm_lsm_set_lab_control(substream, p_info);
+		break;
+	default:
+		dev_err(rtd->dev,
+			"%s: Invalid param_type %d\n",
+			__func__, p_info->param_type);
+		rc = -EINVAL;
+		break;
+	}
+	if (rc) {
+		pr_err("%s: set_param fail for param_type %d\n",
+			__func__, p_info->param_type);
 	}
 
 	return rc;
@@ -897,12 +990,14 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
 	int ret;
 	struct snd_lsm_sound_model_v2 snd_model_v2;
 	struct snd_lsm_session_data session_data;
-	int rc = 0;
+	struct snd_lsm_session_data_v2 ses_data_v2 = {0};
+	int rc = 0, stage_idx;
 	int xchg = 0;
 	struct snd_pcm_runtime *runtime;
 	struct lsm_priv *prtd;
 	struct snd_lsm_detection_params det_params;
 	uint8_t *confidence_level = NULL;
+	uint32_t max_detection_stages_supported = LSM_MAX_STAGES_PER_SESSION;
 
 	if (!substream || !substream->private_data) {
 		pr_err("%s: Invalid %s\n", __func__,
@@ -916,15 +1011,26 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
 
 	switch (cmd) {
 	case SNDRV_LSM_SET_SESSION_DATA:
-		dev_dbg(rtd->dev, "%s: set session data\n", __func__);
-		if (copy_from_user(&session_data, arg,
-				   sizeof(session_data))) {
+	case SNDRV_LSM_SET_SESSION_DATA_V2:
+
+		if (cmd == SNDRV_LSM_SET_SESSION_DATA) {
+			dev_dbg(rtd->dev, "%s: set session data\n", __func__);
+			rc = copy_from_user(&session_data, arg, sizeof(session_data));
+			if (!rc) {
+				ses_data_v2.app_id = session_data.app_id;
+				ses_data_v2.num_stages = 1;
+			}
+		} else {
+			dev_dbg(rtd->dev, "%s: set session data_v2\n", __func__);
+			rc = copy_from_user(&ses_data_v2, arg, sizeof(ses_data_v2));
+		}
+		if (rc) {
 			dev_err(rtd->dev, "%s: %s: copy_from_user failed\n",
-				__func__, "LSM_SET_SESSION_DATA");
+				__func__, "LSM_SET_SESSION_DATA(_V2)");
 			return -EFAULT;
 		}
 
-		if (session_data.app_id != LSM_VOICE_WAKEUP_APP_ID_V2) {
+		if (ses_data_v2.app_id != LSM_VOICE_WAKEUP_APP_ID_V2) {
 			dev_err(rtd->dev,
 				"%s:Invalid App id %d for Listen client\n",
 			       __func__, session_data.app_id);
@@ -932,9 +1038,38 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
 			break;
 		}
 
-		prtd->lsm_client->app_id = session_data.app_id;
-		ret = q6lsm_open(prtd->lsm_client,
-				 prtd->lsm_client->app_id);
+		/*
+		 * Before validating num_stages from user argument.
+		 * Check ADSP support for multi-stage session,
+		 * and reset max_detection_stages_supported to "1" if required.
+		 */
+		if (!q6lsm_adsp_supports_multi_stage_detection()) {
+			dev_dbg(rtd->dev,
+				"%s: multi-stage session not supported by adsp\n", __func__);
+			max_detection_stages_supported = 1;
+		}
+
+		if (ses_data_v2.num_stages <= 0 ||
+			ses_data_v2.num_stages > max_detection_stages_supported) {
+			dev_err(rtd->dev,
+				"%s: Unsupported number of stages req(%d)/max(%d)\n",
+				 __func__, ses_data_v2.num_stages,
+				max_detection_stages_supported);
+			rc = -EINVAL;
+			break;
+		}
+
+		prtd->lsm_client->app_id = ses_data_v2.app_id;
+		prtd->lsm_client->num_stages = ses_data_v2.num_stages;
+		for (stage_idx = LSM_STAGE_INDEX_FIRST;
+			stage_idx < ses_data_v2.num_stages; stage_idx++) {
+			prtd->lsm_client->stage_cfg[stage_idx].app_type =
+				ses_data_v2.stage_info[stage_idx].app_type;
+			prtd->lsm_client->stage_cfg[stage_idx].lpi_enable =
+				ses_data_v2.stage_info[stage_idx].lpi_enable;
+		}
+
+		ret = q6lsm_open(prtd->lsm_client, ses_data_v2.app_id);
 		if (ret < 0) {
 			dev_err(rtd->dev,
 				"%s: lsm open failed, %d\n",
@@ -942,12 +1077,24 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
 			return ret;
 		}
 		prtd->lsm_client->opened = true;
-		dev_dbg(rtd->dev, "%s: Session_ID = %d, APP ID = %d\n",
+		dev_dbg(rtd->dev, "%s: Session_ID = %d, APP ID = %d, Num stages %d\n",
 			__func__,
 			prtd->lsm_client->session,
-			prtd->lsm_client->app_id);
+			prtd->lsm_client->app_id,
+			prtd->lsm_client->num_stages);
 		break;
-	case SNDRV_LSM_REG_SND_MODEL_V2:
+	case SNDRV_LSM_REG_SND_MODEL_V2: {
+		/*
+		 * With multi-stage support sm buff allocation/free usage param info
+		 * to check stage index for which this sound model is being set, and
+		 * to check whether sm data is sent using set param command or not.
+		 * Hence, set param ids to '0' to indicate allocation is for legacy
+		 * reg_sm cmd, where buffer for param header need not be allocated,
+		 * also set stage index to LSM_STAGE_INDEX_FIRST.
+		 */
+		struct lsm_params_info_v2 p_info = {0};
+		p_info.stage_idx = LSM_STAGE_INDEX_FIRST;
+
 		dev_dbg(rtd->dev, "%s: Registering sound model V2\n",
 			__func__);
 		memcpy(&snd_model_v2, arg,
@@ -962,20 +1109,21 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
 			break;
 		}
 		rc = q6lsm_snd_model_buf_alloc(prtd->lsm_client,
-					       snd_model_v2.data_size, false);
+					snd_model_v2.data_size, &p_info);
 		if (rc) {
 			dev_err(rtd->dev,
 				"%s: q6lsm buffer alloc failed V2, size %d\n",
 			       __func__, snd_model_v2.data_size);
 			break;
 		}
-		if (copy_from_user(prtd->lsm_client->sound_model.data,
-			   snd_model_v2.data, snd_model_v2.data_size)) {
+		if (copy_from_user(
+				prtd->lsm_client->stage_cfg[stage_idx].sound_model.data,
+				snd_model_v2.data, snd_model_v2.data_size)) {
 			dev_err(rtd->dev,
 				"%s: copy from user data failed\n"
 			       "data %pK size %d\n", __func__,
 			       snd_model_v2.data, snd_model_v2.data_size);
-			q6lsm_snd_model_buf_free(prtd->lsm_client);
+			q6lsm_snd_model_buf_free(prtd->lsm_client, &p_info);
 			rc = -EFAULT;
 			break;
 		}
@@ -1004,13 +1152,13 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
 				"%s: Register snd Model v2 failed =%d\n",
 			       __func__, rc);
 			kfree(confidence_level);
-			q6lsm_snd_model_buf_free(prtd->lsm_client);
+			q6lsm_snd_model_buf_free(prtd->lsm_client, &p_info);
 		}
 
 		kfree(prtd->lsm_client->confidence_levels);
 		prtd->lsm_client->confidence_levels = NULL;
 		break;
-
+	}
 	case SNDRV_LSM_SET_PARAMS:
 		dev_dbg(rtd->dev, "%s: set_params\n", __func__);
 		memcpy(&det_params, arg,
@@ -1260,10 +1408,14 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
 		break;
 	}
 	case SNDRV_LSM_LAB_CONTROL: {
-		struct lsm_hw_params *out_hw_params =
-				&prtd->lsm_client->out_hw_params;
-		u8 chmap[out_hw_params->num_chs];
-		u32 enable, ch_idx;
+		u32 enable = 0;
+		struct lsm_params_info_v2 p_info = {0};
+
+		if (prtd->lsm_client->num_stages > 1) {
+			dev_err(rtd->dev, "%s: %s: not supported for multi stage session\n",
+				__func__, "LSM_LAB_CONTROL");
+			return -EINVAL;
+		}
 
 		if (copy_from_user(&enable, arg, sizeof(enable))) {
 			dev_err(rtd->dev, "%s: %s: copy_frm_user failed\n",
@@ -1281,53 +1433,19 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
 			break;
 		}
 
-		if (prtd->lsm_client->lab_enable == enable) {
-			dev_dbg(rtd->dev,
-				"%s: Lab for session %d already %s\n",
-				__func__, prtd->lsm_client->session,
-				enable ? "enabled" : "disabled");
-			rc = 0;
-			break;
-		}
-
-		rc = q6lsm_lab_control(prtd->lsm_client, enable);
-		if (rc) {
-			dev_err(rtd->dev,
-				"%s: ioctl %s failed rc %d to %s lab for session %d\n",
-				__func__, "SNDRV_LAB_CONTROL", rc,
-				enable ? "enable" : "disable",
-				prtd->lsm_client->session);
-			break;
-		}
-
-		rc = msm_lsm_lab_buffer_alloc(prtd,
-			enable ? LAB_BUFFER_ALLOC
-			: LAB_BUFFER_DEALLOC);
-		if (rc) {
-			dev_err(rtd->dev,
-				"%s: msm_lsm_lab_buffer_alloc failed rc %d for %s",
-				__func__, rc,
-				enable ? "ALLOC" : "DEALLOC");
-			break;
-		}
-
-		prtd->lsm_client->lab_enable = enable;
-		memset(chmap, 0, out_hw_params->num_chs);
 		/*
-		 * First channel to be read from lab is always the
-		 * best channel (0xff). For second channel onwards,
-		 * the channel indices are 0, 1, .. etc
+		 * With multi-stage support lab control needs to set param info
+		 * specifying stage index for which this lab control is issued,
+		 * along with values of module/instance ids applicable for the stage.
+		 * Hence, set param info with default lab module/instance ids, and
+		 * set stage index to LSM_STAGE_INDEX_FIRST.
 		 */
-		chmap[0] = 0xFF;
-		for (ch_idx = 1; ch_idx < out_hw_params->num_chs; ch_idx++)
-			chmap[ch_idx] = ch_idx - 1;
-
-		rc = q6lsm_lab_out_ch_cfg(prtd->lsm_client, chmap);
-		if (rc)
-			dev_err(rtd->dev,
-				"%s: Failed to set lab out ch cfg %d\n",
-				__func__, rc);
-
+		p_info.param_type = LSM_LAB_CONTROL;
+		p_info.module_id = LSM_MODULE_ID_LAB;
+		p_info.instance_id = INSTANCE_ID_0;
+		p_info.stage_idx = LSM_STAGE_INDEX_FIRST;
+		p_info.param_size = 0;
+		rc = msm_lsm_check_and_set_lab_controls(substream, enable, &p_info);
 		break;
 	}
 	case SNDRV_LSM_STOP_LAB:
@@ -1476,6 +1594,16 @@ struct lsm_params_info_32 {
 	uint32_t param_type;
 };
 
+struct lsm_params_info_v2_32 {
+	u32 module_id;
+	u32 param_id;
+	u32 param_size;
+	compat_uptr_t param_data;
+	uint32_t param_type;
+	u16 instance_id;
+	u16 stage_idx;
+};
+
 struct snd_lsm_module_params_32 {
 	compat_uptr_t params;
 	u32 num_params;
@@ -1491,6 +1619,8 @@ enum {
 		_IOW('U', 0x0B, struct snd_lsm_module_params_32),
 	SNDRV_LSM_EVENT_STATUS_V3_32 =
 		_IOW('U', 0x0F, struct snd_lsm_event_status_v3_32),
+	SNDRV_LSM_SET_MODULE_PARAMS_V2_32 =
+		_IOW('U', 0x13, struct snd_lsm_module_params_32),
 };
 
 static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
@@ -1760,19 +1890,20 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
 		break;
 	}
 
-	case SNDRV_LSM_SET_MODULE_PARAMS_32: {
+	case SNDRV_LSM_SET_MODULE_PARAMS_32:
+	case SNDRV_LSM_SET_MODULE_PARAMS_V2_32: {
 		struct snd_lsm_module_params_32 p_data_32;
 		struct snd_lsm_module_params p_data;
-		u8 *params, *params32;
-		size_t p_size;
-		struct lsm_params_info_32 *p_info_32;
-		struct lsm_params_info *p_info;
-		int i;
+		u8 *params32;
+		size_t expected_size = 0, count;
+		struct lsm_params_info_32 *p_info_32 = NULL;
+		struct lsm_params_info_v2_32 *p_info_v2_32 = NULL;
+		struct lsm_params_info_v2 p_info;
 
 		if (!prtd->lsm_client->use_topology) {
 			dev_err(rtd->dev,
 				"%s: %s: not supported if not using topology\n",
-				__func__, "SET_MODULE_PARAMS_32");
+				__func__, "SET_MODULE_PARAMS(_V2)_32");
 			err = -EINVAL;
 			goto done;
 		}
@@ -1781,7 +1912,7 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
 				   sizeof(p_data_32))) {
 			dev_err(rtd->dev,
 				"%s: %s: copy_from_user failed, size = %zd\n",
-				__func__, "SET_MODULE_PARAMS_32",
+				__func__, "SET_MODULE_PARAMS(_V2)_32",
 				sizeof(p_data_32));
 			err = -EFAULT;
 			goto done;
@@ -1794,79 +1925,85 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
 		if (p_data.num_params > LSM_PARAMS_MAX) {
 			dev_err(rtd->dev,
 				"%s: %s: Invalid num_params %d\n",
-				__func__, "SET_MODULE_PARAMS_32",
+				__func__, "SET_MODULE_PARAMS(_V2)_32",
 				p_data.num_params);
 			err = -EINVAL;
 			goto done;
 		}
 
-		if (p_data.data_size !=
-		    (p_data.num_params * sizeof(struct lsm_params_info_32))) {
+		expected_size = (cmd == SNDRV_LSM_SET_MODULE_PARAMS_32) ?
+					p_data.num_params * sizeof(struct lsm_params_info_32) :
+					p_data.num_params * sizeof(struct lsm_params_info_v2_32);
+
+		if (p_data.data_size != expected_size) {
 			dev_err(rtd->dev,
 				"%s: %s: Invalid size %d\n",
-				__func__, "SET_MODULE_PARAMS_32",
+				__func__, "SET_MODULE_PARAMS(_V2)_32",
 				p_data.data_size);
 			err = -EINVAL;
 			goto done;
 		}
 
-		p_size = sizeof(struct lsm_params_info_32) *
-			 p_data.num_params;
-
-		params32 = kzalloc(p_size, GFP_KERNEL);
+		params32 = kzalloc(p_data.data_size, GFP_KERNEL);
 		if (!params32) {
 			err = -ENOMEM;
 			goto done;
 		}
 
-		p_size = sizeof(struct lsm_params_info) * p_data.num_params;
-		params = kzalloc(p_size, GFP_KERNEL);
-		if (!params) {
-			dev_err(rtd->dev,
-				"%s: no memory for params, size = %zd\n",
-				__func__, p_size);
-			kfree(params32);
-			err = -ENOMEM;
-			goto done;
-		}
-
 		if (copy_from_user(params32, p_data.params,
 				   p_data.data_size)) {
 			dev_err(rtd->dev,
 				"%s: %s: copy_from_user failed, size = %d\n",
 				__func__, "params32", p_data.data_size);
 			kfree(params32);
-			kfree(params);
 			err = -EFAULT;
 			goto done;
 		}
 
-		p_info_32 = (struct lsm_params_info_32 *) params32;
-		p_info = (struct lsm_params_info *) params;
-		for (i = 0; i < p_data.num_params; i++) {
-			p_info->module_id = p_info_32->module_id;
-			p_info->param_id = p_info_32->param_id;
-			p_info->param_size = p_info_32->param_size;
-			p_info->param_data = compat_ptr(p_info_32->param_data);
-			p_info->param_type = p_info_32->param_type;
+		if (cmd == SNDRV_LSM_SET_MODULE_PARAMS_32)
+			p_info_32 = (struct lsm_params_info_32 *) params32;
+		else
+			p_info_v2_32 = (struct lsm_params_info_v2_32 *) params32;
+
+		for (count = 0; count < p_data.num_params; count++) {
+			if (cmd == SNDRV_LSM_SET_MODULE_PARAMS_32) {
+				p_info.module_id = p_info_32->module_id;
+				p_info.param_id = p_info_32->param_id;
+				p_info.param_size = p_info_32->param_size;
+				p_info.param_data = compat_ptr(p_info_32->param_data);
+				p_info.param_type = p_info_32->param_type;
 
-			p_info_32++;
-			p_info++;
+				p_info.instance_id = INSTANCE_ID_0;
+				p_info.stage_idx = LSM_STAGE_INDEX_FIRST;
+
+				p_info_32++;
+			} else {
+				p_info.module_id = p_info_v2_32->module_id;
+				p_info.param_id = p_info_v2_32->param_id;
+				p_info.param_size = p_info_v2_32->param_size;
+				p_info.param_data = compat_ptr(p_info_v2_32->param_data);
+				p_info.param_type = p_info_v2_32->param_type;
+
+				p_info.instance_id = p_info_v2_32->instance_id;
+				p_info.stage_idx = p_info_v2_32->stage_idx;
+
+				p_info_v2_32++;
+			}
+
+			err = msm_lsm_process_params(substream, &p_info);
+			if (err)
+				dev_err(rtd->dev,
+					"%s: Failed to process param, type%d stage=%d err=%d\n",
+					__func__, p_info.param_type, p_info.stage_idx, err);
 		}
 
-		err = msm_lsm_process_params(substream,
-					     &p_data, params);
-		if (err)
-			dev_err(rtd->dev,
-				"%s: Failed to process params, err = %d\n",
-				__func__, err);
-		kfree(params);
 		kfree(params32);
 		break;
 	}
 	case SNDRV_LSM_REG_SND_MODEL_V2:
 	case SNDRV_LSM_SET_PARAMS:
 	case SNDRV_LSM_SET_MODULE_PARAMS:
+	case SNDRV_LSM_SET_MODULE_PARAMS_V2:
 		/*
 		 * In ideal cases, the compat_ioctl should never be called
 		 * with the above unlocked ioctl commands. Print error
@@ -1970,15 +2107,19 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
 		goto done;
 	}
 
-	case SNDRV_LSM_SET_MODULE_PARAMS: {
+	case SNDRV_LSM_SET_MODULE_PARAMS:
+	case SNDRV_LSM_SET_MODULE_PARAMS_V2: {
 		struct snd_lsm_module_params p_data;
-		size_t p_size;
+		struct lsm_params_info *temp_ptr_info = NULL;
+		struct lsm_params_info_v2 info_v2;
+		struct lsm_params_info_v2 *ptr_info_v2 = NULL, *temp_ptr_info_v2 = NULL;
+		size_t p_size = 0, count;
 		u8 *params;
 
 		if (!prtd->lsm_client->use_topology) {
 			dev_err(rtd->dev,
 				"%s: %s: not supported if not using topology\n",
-				__func__, "SET_MODULE_PARAMS");
+				__func__, "SET_MODULE_PARAMS(_V2)");
 			err = -EINVAL;
 			goto done;
 		}
@@ -1995,20 +2136,22 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
 		if (p_data.num_params > LSM_PARAMS_MAX) {
 			dev_err(rtd->dev,
 				"%s: %s: Invalid num_params %d\n",
-				__func__, "SET_MODULE_PARAMS",
+				__func__, "SET_MODULE_PARAMS(_V2)",
 				p_data.num_params);
 			err = -EINVAL;
 			goto done;
 		}
 
-		p_size = p_data.num_params *
-			 sizeof(struct lsm_params_info);
+		if (cmd == SNDRV_LSM_SET_MODULE_PARAMS)
+			p_size = p_data.num_params * sizeof(struct lsm_params_info);
+		else
+			p_size = p_data.num_params * sizeof(struct lsm_params_info_v2);
 
 		if (p_data.data_size != p_size) {
 			dev_err(rtd->dev,
-				"%s: %s: Invalid size %zd\n",
-				__func__, "SET_MODULE_PARAMS", p_size);
-
+				"%s: %s: Invalid data_size(%zd) against expected(%zd)\n",
+				__func__, "SET_MODULE_PARAMS(_V2)",
+				p_data.data_size, p_size);
 			err = -EFAULT;
 			goto done;
 		}
@@ -2020,20 +2163,46 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
 		}
 
 		if (copy_from_user(params, p_data.params,
-				   p_data.data_size)) {
+				  p_data.data_size)) {
 			dev_err(rtd->dev,
 				"%s: %s: copy_from_user failed, size = %d\n",
-				__func__, "params", p_data.data_size);
+				__func__, "set module params", p_data.data_size);
 			kfree(params);
 			err = -EFAULT;
 			goto done;
 		}
 
-		err = msm_lsm_process_params(substream, &p_data, params);
-		if (err)
-			dev_err(rtd->dev,
-				"%s: %s: Failed to set params, err = %d\n",
-				__func__, "SET_MODULE_PARAMS", err);
+		if (cmd == SNDRV_LSM_SET_MODULE_PARAMS)
+			temp_ptr_info = (struct lsm_params_info *)params;
+		else
+			temp_ptr_info_v2 = (struct lsm_params_info_v2 *)params;
+
+		for (count = 0; count < p_data.num_params; count++) {
+			if (cmd == SNDRV_LSM_SET_MODULE_PARAMS) {
+				/* convert to V2 param info struct from legacy param info */
+				info_v2.module_id = temp_ptr_info->module_id;
+				info_v2.param_id = temp_ptr_info->param_id;
+				info_v2.param_size = temp_ptr_info->param_size;
+				info_v2.param_data = temp_ptr_info->param_data;
+				info_v2.param_type = temp_ptr_info->param_type;
+
+				info_v2.instance_id = INSTANCE_ID_0;
+				info_v2.stage_idx = LSM_STAGE_INDEX_FIRST;
+
+				ptr_info_v2 = &info_v2;
+				temp_ptr_info++;
+			} else {
+				/* Just copy the pointer as user already provided v2 params */
+				ptr_info_v2 = temp_ptr_info_v2;
+				temp_ptr_info_v2++;
+			}
+			err = msm_lsm_process_params(substream, ptr_info_v2);
+			if (err)
+				dev_err(rtd->dev,
+					"%s: Failed to process param, type%d stage=%d err=%d\n",
+					__func__, ptr_info_v2->param_type,
+					ptr_info_v2->stage_idx, err);
+		}
 		kfree(params);
 		break;
 	}

+ 346 - 157
dsp/q6lsm.c

@@ -87,7 +87,8 @@ static spinlock_t lsm_session_lock;
 static struct lsm_client *lsm_session[LSM_MAX_SESSION_ID + 1];
 
 static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv);
-static int q6lsm_send_cal(struct lsm_client *client, u32 set_params_opcode);
+static int q6lsm_send_cal(struct lsm_client *client,
+		u32 set_params_opcode, struct lsm_params_info_v2 *p_info);
 static int q6lsm_memory_map_regions(struct lsm_client *client,
 				    dma_addr_t dma_addr_p, uint32_t dma_buf_sz,
 				    uint32_t *mmap_p);
@@ -166,6 +167,7 @@ static int q6lsm_callback(struct apr_client_data *data, void *priv)
 		case LSM_SESSION_CMD_EOB:
 		case LSM_SESSION_CMD_READ:
 		case LSM_SESSION_CMD_OPEN_TX_V2:
+		case LSM_SESSION_CMD_OPEN_TX_V3:
 		case LSM_CMD_ADD_TOPOLOGIES:
 		case LSM_SESSION_CMD_SET_PARAMS_V2:
 		case LSM_SESSION_CMD_SET_PARAMS_V3:
@@ -689,6 +691,94 @@ done:
 	return rc;
 }
 
+static int q6lsm_get_topology_for_app_type(struct lsm_client *client,
+				int app_type, uint32_t *topology)
+{
+	int rc = -EINVAL;
+	struct cal_block_data *cal_block = NULL;
+	struct audio_cal_info_lsm_top *lsm_top;
+	struct list_head *ptr;
+
+	if (lsm_common.cal_data[LSM_TOP_IDX] == NULL) {
+		pr_err("%s: LSM_TOP_IDX invalid\n", __func__);
+		return rc;
+	}
+
+	mutex_lock(&lsm_common.cal_data[LSM_TOP_IDX]->lock);
+	list_for_each(ptr, &lsm_common.cal_data[LSM_TOP_IDX]->cal_blocks) {
+		cal_block = list_entry(ptr, struct cal_block_data, list);
+		if (!cal_block) {
+			pr_err("%s: Cal block for LSM_TOP_IDX not found\n",
+				__func__);
+			break;
+		}
+
+		lsm_top = (struct audio_cal_info_lsm_top *) cal_block->cal_info;
+		if (!lsm_top) {
+			pr_err("%s: cal_info for LSM_TOP_IDX not found\n",
+				__func__);
+			break;
+		}
+
+		pr_debug("%s: checking topology 0x%x, app_type 0x%x\n",
+			 __func__, lsm_top->topology, lsm_top->app_type);
+
+		if (app_type == 0  || lsm_top->app_type == app_type) {
+			*topology = lsm_top->topology;
+			rc = 0;
+			break;
+		}
+	}
+	mutex_unlock(&lsm_common.cal_data[LSM_TOP_IDX]->lock);
+
+	pr_debug("%s: found topology_id = 0x%x, app_type = 0x%x\n",
+		 __func__, *topology, app_type);
+
+	return rc;
+}
+
+static int q6lsm_do_open_v3(struct lsm_client *client)
+{
+	int rc, app_type;
+	struct lsm_stream_cmd_open_tx_v3 *open_v3;
+	size_t cmd_size = 0, stage_idx = LSM_STAGE_INDEX_FIRST;
+	uint32_t topology_id = 0, *uint32_ptr = NULL;
+
+	cmd_size = sizeof(struct lsm_stream_cmd_open_tx_v3);
+	cmd_size += client->num_stages * sizeof(struct lsm_stream_stage_info);
+	open_v3 = kzalloc(cmd_size, GFP_KERNEL);
+	if (!open_v3)
+		return -ENOMEM;
+
+	q6lsm_add_hdr(client, &open_v3->hdr, cmd_size, true);
+	open_v3->hdr.opcode = LSM_SESSION_CMD_OPEN_TX_V3;
+	open_v3->num_stages = client->num_stages;
+	uint32_ptr = &open_v3->num_stages;
+	uint32_ptr++;
+
+	for (; stage_idx < client->num_stages; stage_idx++) {
+		app_type = client->stage_cfg[stage_idx].app_type;
+		rc = q6lsm_get_topology_for_app_type(client, app_type, &topology_id);
+		if (rc) {
+			pr_err("%s: failed to get topology for stage %d\n",
+				 __func__, stage_idx);
+			return -EINVAL;
+		}
+		*uint32_ptr++ = topology_id;
+		*uint32_ptr++ = client->stage_cfg[stage_idx].lpi_enable;
+	}
+
+	rc = q6lsm_apr_send_pkt(client, client->apr, open_v3, true, NULL);
+	if (rc)
+		pr_err("%s: open_v3 failed, err = %d\n", __func__, rc);
+	else
+		client->use_topology = true;
+
+	kfree(open_v3);
+	return rc;
+
+}
+
 static int q6lsm_do_open_v2(struct lsm_client *client,
 		uint16_t app_id)
 {
@@ -722,9 +812,8 @@ static int q6lsm_do_open_v2(struct lsm_client *client,
 		goto unlock;
 	}
 
-	pr_debug("%s: topology_id = 0x%x, acdb_id = 0x%x, app_type = 0x%x\n",
-		 __func__, lsm_top->topology, lsm_top->acdb_id,
-		 lsm_top->app_type);
+	pr_debug("%s: topology_id = 0x%x, app_type = 0x%x\n",
+		 __func__, lsm_top->topology, lsm_top->app_type);
 
 	if (lsm_top->topology == 0) {
 		pr_err("%s: toplogy id not sent for app_type 0x%x\n",
@@ -764,26 +853,41 @@ done:
  *
  */
 void q6lsm_sm_set_param_data(struct lsm_client *client,
-		struct lsm_params_info *p_info,
+		struct lsm_params_info_v2 *p_info,
 		size_t *offset)
 {
 	struct param_hdr_v3 param_hdr;
-	int ret = 0;
+	int ret;
+	struct lsm_sound_model *sm;
 
+	sm = &client->stage_cfg[p_info->stage_idx].sound_model;
 	memset(&param_hdr, 0, sizeof(param_hdr));
 
 	param_hdr.module_id = p_info->module_id;
-	param_hdr.instance_id = INSTANCE_ID_0;
+	param_hdr.instance_id = p_info->instance_id;
 	param_hdr.param_id = p_info->param_id;
-	param_hdr.param_size = client->sound_model.size;
+	param_hdr.param_size = sm->size;
 
-	ret = q6lsm_pack_params(client->sound_model.data, &param_hdr,
+	ret = q6lsm_pack_params(sm->data, &param_hdr,
 				NULL, offset, LSM_SESSION_CMD_SET_PARAMS_V2);
 	if (ret)
 		pr_err("%s: Failed to pack params, error %d\n", __func__, ret);
 }
 EXPORT_SYMBOL(q6lsm_sm_set_param_data);
 
+/**
+ * q6lsm_support_multi_stage_detection -
+ *       check for multi-stage support in adsp lsm framework service
+ *
+ * Returns true if multi-stage support available, else false
+ */
+bool q6lsm_adsp_supports_multi_stage_detection(void)
+{
+	return q6core_get_avcs_api_version_per_service(
+			APRV2_IDS_SERVICE_ID_ADSP_LSM_V) >= LSM_API_VERSION_V3;
+}
+EXPORT_SYMBOL(q6lsm_adsp_supports_multi_stage_detection);
+
 /**
  * q6lsm_open -
  *       command to open LSM session
@@ -807,9 +911,13 @@ int q6lsm_open(struct lsm_client *client, uint16_t app_id)
 	}
 
 	/* Try to open with topology first */
-	rc = q6lsm_do_open_v2(client, app_id);
+	if ((client->stage_cfg[LSM_STAGE_INDEX_FIRST].app_type != 0) &&
+		q6lsm_adsp_supports_multi_stage_detection())
+		rc = q6lsm_do_open_v3(client);
+	else
+		rc = q6lsm_do_open_v2(client, app_id);
 	if (!rc)
-		/* open_v2 was successful */
+		/* open_v2/v3 was successful */
 		goto done;
 
 	pr_debug("%s: try without topology\n",
@@ -1183,6 +1291,7 @@ int q6lsm_set_data(struct lsm_client *client,
 {
 	struct param_hdr_v3 param_hdr;
 	int rc = 0;
+	struct lsm_params_info_v2 p_info = {0};
 
 	memset(&param_hdr, 0, sizeof(param_hdr));
 
@@ -1228,7 +1337,8 @@ int q6lsm_set_data(struct lsm_client *client,
 		goto err_ret;
 	}
 
-	rc = q6lsm_send_cal(client, LSM_SESSION_CMD_SET_PARAMS);
+	p_info.stage_idx = LSM_STAGE_INDEX_FIRST;
+	rc = q6lsm_send_cal(client, LSM_SESSION_CMD_SET_PARAMS, &p_info);
 	if (rc) {
 		pr_err("%s: Failed to send calibration data %d\n",
 			__func__, rc);
@@ -1254,6 +1364,7 @@ int q6lsm_register_sound_model(struct lsm_client *client,
 {
 	int rc;
 	struct lsm_cmd_reg_snd_model cmd;
+	struct lsm_sound_model *sm;
 
 	memset(&cmd, 0, sizeof(cmd));
 	rc = q6lsm_set_data(client, mode, detectfailure);
@@ -1263,18 +1374,19 @@ int q6lsm_register_sound_model(struct lsm_client *client,
 		return rc;
 	}
 
+	sm = &client->stage_cfg[LSM_STAGE_INDEX_FIRST].sound_model;
+
 	q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd), true);
 	cmd.hdr.opcode = LSM_SESSION_CMD_REGISTER_SOUND_MODEL;
-	cmd.model_addr_lsw = lower_32_bits(client->sound_model.phys);
-	cmd.model_addr_msw = msm_audio_populate_upper_32_bits(
-						client->sound_model.phys);
-	cmd.model_size = client->sound_model.size;
+	cmd.model_addr_lsw = lower_32_bits(sm->phys);
+	cmd.model_addr_msw = msm_audio_populate_upper_32_bits(sm->phys);
+	cmd.model_size = sm->size;
 	/* read updated mem_map_handle by q6lsm_mmapcallback */
 	rmb();
-	cmd.mem_map_handle = client->sound_model.mem_map_handle;
+	cmd.mem_map_handle = sm->mem_map_handle;
 
 	pr_debug("%s: addr %pK, size %d, handle 0x%x\n", __func__,
-		&client->sound_model.phys, cmd.model_size, cmd.mem_map_handle);
+		&sm->phys, cmd.model_size, cmd.mem_map_handle);
 	rc = q6lsm_apr_send_pkt(client, client->apr, &cmd, true, NULL);
 	if (rc)
 		pr_err("%s: Failed cmd op[0x%x]rc[%d]\n", __func__,
@@ -1298,6 +1410,16 @@ int q6lsm_deregister_sound_model(struct lsm_client *client)
 {
 	int rc;
 	struct lsm_cmd_reg_snd_model cmd;
+	/*
+	 * With multi-stage support sm buff allocation/free usage param info
+	 * to check stage index for which this sound model is being set, and
+	 * to check whether sm data is sent using set param command or not.
+	 * Hence, set param ids to '0' to indicate allocation is for legacy
+	 * reg_sm cmd, where buffer for param header need not be allocated,
+	 * also set stage index to LSM_STAGE_INDEX_FIRST.
+	 */
+	struct lsm_params_info_v2 p_info = {0};
+	p_info.stage_idx = LSM_STAGE_INDEX_FIRST;
 
 	if (!client) {
 		pr_err("APR handle NULL\n");
@@ -1325,7 +1447,7 @@ int q6lsm_deregister_sound_model(struct lsm_client *client)
 		pr_debug("%s: Deregister sound model succeeded\n", __func__);
 	}
 
-	q6lsm_snd_model_buf_free(client);
+	q6lsm_snd_model_buf_free(client, &p_info);
 
 	return rc;
 }
@@ -1425,11 +1547,11 @@ static int q6lsm_memory_unmap_regions(struct lsm_client *client,
 }
 
 static int q6lsm_send_cal(struct lsm_client *client,
-			  u32 set_params_opcode)
+			u32 set_params_opcode, struct lsm_params_info_v2 *p_info)
 {
-	int rc = 0;
+	int rc = 0, stage_idx = p_info->stage_idx;
 	struct mem_mapping_hdr mem_hdr;
-	struct cal_block_data *cal_block = NULL;
+	dma_addr_t lsm_cal_phy_addr;
 
 	memset(&mem_hdr, 0, sizeof(mem_hdr));
 
@@ -1439,40 +1561,132 @@ static int q6lsm_send_cal(struct lsm_client *client,
 		return -EINVAL;
 	}
 
-	if (lsm_common.cal_data[LSM_CAL_IDX] == NULL)
-		goto done;
+	lsm_cal_phy_addr = client->stage_cfg[stage_idx].cal_info.phys;
+	if (lsm_cal_phy_addr != 0) {
+		lsm_common.common_client[client->session].session = client->session;
+		mem_hdr.data_payload_addr_lsw = lower_32_bits(lsm_cal_phy_addr);
+		mem_hdr.data_payload_addr_msw =
+			msm_audio_populate_upper_32_bits(lsm_cal_phy_addr);
+		mem_hdr.mem_map_handle =
+			client->stage_cfg[stage_idx].cal_info.mem_map_handle;
+
+		rc = q6lsm_set_params(client, &mem_hdr, NULL,
+				client->stage_cfg[stage_idx].cal_info.size, set_params_opcode);
+		if (rc)
+			pr_err("%s: Failed set_params, rc %d\n", __func__, rc);
+	}
+
+	return rc;
+}
+
+static int q6lsm_snd_cal_free(struct lsm_client *client,
+			struct lsm_params_info_v2 *p_info)
+{
+	int rc = 0, stage_idx = p_info->stage_idx;
+	struct lsm_cal_data_info *cal = NULL;
+
+	if (!client->stage_cfg[stage_idx].cal_info.data)
+		return 0;
+
+	mutex_lock(&client->cmd_lock);
+	cal = &client->stage_cfg[stage_idx].cal_info;
+	if (cal->mem_map_handle != 0) {
+		rc = q6lsm_memory_unmap_regions(client, cal->mem_map_handle);
+		if (rc)
+			pr_err("%s: CMD Memory_unmap_regions failed %d\n",
+					__func__, rc);
+		cal->mem_map_handle = 0;
+	}
+	msm_audio_ion_free(cal->dma_buf);
+	cal->dma_buf = NULL;
+	cal->data = NULL;
+	cal->phys = 0;
+	mutex_unlock(&client->cmd_lock);
+
+	return rc;
+}
+
+static int q6lsm_snd_cal_alloc(struct lsm_client *client,
+			struct lsm_params_info_v2 *p_info)
+{
+	int rc = 0;
+	size_t len = 0, total_mem = 0;
+	struct lsm_cal_data_info *cal = NULL;
+	struct cal_block_data *cal_block = NULL;
+	struct audio_cal_info_lsm *lsm_cal_info = NULL;
+	struct list_head *ptr = NULL;
+	int app_type, stage_idx = p_info->stage_idx;
+	bool cal_block_found = false;
+
+	app_type = client->stage_cfg[stage_idx].app_type;
+	pr_debug("%s: app_type %d, stage_idx %d\n",
+			__func__, app_type, stage_idx);
 
+	mutex_lock(&client->cmd_lock);
 	mutex_lock(&lsm_common.cal_data[LSM_CAL_IDX]->lock);
-	cal_block = cal_utils_get_only_cal_block(
-		lsm_common.cal_data[LSM_CAL_IDX]);
+	list_for_each(ptr, &lsm_common.cal_data[LSM_CAL_IDX]->cal_blocks) {
+		cal_block = list_entry(ptr, struct cal_block_data, list);
+		lsm_cal_info = (struct audio_cal_info_lsm *)
+						(cal_block) ? cal_block->cal_info : NULL;
+		if ((cal_block && cal_block->cal_data.paddr) &&
+			(lsm_cal_info != NULL) &&
+			(app_type == 0 || app_type == lsm_cal_info->app_type)) {
+			cal_block_found = true;
+			len = cal_block->cal_data.size;
+			break;
+		}
+	}
 
-	if (!cal_block || cal_block->cal_data.size <= 0) {
-		pr_debug("%s: No cal to send!\n", __func__);
-		goto unlock;
+	if (!cal_block_found) {
+		pr_info("%s: cal not found for stage_idx %d\n", __func__, stage_idx);
+		goto exit;
 	}
 
-	if (cal_block->cal_data.size != client->lsm_cal_size) {
-		pr_err("%s: Cal size %zd doesn't match lsm cal size %d\n",
-			__func__, cal_block->cal_data.size,
-			client->lsm_cal_size);
-		rc = -EINVAL;
-		goto unlock;
+	if (!len) {
+		pr_debug("%s: cal size is 0, for stage_idx %d\n", __func__, stage_idx);
+		goto exit;
 	}
-	/* Cache mmap address, only map once or if new addr */
-	lsm_common.common_client[client->session].session = client->session;
-	mem_hdr.data_payload_addr_lsw = lower_32_bits(client->lsm_cal_phy_addr);
-	mem_hdr.data_payload_addr_msw =
-		msm_audio_populate_upper_32_bits(client->lsm_cal_phy_addr);
-	mem_hdr.mem_map_handle = client->sound_model.mem_map_handle;
 
-	pr_debug("%s: Cal Size = %zd", __func__, cal_block->cal_data.size);
-	rc = q6lsm_set_params(client, &mem_hdr, NULL, cal_block->cal_data.size,
-			      set_params_opcode);
-	if (rc)
-		pr_err("%s: Failed set_params, rc %d\n", __func__, rc);
-unlock:
+	cal = &client->stage_cfg[stage_idx].cal_info;
+	if (cal->data) {
+		pr_debug("%s: cal data for stage_idx(%d) is already set \n",
+			__func__, stage_idx);
+		goto exit;
+	}
+
+	cal->size = len;
+	total_mem = PAGE_ALIGN(len);
+	pr_debug("%s: cal info data size %zd Total mem %zd, stage_idx %d\n",
+		 __func__, len, total_mem, stage_idx);
+
+	rc = msm_audio_ion_alloc(&cal->dma_buf, total_mem,
+			&cal->phys, &len, &cal->data);
+	if (rc) {
+		pr_err("%s: Audio ION alloc is failed for stage_idx %d, rc = %d\n",
+			__func__, stage_idx, rc);
+		cal->dma_buf = NULL;
+		cal->data = NULL;
+		goto exit;
+	}
+
+	memcpy(cal->data, (uint32_t *)cal_block->cal_data.kvaddr, cal->size);
 	mutex_unlock(&lsm_common.cal_data[LSM_CAL_IDX]->lock);
-done:
+	mutex_unlock(&client->cmd_lock);
+	rc = q6lsm_memory_map_regions(client, cal->phys, len, &cal->mem_map_handle);
+	if (rc) {
+		pr_err("%s: CMD Memory_map_regions failed for stage_idx %d, rc = %d\n",
+			__func__, stage_idx, rc);
+		cal->mem_map_handle = 0;
+		goto fail;
+	}
+
+	return 0;
+
+exit:
+	mutex_unlock(&client->cmd_lock);
+	mutex_unlock(&lsm_common.cal_data[LSM_CAL_IDX]->lock);
+fail:
+	q6lsm_snd_cal_free(client, p_info);
 	return rc;
 }
 
@@ -1481,12 +1695,15 @@ done:
  *       Free memory for LSM snd model
  *
  * @client: LSM client handle
+ * @p_info: sound model param info
  *
  * Returns 0 on success or error on failure
  */
-int q6lsm_snd_model_buf_free(struct lsm_client *client)
+int q6lsm_snd_model_buf_free(struct lsm_client *client,
+			struct lsm_params_info_v2 *p_info)
 {
-	int rc;
+	int rc = 0, stage_idx = p_info->stage_idx;
+	struct lsm_sound_model *sm = NULL;
 
 	pr_debug("%s: Session id %d\n", __func__, client->session);
 	if (CHECK_SESSION(client->session)) {
@@ -1494,22 +1711,25 @@ int q6lsm_snd_model_buf_free(struct lsm_client *client)
 		return -EINVAL;
 	}
 
-	mutex_lock(&client->cmd_lock);
-	rc = q6lsm_memory_unmap_regions(client,
-					client->sound_model.mem_map_handle);
-	if (rc)
-		pr_err("%s: CMD Memory_unmap_regions failed %d\n",
-			__func__, rc);
+	if (!client->stage_cfg[stage_idx].sound_model.data)
+		return 0;
 
-	if (client->sound_model.data) {
-		msm_audio_ion_free(client->sound_model.dma_buf);
-		client->sound_model.dma_buf = NULL;
-		client->sound_model.data = NULL;
-		client->sound_model.phys = 0;
-		client->lsm_cal_phy_addr = 0;
-		client->lsm_cal_size = 0;
+	mutex_lock(&client->cmd_lock);
+	sm = &client->stage_cfg[stage_idx].sound_model;
+	if (sm->mem_map_handle != 0) {
+		rc = q6lsm_memory_unmap_regions(client, sm->mem_map_handle);
+		if (rc)
+			pr_err("%s: CMD Memory_unmap_regions failed %d\n",
+				__func__, rc);
+		sm->mem_map_handle = 0;
 	}
+	msm_audio_ion_free(sm->dma_buf);
+	sm->dma_buf = NULL;
+	sm->data = NULL;
+	sm->phys = 0;
 	mutex_unlock(&client->cmd_lock);
+
+	rc = q6lsm_snd_cal_free(client, p_info);
 	return rc;
 }
 EXPORT_SYMBOL(q6lsm_snd_model_buf_free);
@@ -1551,7 +1771,6 @@ static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv)
 		apr_reset(lsm_common.apr);
 		lsm_common.apr = NULL;
 		atomic_set(&lsm_common.apr_users, 0);
-		lsm_common.common_client[sid].lsm_cal_phy_addr = 0;
 		cal_utils_clear_cal_block_q6maps(LSM_MAX_CAL_IDX,
 			lsm_common.cal_data);
 		lsm_common.set_custom_topology = 1;
@@ -1623,109 +1842,73 @@ static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv)
  *
  * @client: LSM client handle
  * @len: size of sound model
- * @allocate_module_data: flag to allocate for set_param payload
+ * @p_info: sound model param info
+ *          p_info->param_id != 0 when using set param to register sound model
  *
  * Returns 0 on success or error on failure
  */
 int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len,
-			      bool allocate_module_data)
+			      struct lsm_params_info_v2 *p_info)
 {
-	int rc = -EINVAL;
-	struct cal_block_data		*cal_block = NULL;
-
-	size_t pad_zero = 0, total_mem = 0;
+	int rc = -EINVAL, stage_idx = p_info->stage_idx;
+	size_t total_mem = 0;
+	struct lsm_sound_model *sm = NULL;
 
 	if (!client || len <= LSM_ALIGN_BOUNDARY)
 		return rc;
 
-	mutex_lock(&client->cmd_lock);
-
-	mutex_lock(&lsm_common.cal_data[LSM_CAL_IDX]->lock);
-	cal_block = cal_utils_get_only_cal_block(
-		lsm_common.cal_data[LSM_CAL_IDX]);
-	if (cal_block == NULL)
-		goto fail;
-
-	pr_debug("%s:Snd Model len = %zd cal size %zd phys addr %pK", __func__,
-		len, cal_block->cal_data.size,
-		&cal_block->cal_data.paddr);
-	if (!cal_block->cal_data.paddr) {
-		pr_err("%s: No LSM calibration set for session", __func__);
-		rc = -EINVAL;
-		goto fail;
-	}
-	if (!client->sound_model.data) {
+	pr_debug("%s:Snd Model len = %zd, stage idx %d\n",
+			__func__, len, stage_idx);
 
+	mutex_lock(&client->cmd_lock);
+	sm = &client->stage_cfg[stage_idx].sound_model;
+	if (!sm->data) {
 		/*
-		 * if sound module is sent as set_param
+		 * If sound model is sent as set_param, i.e. param_id != 0,
 		 * Then memory needs to be allocated for
 		 * set_param payload as well.
 		 */
-		if (allocate_module_data)
+		if (p_info->param_id != 0)
 			len += sizeof(union param_hdrs);
 
-		client->sound_model.size = len;
-		pad_zero = (LSM_ALIGN_BOUNDARY -
-			    (len % LSM_ALIGN_BOUNDARY));
-		if ((len > SIZE_MAX - pad_zero) ||
-		    (len + pad_zero >
-		     SIZE_MAX - cal_block->cal_data.size)) {
-			pr_err("%s: invalid allocation size, len = %zd, pad_zero =%zd, cal_size = %zd\n",
-				__func__, len, pad_zero,
-				cal_block->cal_data.size);
-			rc = -EINVAL;
-			goto fail;
-		}
-
-		total_mem = PAGE_ALIGN(pad_zero + len +
-			cal_block->cal_data.size);
-		pr_debug("%s: Pad zeros sound model %zd Total mem %zd\n",
-				 __func__, pad_zero, total_mem);
-		rc = msm_audio_ion_alloc(&client->sound_model.dma_buf,
-				total_mem,
-				&client->sound_model.phys,
-				&len,
-				&client->sound_model.data);
+		sm->size = len;
+		total_mem = PAGE_ALIGN(len);
+		pr_debug("%s: sm param size %zd Total mem %zd, stage_idx %d\n",
+				 __func__, len, total_mem, stage_idx);
+		rc = msm_audio_ion_alloc(&sm->dma_buf, total_mem,
+								&sm->phys, &len, &sm->data);
 		if (rc) {
-			pr_err("%s: Audio ION alloc is failed, rc = %d\n",
-				__func__, rc);
+			pr_err("%s: Audio ION alloc is failed, rc = %d, stage_idx = %d\n",
+				__func__, rc, stage_idx);
 			goto fail;
 		}
-	pr_debug("%s: Length = %zd\n", __func__, len);
-	client->lsm_cal_phy_addr = (pad_zero +
-				    client->sound_model.phys +
-				    client->sound_model.size);
-	client->lsm_cal_size = cal_block->cal_data.size;
-	memcpy((client->sound_model.data + pad_zero +
-		client->sound_model.size),
-	       (uint32_t *)cal_block->cal_data.kvaddr, client->lsm_cal_size);
-	pr_debug("%s: Copy cal start virt_addr %pK phy_addr %pK\n"
-			 "Offset cal virtual Addr %pK\n", __func__,
-			 client->sound_model.data, &client->sound_model.phys,
-			 (pad_zero + client->sound_model.data +
-			 client->sound_model.size));
 	} else {
-		pr_err("%s: sound model busy\n", __func__);
+		pr_err("%s: sound model busy, stage_idx %d\n", __func__, stage_idx);
 		rc = -EBUSY;
 		goto fail;
 	}
-	mutex_unlock(&lsm_common.cal_data[LSM_CAL_IDX]->lock);
+
+	rc = q6lsm_memory_map_regions(client, sm->phys, len, &sm->mem_map_handle);
+	if (rc) {
+		pr_err("%s: CMD Memory_map_regions failed %d, stage_idx %d\n",
+			__func__, rc, stage_idx);
+		sm->mem_map_handle = 0;
+		goto fail;
+	}
 	mutex_unlock(&client->cmd_lock);
 
-	rc = q6lsm_memory_map_regions(client, client->sound_model.phys,
-				      len,
-				      &client->sound_model.mem_map_handle);
+	rc = q6lsm_snd_cal_alloc(client, p_info);
 	if (rc) {
-		pr_err("%s: CMD Memory_map_regions failed %d\n", __func__, rc);
-		goto exit;
+		pr_err("%s: cal alloc failed %d, stage_idx %d\n",
+			__func__, rc, stage_idx);
+		goto fail_1;
 	}
+	return rc;
 
-	return 0;
 fail:
-	mutex_unlock(&lsm_common.cal_data[LSM_CAL_IDX]->lock);
 	mutex_unlock(&client->cmd_lock);
-exit:
-	q6lsm_snd_model_buf_free(client);
+fail_1:
+	q6lsm_snd_model_buf_free(client, p_info);
 	return rc;
 }
 EXPORT_SYMBOL(q6lsm_snd_model_buf_alloc);
@@ -1811,7 +1994,7 @@ static int q6lsm_send_param_gain(struct lsm_client *client, u16 gain,
  * Returns 0 on success or error on failure
  */
 int q6lsm_set_one_param(struct lsm_client *client,
-	struct lsm_params_info *p_info, void *data,
+	struct lsm_params_info_v2 *p_info, void *data,
 	uint32_t param_type)
 {
 	struct param_hdr_v3 param_info;
@@ -1822,7 +2005,7 @@ int q6lsm_set_one_param(struct lsm_client *client,
 	switch (param_type) {
 	case LSM_ENDPOINT_DETECT_THRESHOLD: {
 		param_info.module_id = p_info->module_id;
-		param_info.instance_id = INSTANCE_ID_0;
+		param_info.instance_id = p_info->instance_id;
 		param_info.param_id = p_info->param_id;
 		rc = q6lsm_send_param_epd_thres(client, data, &param_info);
 		if (rc)
@@ -1847,7 +2030,7 @@ int q6lsm_set_one_param(struct lsm_client *client,
 		client->mode |= det_mode->detect_failure << 2;
 
 		param_info.module_id = p_info->module_id;
-		param_info.instance_id = INSTANCE_ID_0;
+		param_info.instance_id = p_info->instance_id;
 		param_info.param_id = p_info->param_id;
 
 		rc = q6lsm_send_param_opmode(client, &param_info,
@@ -1861,7 +2044,7 @@ int q6lsm_set_one_param(struct lsm_client *client,
 	case LSM_GAIN: {
 		struct snd_lsm_gain *lsm_gain = (struct snd_lsm_gain *) data;
 		param_info.module_id = p_info->module_id;
-		param_info.instance_id = INSTANCE_ID_0;
+		param_info.instance_id = p_info->instance_id;
 		param_info.param_id = p_info->param_id;
 		rc = q6lsm_send_param_gain(client, lsm_gain->gain, &param_info);
 		if (rc)
@@ -1872,7 +2055,7 @@ int q6lsm_set_one_param(struct lsm_client *client,
 
 	case LSM_MIN_CONFIDENCE_LEVELS:
 		param_info.module_id = p_info->module_id;
-		param_info.instance_id = INSTANCE_ID_0;
+		param_info.instance_id = p_info->instance_id;
 		param_info.param_id = p_info->param_id;
 		rc = q6lsm_send_confidence_levels(
 			client, &param_info, LSM_SESSION_CMD_SET_PARAMS_V2);
@@ -1884,7 +2067,7 @@ int q6lsm_set_one_param(struct lsm_client *client,
 		struct snd_lsm_poll_enable *lsm_poll_enable =
 				(struct snd_lsm_poll_enable *) data;
 		param_info.module_id = p_info->module_id;
-		param_info.instance_id = INSTANCE_ID_0;
+		param_info.instance_id = p_info->instance_id;
 		param_info.param_id = p_info->param_id;
 		rc = q6lsm_send_param_polling_enable(
 			client, lsm_poll_enable->poll_en, &param_info,
@@ -1898,6 +2081,7 @@ int q6lsm_set_one_param(struct lsm_client *client,
 	case LSM_REG_SND_MODEL: {
 		struct mem_mapping_hdr mem_hdr;
 		u32 payload_size;
+		struct lsm_sound_model *sm = NULL;
 
 		memset(&mem_hdr, 0, sizeof(mem_hdr));
 
@@ -1908,12 +2092,14 @@ int q6lsm_set_one_param(struct lsm_client *client,
 			payload_size = p_info->param_size +
 				       sizeof(struct param_hdr_v2);
 
+		sm = &client->stage_cfg[p_info->stage_idx].sound_model;
+
 		mem_hdr.data_payload_addr_lsw =
-			lower_32_bits(client->sound_model.phys);
+			lower_32_bits(sm->phys);
 		mem_hdr.data_payload_addr_msw =
 			msm_audio_populate_upper_32_bits(
-				client->sound_model.phys),
-		mem_hdr.mem_map_handle = client->sound_model.mem_map_handle;
+				sm->phys),
+		mem_hdr.mem_map_handle = sm->mem_map_handle;
 
 		rc = q6lsm_set_params(client, &mem_hdr, NULL, payload_size,
 				      LSM_SESSION_CMD_SET_PARAMS_V2);
@@ -1923,7 +2109,7 @@ int q6lsm_set_one_param(struct lsm_client *client,
 			return rc;
 		}
 
-		rc = q6lsm_send_cal(client, LSM_SESSION_CMD_SET_PARAMS);
+		rc = q6lsm_send_cal(client, LSM_SESSION_CMD_SET_PARAMS, p_info);
 		if (rc)
 			pr_err("%s: Failed to send lsm cal, err = %d\n",
 				__func__, rc);
@@ -1932,7 +2118,7 @@ int q6lsm_set_one_param(struct lsm_client *client,
 
 	case LSM_DEREG_SND_MODEL: {
 		param_info.module_id = p_info->module_id;
-		param_info.instance_id = INSTANCE_ID_0;
+		param_info.instance_id = p_info->instance_id;
 		param_info.param_id = p_info->param_id;
 		param_info.param_size = 0;
 		rc = q6lsm_pack_and_set_params(client, &param_info, NULL,
@@ -1967,7 +2153,7 @@ int q6lsm_set_one_param(struct lsm_client *client,
 					(struct snd_lsm_det_event_type *)data;
 
 		param_info.module_id = p_info->module_id;
-		param_info.instance_id = INSTANCE_ID_0;
+		param_info.instance_id = p_info->instance_id;
 		param_info.param_id = p_info->param_id;
 		param_info.param_size = sizeof(det_event_type);
 
@@ -2044,10 +2230,12 @@ EXPORT_SYMBOL(q6lsm_close);
  *
  * @client: LSM client handle
  * @enable: bool flag  to enable or disable LAB on DSP
+ * @p_info: param info to be used for sending lab control param
  *
  * Returns 0 on success or error on failure
  */
-int q6lsm_lab_control(struct lsm_client *client, u32 enable)
+int q6lsm_lab_control(struct lsm_client *client, u32 enable,
+		struct lsm_params_info_v2 *p_info)
 {
 	struct lsm_param_lab_enable lab_enable;
 	struct param_hdr_v3 lab_enable_hdr;
@@ -2066,8 +2254,8 @@ int q6lsm_lab_control(struct lsm_client *client, u32 enable)
 	}
 
 	/* enable/disable lab on dsp */
-	lab_enable_hdr.module_id = LSM_MODULE_ID_LAB;
-	lab_enable_hdr.instance_id = INSTANCE_ID_0;
+	lab_enable_hdr.module_id = p_info->module_id;
+	lab_enable_hdr.instance_id = p_info->instance_id;
 	lab_enable_hdr.param_id = LSM_PARAM_ID_LAB_ENABLE;
 	lab_enable_hdr.param_size = sizeof(lab_enable);
 	lab_enable.enable = (enable) ? 1 : 0;
@@ -2082,8 +2270,8 @@ int q6lsm_lab_control(struct lsm_client *client, u32 enable)
 		goto exit;
 
 	/* lab session is being enabled set the config values */
-	lab_config_hdr.module_id = LSM_MODULE_ID_LAB;
-	lab_config_hdr.instance_id = INSTANCE_ID_0;
+	lab_config_hdr.module_id = p_info->module_id;
+	lab_config_hdr.instance_id = p_info->instance_id;
 	lab_config_hdr.param_id = LSM_PARAM_ID_LAB_CONFIG;
 	lab_config_hdr.param_size = sizeof(lab_config);
 	lab_config.minor_version = 1;
@@ -2114,11 +2302,12 @@ EXPORT_SYMBOL(q6lsm_lab_control);
  * @client: LSM client handle
  * @ch_map: Channel map indicating the order
  *	    of channels to be configured.
+ * @p_info: param info to be used for sending lab config param
  *
  * Returns 0 on success or error on failure
  */
 int q6lsm_lab_out_ch_cfg(struct lsm_client *client,
-			 u8 *ch_map)
+			 u8 *ch_map, struct lsm_params_info_v2 *p_info)
 {
 	u8 *param_buf;
 	struct lsm_param_lab_out_ch_cfg *lab_out_cfg;
@@ -2144,8 +2333,8 @@ int q6lsm_lab_out_ch_cfg(struct lsm_client *client,
 		lab_out_cfg->channel_indices[i] = ch_map[i];
 
 	memset(&lab_out_cfg_hdr, 0, sizeof(lab_out_cfg_hdr));
-	lab_out_cfg_hdr.module_id = LSM_MODULE_ID_LAB;
-	lab_out_cfg_hdr.instance_id = INSTANCE_ID_0;
+	lab_out_cfg_hdr.module_id = p_info->module_id;
+	lab_out_cfg_hdr.instance_id = p_info->instance_id;
 	lab_out_cfg_hdr.param_id = LSM_PARAM_ID_LAB_OUTPUT_CHANNEL_CONFIG;
 	lab_out_cfg_hdr.param_size = param_len;
 

+ 1 - 0
include/dsp/apr_audio-v2.h

@@ -9949,6 +9949,7 @@ struct avcs_fwk_ver_info {
 #define LSM_SESSION_CMD_EOB				(0x00012A89)
 #define LSM_SESSION_CMD_READ				(0x00012A8A)
 #define LSM_SESSION_CMD_OPEN_TX_V2			(0x00012A8B)
+#define LSM_SESSION_CMD_OPEN_TX_V3			(0x00012A95)
 #define LSM_CMD_ADD_TOPOLOGIES				(0x00012A8C)
 
 #define LSM_SESSION_EVENT_DETECTION_STATUS		(0x00012B00)

+ 43 - 9
include/dsp/q6lsm.h

@@ -26,6 +26,8 @@
 #define LSM_MAX_NUM_CHANNELS 8
 #define LSM_V3P0_MAX_NUM_CHANNELS 9
 
+#define LSM_API_VERSION_V3 3
+
 typedef void (*lsm_app_cb)(uint32_t opcode, uint32_t token,
 		       uint32_t *payload, void *priv);
 
@@ -60,6 +62,24 @@ struct lsm_hw_params {
 	u16 num_chs;
 };
 
+struct lsm_cal_data_info {
+	dma_addr_t	phys;
+	void	*data;
+	size_t	size;
+	struct dma_buf	*dma_buf;
+	uint32_t	mem_map_handle;
+};
+
+struct lsm_stage_config {
+	uint32_t	app_type;
+	uint32_t	topology_id;
+	bool	lpi_enable;
+	bool	lab_enable;
+	struct lsm_sound_model	sound_model;
+	struct lsm_cal_data_info	cal_info;
+};
+
+
 struct lsm_client {
 	int		session;
 	lsm_app_cb	cb;
@@ -68,7 +88,6 @@ struct lsm_client {
 	struct apr_svc  *apr;
 	struct apr_svc  *mmap_apr;
 	struct mutex    cmd_lock;
-	struct lsm_sound_model sound_model;
 	wait_queue_head_t cmd_wait;
 	uint32_t	cmd_err_code;
 	uint16_t	mode;
@@ -77,8 +96,6 @@ struct lsm_client {
 	uint8_t		*confidence_levels;
 	bool		opened;
 	bool		started;
-	dma_addr_t	lsm_cal_phy_addr;
-	uint32_t	lsm_cal_size;
 	uint32_t	app_id;
 	bool		lab_enable;
 	bool		lab_started;
@@ -91,6 +108,8 @@ struct lsm_client {
 	int		perf_mode;
 	uint32_t	event_mode;
 	uint32_t	event_type;
+	uint32_t	num_stages;
+	struct lsm_stage_config	stage_cfg[LSM_MAX_STAGES_PER_SESSION];
 };
 
 struct lsm_stream_cmd_open_tx {
@@ -105,6 +124,17 @@ struct lsm_stream_cmd_open_tx_v2 {
 	uint32_t	topology_id;
 } __packed;
 
+struct lsm_stream_stage_info {
+	uint32_t	topology_id;
+	uint32_t	island_enable;
+} __packed;
+
+struct lsm_stream_cmd_open_tx_v3 {
+	struct apr_hdr	hdr;
+	uint32_t	num_stages;
+	struct lsm_stream_stage_info	stage_info[0];
+} __packed;
+
 struct lsm_custom_topologies {
 	struct apr_hdr hdr;
 	uint32_t data_payload_addr_lsw;
@@ -242,8 +272,9 @@ int q6lsm_open(struct lsm_client *client, uint16_t app_id);
 int q6lsm_start(struct lsm_client *client, bool wait);
 int q6lsm_stop(struct lsm_client *client, bool wait);
 int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len,
-			      bool allocate_module_data);
-int q6lsm_snd_model_buf_free(struct lsm_client *client);
+			struct lsm_params_info_v2 *p_info);
+int q6lsm_snd_model_buf_free(struct lsm_client *client,
+			struct lsm_params_info_v2 *p_info);
 int q6lsm_close(struct lsm_client *client);
 int q6lsm_register_sound_model(struct lsm_client *client,
 			       enum lsm_detection_mode mode,
@@ -254,19 +285,22 @@ int q6lsm_set_data(struct lsm_client *client,
 int q6lsm_deregister_sound_model(struct lsm_client *client);
 void set_lsm_port(int lsm_port);
 int get_lsm_port(void);
-int q6lsm_lab_control(struct lsm_client *client, u32 enable);
+int q6lsm_lab_control(struct lsm_client *client, u32 enable,
+		struct lsm_params_info_v2 *p_info);
 int q6lsm_stop_lab(struct lsm_client *client);
 int q6lsm_read(struct lsm_client *client, struct lsm_cmd_read *read);
 int q6lsm_lab_buffer_alloc(struct lsm_client *client, bool alloc);
 int q6lsm_set_one_param(struct lsm_client *client,
-			struct lsm_params_info *p_info, void *data,
+			struct lsm_params_info_v2 *p_info, void *data,
 			uint32_t param_type);
 void q6lsm_sm_set_param_data(struct lsm_client *client,
-		struct lsm_params_info *p_info,
+		struct lsm_params_info_v2 *p_info,
 		size_t *offset);
 int q6lsm_set_port_connected(struct lsm_client *client);
 int q6lsm_set_fwk_mode_cfg(struct lsm_client *client, uint32_t event_mode);
 int q6lsm_set_media_fmt_params(struct lsm_client *client);
 int q6lsm_set_media_fmt_v2_params(struct lsm_client *client);
-int q6lsm_lab_out_ch_cfg(struct lsm_client *client, u8 *ch_map);
+int q6lsm_lab_out_ch_cfg(struct lsm_client *client, u8 *ch_map,
+		struct lsm_params_info_v2 *p_info);
+bool q6lsm_adsp_supports_multi_stage_detection(void);
 #endif /* __Q6LSM_H__ */