From ce6ec5fcf269c6b13c5619bac186e13a9eebd0fb Mon Sep 17 00:00:00 2001 From: Dhananjay Kumar Date: Tue, 19 Jun 2018 06:07:29 +0530 Subject: [PATCH] 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 --- asoc/msm-lsm-client.c | 565 ++++++++++++++++++++++++------------- dsp/q6lsm.c | 511 ++++++++++++++++++++++----------- include/dsp/apr_audio-v2.h | 1 + include/dsp/q6lsm.h | 52 +++- 4 files changed, 761 insertions(+), 368 deletions(-) diff --git a/asoc/msm-lsm-client.c b/asoc/msm-lsm-client.c index 3ecafbccec..e0eeef3c49 100644 --- a/asoc/msm-lsm-client.c +++ b/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); + 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; + } - 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; - } - - 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; - p_info_32++; - p_info++; + 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.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; } diff --git a/dsp/q6lsm.c b/dsp/q6lsm.c index 4e0f7247f5..8146b65d95 100644 --- a/dsp/q6lsm.c +++ b/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(¶m_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, ¶m_hdr, + ret = q6lsm_pack_params(sm->data, ¶m_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(¶m_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]); - - if (!cal_block || cal_block->cal_data.size <= 0) { - pr_debug("%s: No cal to send!\n", __func__); - goto unlock; + 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_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 (!cal_block_found) { + pr_info("%s: cal not found 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: + if (!len) { + pr_debug("%s: cal size is 0, for stage_idx %d\n", __func__, stage_idx); + goto exit; + } + + 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; + pr_debug("%s:Snd Model len = %zd, stage idx %d\n", + __func__, len, 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]); - 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) { - + 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); - mutex_unlock(&client->cmd_lock); - rc = q6lsm_memory_map_regions(client, client->sound_model.phys, - len, - &client->sound_model.mem_map_handle); + rc = q6lsm_memory_map_regions(client, sm->phys, len, &sm->mem_map_handle); if (rc) { - pr_err("%s: CMD Memory_map_regions failed %d\n", __func__, rc); - goto exit; + pr_err("%s: CMD Memory_map_regions failed %d, stage_idx %d\n", + __func__, rc, stage_idx); + sm->mem_map_handle = 0; + goto fail; } - - 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); + + rc = q6lsm_snd_cal_alloc(client, p_info); + if (rc) { + pr_err("%s: cal alloc failed %d, stage_idx %d\n", + __func__, rc, stage_idx); + goto fail_1; + } + return rc; + +fail: + mutex_unlock(&client->cmd_lock); +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, ¶m_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, ¶m_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, ¶m_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, ¶m_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, ¶m_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, ¶m_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; diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h index 49ad902894..535f09f1d3 100644 --- a/include/dsp/apr_audio-v2.h +++ b/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) diff --git a/include/dsp/q6lsm.h b/include/dsp/q6lsm.h index 740fba4e89..5670d776c5 100644 --- a/include/dsp/q6lsm.h +++ b/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__ */