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 <dhakumar@codeaurora.org>
This commit is contained in:
Dhananjay Kumar
2018-06-19 06:07:29 +05:30
parent a6a600898a
commit ce6ec5fcf2
4 changed files with 761 additions and 368 deletions

View File

@@ -42,6 +42,9 @@
#define LAB_BUFFER_ALLOC 1 #define LAB_BUFFER_ALLOC 1
#define LAB_BUFFER_DEALLOC 0 #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 = { static struct snd_pcm_hardware msm_pcm_hardware_capture = {
.info = (SNDRV_PCM_INFO_MMAP | .info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -463,7 +466,7 @@ done:
} }
static int msm_lsm_set_epd(struct snd_pcm_substream *substream, 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 snd_pcm_runtime *runtime = substream->runtime;
struct lsm_priv *prtd = runtime->private_data; struct lsm_priv *prtd = runtime->private_data;
@@ -499,7 +502,7 @@ done:
} }
static int msm_lsm_set_mode(struct snd_pcm_substream *substream, 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 snd_pcm_runtime *runtime = substream->runtime;
struct lsm_priv *prtd = runtime->private_data; struct lsm_priv *prtd = runtime->private_data;
@@ -535,7 +538,7 @@ done:
} }
static int msm_lsm_set_gain(struct snd_pcm_substream *substream, 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 snd_pcm_runtime *runtime = substream->runtime;
struct lsm_priv *prtd = runtime->private_data; struct lsm_priv *prtd = runtime->private_data;
@@ -571,7 +574,7 @@ done:
} }
static int msm_lsm_set_conf(struct snd_pcm_substream *substream, 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 snd_pcm_runtime *runtime = substream->runtime;
struct lsm_priv *prtd = runtime->private_data; 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, 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 snd_pcm_runtime *runtime = substream->runtime;
struct lsm_priv *prtd = runtime->private_data; struct lsm_priv *prtd = runtime->private_data;
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
int rc = 0; int rc = 0;
u8 *snd_model_ptr; struct lsm_sound_model *sm = NULL;
size_t offset; size_t offset = sizeof(union param_hdrs);
rc = q6lsm_snd_model_buf_alloc(prtd->lsm_client, rc = q6lsm_snd_model_buf_alloc(prtd->lsm_client,
p_info->param_size, p_info->param_size, p_info);
true);
if (rc) { if (rc) {
dev_err(rtd->dev, dev_err(rtd->dev,
"%s: snd_model buf alloc failed, size = %d\n", "%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 * For set_param, advance the sound model data with the
* number of bytes required by param_data. * 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)) { p_info->param_data, p_info->param_size)) {
dev_err(rtd->dev, dev_err(rtd->dev,
"%s: copy_from_user for snd_model failed, size = %d\n", "%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; return rc;
err_copy: err_copy:
q6lsm_snd_model_buf_free(prtd->lsm_client); q6lsm_snd_model_buf_free(prtd->lsm_client, p_info);
return rc; return rc;
} }
static int msm_lsm_dereg_model(struct snd_pcm_substream *substream, 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 snd_pcm_runtime *runtime = substream->runtime;
struct lsm_priv *prtd = runtime->private_data; 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", "%s: Failed to set det_mode param, err = %d\n",
__func__, rc); __func__, rc);
q6lsm_snd_model_buf_free(prtd->lsm_client); q6lsm_snd_model_buf_free(prtd->lsm_client, p_info);
return rc; return rc;
} }
static int msm_lsm_set_custom(struct snd_pcm_substream *substream, 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 snd_pcm_runtime *runtime = substream->runtime;
struct lsm_priv *prtd = runtime->private_data; struct lsm_priv *prtd = runtime->private_data;
@@ -712,8 +714,96 @@ err_ret:
return rc; 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, 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 snd_pcm_runtime *runtime = substream->runtime;
struct lsm_priv *prtd = runtime->private_data; 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, 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_lsm_det_event_type det_event_type;
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
@@ -801,65 +891,68 @@ done:
} }
static int msm_lsm_process_params(struct snd_pcm_substream *substream, static int msm_lsm_process_params(struct snd_pcm_substream *substream,
struct snd_lsm_module_params *p_data, struct lsm_params_info_v2 *p_info)
void *params)
{ {
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_soc_pcm_runtime *rtd = substream->private_data;
struct lsm_params_info *p_info;
int i;
int rc = 0; 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++) { if (!prtd->lsm_client ||
dev_dbg(rtd->dev, prtd->lsm_client->num_stages <= p_info->stage_idx) {
"%s: param (%d), module_id = 0x%x, param_id = 0x%x, param_size = 0x%x, param_type = 0x%x\n", dev_err(rtd->dev,
__func__, i, p_info->module_id, "%s: invalid stage_idx(%d) for client(%p) having num_stages(%d)\n",
p_info->param_id, p_info->param_size, __func__, p_info->stage_idx, prtd->lsm_client,
p_info->param_type); prtd->lsm_client ? prtd->lsm_client->num_stages : 0);
return -EINVAL;
}
switch (p_info->param_type) { switch (p_info->param_type) {
case LSM_ENDPOINT_DETECT_THRESHOLD: case LSM_ENDPOINT_DETECT_THRESHOLD:
rc = msm_lsm_set_epd(substream, p_info); rc = msm_lsm_set_epd(substream, p_info);
break; break;
case LSM_OPERATION_MODE: case LSM_OPERATION_MODE:
rc = msm_lsm_set_mode(substream, p_info); rc = msm_lsm_set_mode(substream, p_info);
break; break;
case LSM_GAIN: case LSM_GAIN:
rc = msm_lsm_set_gain(substream, p_info); rc = msm_lsm_set_gain(substream, p_info);
break; break;
case LSM_MIN_CONFIDENCE_LEVELS: case LSM_MIN_CONFIDENCE_LEVELS:
rc = msm_lsm_set_conf(substream, p_info); rc = msm_lsm_set_conf(substream, p_info);
break; break;
case LSM_REG_SND_MODEL: case LSM_REG_SND_MODEL:
rc = msm_lsm_reg_model(substream, p_info); rc = msm_lsm_reg_model(substream, p_info);
break; break;
case LSM_DEREG_SND_MODEL: case LSM_DEREG_SND_MODEL:
rc = msm_lsm_dereg_model(substream, p_info); rc = msm_lsm_dereg_model(substream, p_info);
break; break;
case LSM_CUSTOM_PARAMS: case LSM_CUSTOM_PARAMS:
rc = msm_lsm_set_custom(substream, p_info); rc = msm_lsm_set_custom(substream, p_info);
break; break;
case LSM_POLLING_ENABLE: case LSM_POLLING_ENABLE:
rc = msm_lsm_set_poll_enable(substream, p_info); rc = msm_lsm_set_poll_enable(substream, p_info);
break; break;
case LSM_DET_EVENT_TYPE: case LSM_DET_EVENT_TYPE:
rc = msm_lsm_set_det_event_type(substream, p_info); rc = msm_lsm_set_det_event_type(substream, p_info);
break; break;
default: case LSM_LAB_CONTROL:
dev_err(rtd->dev, rc = msm_lsm_set_lab_control(substream, p_info);
"%s: Invalid param_type %d\n", break;
__func__, p_info->param_type); default:
rc = -EINVAL; dev_err(rtd->dev,
break; "%s: Invalid param_type %d\n",
} __func__, p_info->param_type);
if (rc) { rc = -EINVAL;
pr_err("%s: set_param fail for param_type %d\n", break;
__func__, p_info->param_type); }
return rc; if (rc) {
} pr_err("%s: set_param fail for param_type %d\n",
__func__, p_info->param_type);
p_info++;
} }
return rc; return rc;
@@ -897,12 +990,14 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
int ret; int ret;
struct snd_lsm_sound_model_v2 snd_model_v2; struct snd_lsm_sound_model_v2 snd_model_v2;
struct snd_lsm_session_data session_data; 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; int xchg = 0;
struct snd_pcm_runtime *runtime; struct snd_pcm_runtime *runtime;
struct lsm_priv *prtd; struct lsm_priv *prtd;
struct snd_lsm_detection_params det_params; struct snd_lsm_detection_params det_params;
uint8_t *confidence_level = NULL; uint8_t *confidence_level = NULL;
uint32_t max_detection_stages_supported = LSM_MAX_STAGES_PER_SESSION;
if (!substream || !substream->private_data) { if (!substream || !substream->private_data) {
pr_err("%s: Invalid %s\n", __func__, pr_err("%s: Invalid %s\n", __func__,
@@ -916,15 +1011,26 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
switch (cmd) { switch (cmd) {
case SNDRV_LSM_SET_SESSION_DATA: case SNDRV_LSM_SET_SESSION_DATA:
dev_dbg(rtd->dev, "%s: set session data\n", __func__); case SNDRV_LSM_SET_SESSION_DATA_V2:
if (copy_from_user(&session_data, arg,
sizeof(session_data))) { 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", dev_err(rtd->dev, "%s: %s: copy_from_user failed\n",
__func__, "LSM_SET_SESSION_DATA"); __func__, "LSM_SET_SESSION_DATA(_V2)");
return -EFAULT; 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, dev_err(rtd->dev,
"%s:Invalid App id %d for Listen client\n", "%s:Invalid App id %d for Listen client\n",
__func__, session_data.app_id); __func__, session_data.app_id);
@@ -932,9 +1038,38 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
break; break;
} }
prtd->lsm_client->app_id = session_data.app_id; /*
ret = q6lsm_open(prtd->lsm_client, * Before validating num_stages from user argument.
prtd->lsm_client->app_id); * 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) { if (ret < 0) {
dev_err(rtd->dev, dev_err(rtd->dev,
"%s: lsm open failed, %d\n", "%s: lsm open failed, %d\n",
@@ -942,12 +1077,24 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
return ret; return ret;
} }
prtd->lsm_client->opened = true; 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__, __func__,
prtd->lsm_client->session, prtd->lsm_client->session,
prtd->lsm_client->app_id); prtd->lsm_client->app_id,
prtd->lsm_client->num_stages);
break; 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", dev_dbg(rtd->dev, "%s: Registering sound model V2\n",
__func__); __func__);
memcpy(&snd_model_v2, arg, memcpy(&snd_model_v2, arg,
@@ -962,20 +1109,21 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
break; break;
} }
rc = q6lsm_snd_model_buf_alloc(prtd->lsm_client, rc = q6lsm_snd_model_buf_alloc(prtd->lsm_client,
snd_model_v2.data_size, false); snd_model_v2.data_size, &p_info);
if (rc) { if (rc) {
dev_err(rtd->dev, dev_err(rtd->dev,
"%s: q6lsm buffer alloc failed V2, size %d\n", "%s: q6lsm buffer alloc failed V2, size %d\n",
__func__, snd_model_v2.data_size); __func__, snd_model_v2.data_size);
break; break;
} }
if (copy_from_user(prtd->lsm_client->sound_model.data, if (copy_from_user(
snd_model_v2.data, snd_model_v2.data_size)) { prtd->lsm_client->stage_cfg[stage_idx].sound_model.data,
snd_model_v2.data, snd_model_v2.data_size)) {
dev_err(rtd->dev, dev_err(rtd->dev,
"%s: copy from user data failed\n" "%s: copy from user data failed\n"
"data %pK size %d\n", __func__, "data %pK size %d\n", __func__,
snd_model_v2.data, snd_model_v2.data_size); 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; rc = -EFAULT;
break; break;
} }
@@ -1004,13 +1152,13 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
"%s: Register snd Model v2 failed =%d\n", "%s: Register snd Model v2 failed =%d\n",
__func__, rc); __func__, rc);
kfree(confidence_level); 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); kfree(prtd->lsm_client->confidence_levels);
prtd->lsm_client->confidence_levels = NULL; prtd->lsm_client->confidence_levels = NULL;
break; break;
}
case SNDRV_LSM_SET_PARAMS: case SNDRV_LSM_SET_PARAMS:
dev_dbg(rtd->dev, "%s: set_params\n", __func__); dev_dbg(rtd->dev, "%s: set_params\n", __func__);
memcpy(&det_params, arg, memcpy(&det_params, arg,
@@ -1260,10 +1408,14 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
break; break;
} }
case SNDRV_LSM_LAB_CONTROL: { case SNDRV_LSM_LAB_CONTROL: {
struct lsm_hw_params *out_hw_params = u32 enable = 0;
&prtd->lsm_client->out_hw_params; struct lsm_params_info_v2 p_info = {0};
u8 chmap[out_hw_params->num_chs];
u32 enable, ch_idx; 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))) { if (copy_from_user(&enable, arg, sizeof(enable))) {
dev_err(rtd->dev, "%s: %s: copy_frm_user failed\n", 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; 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 * With multi-stage support lab control needs to set param info
* best channel (0xff). For second channel onwards, * specifying stage index for which this lab control is issued,
* the channel indices are 0, 1, .. etc * 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; p_info.param_type = LSM_LAB_CONTROL;
for (ch_idx = 1; ch_idx < out_hw_params->num_chs; ch_idx++) p_info.module_id = LSM_MODULE_ID_LAB;
chmap[ch_idx] = ch_idx - 1; p_info.instance_id = INSTANCE_ID_0;
p_info.stage_idx = LSM_STAGE_INDEX_FIRST;
rc = q6lsm_lab_out_ch_cfg(prtd->lsm_client, chmap); p_info.param_size = 0;
if (rc) rc = msm_lsm_check_and_set_lab_controls(substream, enable, &p_info);
dev_err(rtd->dev,
"%s: Failed to set lab out ch cfg %d\n",
__func__, rc);
break; break;
} }
case SNDRV_LSM_STOP_LAB: case SNDRV_LSM_STOP_LAB:
@@ -1476,6 +1594,16 @@ struct lsm_params_info_32 {
uint32_t param_type; 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 { struct snd_lsm_module_params_32 {
compat_uptr_t params; compat_uptr_t params;
u32 num_params; u32 num_params;
@@ -1491,6 +1619,8 @@ enum {
_IOW('U', 0x0B, struct snd_lsm_module_params_32), _IOW('U', 0x0B, struct snd_lsm_module_params_32),
SNDRV_LSM_EVENT_STATUS_V3_32 = SNDRV_LSM_EVENT_STATUS_V3_32 =
_IOW('U', 0x0F, struct snd_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, 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; 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_32 p_data_32;
struct snd_lsm_module_params p_data; struct snd_lsm_module_params p_data;
u8 *params, *params32; u8 *params32;
size_t p_size; size_t expected_size = 0, count;
struct lsm_params_info_32 *p_info_32; struct lsm_params_info_32 *p_info_32 = NULL;
struct lsm_params_info *p_info; struct lsm_params_info_v2_32 *p_info_v2_32 = NULL;
int i; struct lsm_params_info_v2 p_info;
if (!prtd->lsm_client->use_topology) { if (!prtd->lsm_client->use_topology) {
dev_err(rtd->dev, dev_err(rtd->dev,
"%s: %s: not supported if not using topology\n", "%s: %s: not supported if not using topology\n",
__func__, "SET_MODULE_PARAMS_32"); __func__, "SET_MODULE_PARAMS(_V2)_32");
err = -EINVAL; err = -EINVAL;
goto done; goto done;
} }
@@ -1781,7 +1912,7 @@ static int msm_lsm_ioctl_compat(struct snd_pcm_substream *substream,
sizeof(p_data_32))) { sizeof(p_data_32))) {
dev_err(rtd->dev, dev_err(rtd->dev,
"%s: %s: copy_from_user failed, size = %zd\n", "%s: %s: copy_from_user failed, size = %zd\n",
__func__, "SET_MODULE_PARAMS_32", __func__, "SET_MODULE_PARAMS(_V2)_32",
sizeof(p_data_32)); sizeof(p_data_32));
err = -EFAULT; err = -EFAULT;
goto done; 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) { if (p_data.num_params > LSM_PARAMS_MAX) {
dev_err(rtd->dev, dev_err(rtd->dev,
"%s: %s: Invalid num_params %d\n", "%s: %s: Invalid num_params %d\n",
__func__, "SET_MODULE_PARAMS_32", __func__, "SET_MODULE_PARAMS(_V2)_32",
p_data.num_params); p_data.num_params);
err = -EINVAL; err = -EINVAL;
goto done; goto done;
} }
if (p_data.data_size != 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_32) :
p_data.num_params * sizeof(struct lsm_params_info_v2_32);
if (p_data.data_size != expected_size) {
dev_err(rtd->dev, dev_err(rtd->dev,
"%s: %s: Invalid size %d\n", "%s: %s: Invalid size %d\n",
__func__, "SET_MODULE_PARAMS_32", __func__, "SET_MODULE_PARAMS(_V2)_32",
p_data.data_size); p_data.data_size);
err = -EINVAL; err = -EINVAL;
goto done; goto done;
} }
p_size = sizeof(struct lsm_params_info_32) * params32 = kzalloc(p_data.data_size, GFP_KERNEL);
p_data.num_params;
params32 = kzalloc(p_size, GFP_KERNEL);
if (!params32) { if (!params32) {
err = -ENOMEM; err = -ENOMEM;
goto done; 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, if (copy_from_user(params32, p_data.params,
p_data.data_size)) { p_data.data_size)) {
dev_err(rtd->dev, dev_err(rtd->dev,
"%s: %s: copy_from_user failed, size = %d\n", "%s: %s: copy_from_user failed, size = %d\n",
__func__, "params32", p_data.data_size); __func__, "params32", p_data.data_size);
kfree(params32); kfree(params32);
kfree(params);
err = -EFAULT; err = -EFAULT;
goto done; goto done;
} }
p_info_32 = (struct lsm_params_info_32 *) params32; if (cmd == SNDRV_LSM_SET_MODULE_PARAMS_32)
p_info = (struct lsm_params_info *) params; p_info_32 = (struct lsm_params_info_32 *) params32;
for (i = 0; i < p_data.num_params; i++) { else
p_info->module_id = p_info_32->module_id; p_info_v2_32 = (struct lsm_params_info_v2_32 *) params32;
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++; for (count = 0; count < p_data.num_params; count++) {
p_info++; 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); kfree(params32);
break; break;
} }
case SNDRV_LSM_REG_SND_MODEL_V2: case SNDRV_LSM_REG_SND_MODEL_V2:
case SNDRV_LSM_SET_PARAMS: case SNDRV_LSM_SET_PARAMS:
case SNDRV_LSM_SET_MODULE_PARAMS: case SNDRV_LSM_SET_MODULE_PARAMS:
case SNDRV_LSM_SET_MODULE_PARAMS_V2:
/* /*
* In ideal cases, the compat_ioctl should never be called * In ideal cases, the compat_ioctl should never be called
* with the above unlocked ioctl commands. Print error * with the above unlocked ioctl commands. Print error
@@ -1970,15 +2107,19 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
goto done; 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; 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; u8 *params;
if (!prtd->lsm_client->use_topology) { if (!prtd->lsm_client->use_topology) {
dev_err(rtd->dev, dev_err(rtd->dev,
"%s: %s: not supported if not using topology\n", "%s: %s: not supported if not using topology\n",
__func__, "SET_MODULE_PARAMS"); __func__, "SET_MODULE_PARAMS(_V2)");
err = -EINVAL; err = -EINVAL;
goto done; goto done;
} }
@@ -1995,20 +2136,22 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
if (p_data.num_params > LSM_PARAMS_MAX) { if (p_data.num_params > LSM_PARAMS_MAX) {
dev_err(rtd->dev, dev_err(rtd->dev,
"%s: %s: Invalid num_params %d\n", "%s: %s: Invalid num_params %d\n",
__func__, "SET_MODULE_PARAMS", __func__, "SET_MODULE_PARAMS(_V2)",
p_data.num_params); p_data.num_params);
err = -EINVAL; err = -EINVAL;
goto done; goto done;
} }
p_size = p_data.num_params * if (cmd == SNDRV_LSM_SET_MODULE_PARAMS)
sizeof(struct lsm_params_info); 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) { if (p_data.data_size != p_size) {
dev_err(rtd->dev, dev_err(rtd->dev,
"%s: %s: Invalid size %zd\n", "%s: %s: Invalid data_size(%zd) against expected(%zd)\n",
__func__, "SET_MODULE_PARAMS", p_size); __func__, "SET_MODULE_PARAMS(_V2)",
p_data.data_size, p_size);
err = -EFAULT; err = -EFAULT;
goto done; goto done;
} }
@@ -2020,20 +2163,46 @@ static int msm_lsm_ioctl(struct snd_pcm_substream *substream,
} }
if (copy_from_user(params, p_data.params, if (copy_from_user(params, p_data.params,
p_data.data_size)) { p_data.data_size)) {
dev_err(rtd->dev, dev_err(rtd->dev,
"%s: %s: copy_from_user failed, size = %d\n", "%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); kfree(params);
err = -EFAULT; err = -EFAULT;
goto done; goto done;
} }
err = msm_lsm_process_params(substream, &p_data, params); if (cmd == SNDRV_LSM_SET_MODULE_PARAMS)
if (err) temp_ptr_info = (struct lsm_params_info *)params;
dev_err(rtd->dev, else
"%s: %s: Failed to set params, err = %d\n", temp_ptr_info_v2 = (struct lsm_params_info_v2 *)params;
__func__, "SET_MODULE_PARAMS", err);
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); kfree(params);
break; break;
} }

View File

@@ -87,7 +87,8 @@ static spinlock_t lsm_session_lock;
static struct lsm_client *lsm_session[LSM_MAX_SESSION_ID + 1]; 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_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, static int q6lsm_memory_map_regions(struct lsm_client *client,
dma_addr_t dma_addr_p, uint32_t dma_buf_sz, dma_addr_t dma_addr_p, uint32_t dma_buf_sz,
uint32_t *mmap_p); 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_EOB:
case LSM_SESSION_CMD_READ: case LSM_SESSION_CMD_READ:
case LSM_SESSION_CMD_OPEN_TX_V2: case LSM_SESSION_CMD_OPEN_TX_V2:
case LSM_SESSION_CMD_OPEN_TX_V3:
case LSM_CMD_ADD_TOPOLOGIES: case LSM_CMD_ADD_TOPOLOGIES:
case LSM_SESSION_CMD_SET_PARAMS_V2: case LSM_SESSION_CMD_SET_PARAMS_V2:
case LSM_SESSION_CMD_SET_PARAMS_V3: case LSM_SESSION_CMD_SET_PARAMS_V3:
@@ -689,6 +691,94 @@ done:
return rc; 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, static int q6lsm_do_open_v2(struct lsm_client *client,
uint16_t app_id) uint16_t app_id)
{ {
@@ -722,9 +812,8 @@ static int q6lsm_do_open_v2(struct lsm_client *client,
goto unlock; goto unlock;
} }
pr_debug("%s: topology_id = 0x%x, acdb_id = 0x%x, app_type = 0x%x\n", pr_debug("%s: topology_id = 0x%x, app_type = 0x%x\n",
__func__, lsm_top->topology, lsm_top->acdb_id, __func__, lsm_top->topology, lsm_top->app_type);
lsm_top->app_type);
if (lsm_top->topology == 0) { if (lsm_top->topology == 0) {
pr_err("%s: toplogy id not sent for app_type 0x%x\n", 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, 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) size_t *offset)
{ {
struct param_hdr_v3 param_hdr; 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)); memset(&param_hdr, 0, sizeof(param_hdr));
param_hdr.module_id = p_info->module_id; 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_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); NULL, offset, LSM_SESSION_CMD_SET_PARAMS_V2);
if (ret) if (ret)
pr_err("%s: Failed to pack params, error %d\n", __func__, ret); pr_err("%s: Failed to pack params, error %d\n", __func__, ret);
} }
EXPORT_SYMBOL(q6lsm_sm_set_param_data); 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 - * q6lsm_open -
* command to open LSM session * 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 */ /* 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) if (!rc)
/* open_v2 was successful */ /* open_v2/v3 was successful */
goto done; goto done;
pr_debug("%s: try without topology\n", 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; struct param_hdr_v3 param_hdr;
int rc = 0; int rc = 0;
struct lsm_params_info_v2 p_info = {0};
memset(&param_hdr, 0, sizeof(param_hdr)); memset(&param_hdr, 0, sizeof(param_hdr));
@@ -1228,7 +1337,8 @@ int q6lsm_set_data(struct lsm_client *client,
goto err_ret; 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) { if (rc) {
pr_err("%s: Failed to send calibration data %d\n", pr_err("%s: Failed to send calibration data %d\n",
__func__, rc); __func__, rc);
@@ -1254,6 +1364,7 @@ int q6lsm_register_sound_model(struct lsm_client *client,
{ {
int rc; int rc;
struct lsm_cmd_reg_snd_model cmd; struct lsm_cmd_reg_snd_model cmd;
struct lsm_sound_model *sm;
memset(&cmd, 0, sizeof(cmd)); memset(&cmd, 0, sizeof(cmd));
rc = q6lsm_set_data(client, mode, detectfailure); rc = q6lsm_set_data(client, mode, detectfailure);
@@ -1263,18 +1374,19 @@ int q6lsm_register_sound_model(struct lsm_client *client,
return rc; return rc;
} }
sm = &client->stage_cfg[LSM_STAGE_INDEX_FIRST].sound_model;
q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd), true); q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd), true);
cmd.hdr.opcode = LSM_SESSION_CMD_REGISTER_SOUND_MODEL; cmd.hdr.opcode = LSM_SESSION_CMD_REGISTER_SOUND_MODEL;
cmd.model_addr_lsw = lower_32_bits(client->sound_model.phys); cmd.model_addr_lsw = lower_32_bits(sm->phys);
cmd.model_addr_msw = msm_audio_populate_upper_32_bits( cmd.model_addr_msw = msm_audio_populate_upper_32_bits(sm->phys);
client->sound_model.phys); cmd.model_size = sm->size;
cmd.model_size = client->sound_model.size;
/* read updated mem_map_handle by q6lsm_mmapcallback */ /* read updated mem_map_handle by q6lsm_mmapcallback */
rmb(); 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__, 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); rc = q6lsm_apr_send_pkt(client, client->apr, &cmd, true, NULL);
if (rc) if (rc)
pr_err("%s: Failed cmd op[0x%x]rc[%d]\n", __func__, 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; int rc;
struct lsm_cmd_reg_snd_model cmd; 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) { if (!client) {
pr_err("APR handle NULL\n"); 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__); 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; 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, 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 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)); memset(&mem_hdr, 0, sizeof(mem_hdr));
@@ -1439,40 +1561,132 @@ static int q6lsm_send_cal(struct lsm_client *client,
return -EINVAL; return -EINVAL;
} }
if (lsm_common.cal_data[LSM_CAL_IDX] == NULL) lsm_cal_phy_addr = client->stage_cfg[stage_idx].cal_info.phys;
goto done; 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); mutex_lock(&lsm_common.cal_data[LSM_CAL_IDX]->lock);
cal_block = cal_utils_get_only_cal_block( list_for_each(ptr, &lsm_common.cal_data[LSM_CAL_IDX]->cal_blocks) {
lsm_common.cal_data[LSM_CAL_IDX]); cal_block = list_entry(ptr, struct cal_block_data, list);
lsm_cal_info = (struct audio_cal_info_lsm *)
if (!cal_block || cal_block->cal_data.size <= 0) { (cal_block) ? cal_block->cal_info : NULL;
pr_debug("%s: No cal to send!\n", __func__); if ((cal_block && cal_block->cal_data.paddr) &&
goto unlock; (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) { if (!cal_block_found) {
pr_err("%s: Cal size %zd doesn't match lsm cal size %d\n", pr_info("%s: cal not found for stage_idx %d\n", __func__, stage_idx);
__func__, cal_block->cal_data.size, goto exit;
client->lsm_cal_size);
rc = -EINVAL;
goto unlock;
} }
/* 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); if (!len) {
rc = q6lsm_set_params(client, &mem_hdr, NULL, cal_block->cal_data.size, pr_debug("%s: cal size is 0, for stage_idx %d\n", __func__, stage_idx);
set_params_opcode); goto exit;
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); 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; return rc;
} }
@@ -1481,12 +1695,15 @@ done:
* Free memory for LSM snd model * Free memory for LSM snd model
* *
* @client: LSM client handle * @client: LSM client handle
* @p_info: sound model param info
* *
* Returns 0 on success or error on failure * 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); pr_debug("%s: Session id %d\n", __func__, client->session);
if (CHECK_SESSION(client->session)) { if (CHECK_SESSION(client->session)) {
@@ -1494,22 +1711,25 @@ int q6lsm_snd_model_buf_free(struct lsm_client *client)
return -EINVAL; return -EINVAL;
} }
mutex_lock(&client->cmd_lock); if (!client->stage_cfg[stage_idx].sound_model.data)
rc = q6lsm_memory_unmap_regions(client, return 0;
client->sound_model.mem_map_handle);
if (rc)
pr_err("%s: CMD Memory_unmap_regions failed %d\n",
__func__, rc);
if (client->sound_model.data) { mutex_lock(&client->cmd_lock);
msm_audio_ion_free(client->sound_model.dma_buf); sm = &client->stage_cfg[stage_idx].sound_model;
client->sound_model.dma_buf = NULL; if (sm->mem_map_handle != 0) {
client->sound_model.data = NULL; rc = q6lsm_memory_unmap_regions(client, sm->mem_map_handle);
client->sound_model.phys = 0; if (rc)
client->lsm_cal_phy_addr = 0; pr_err("%s: CMD Memory_unmap_regions failed %d\n",
client->lsm_cal_size = 0; __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); mutex_unlock(&client->cmd_lock);
rc = q6lsm_snd_cal_free(client, p_info);
return rc; return rc;
} }
EXPORT_SYMBOL(q6lsm_snd_model_buf_free); 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); apr_reset(lsm_common.apr);
lsm_common.apr = NULL; lsm_common.apr = NULL;
atomic_set(&lsm_common.apr_users, 0); 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, cal_utils_clear_cal_block_q6maps(LSM_MAX_CAL_IDX,
lsm_common.cal_data); lsm_common.cal_data);
lsm_common.set_custom_topology = 1; 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 * @client: LSM client handle
* @len: size of sound model * @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 * Returns 0 on success or error on failure
*/ */
int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len, 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; int rc = -EINVAL, stage_idx = p_info->stage_idx;
struct cal_block_data *cal_block = NULL; size_t total_mem = 0;
struct lsm_sound_model *sm = NULL;
size_t pad_zero = 0, total_mem = 0;
if (!client || len <= LSM_ALIGN_BOUNDARY) if (!client || len <= LSM_ALIGN_BOUNDARY)
return rc; return rc;
pr_debug("%s:Snd Model len = %zd, stage idx %d\n",
__func__, len, stage_idx);
mutex_lock(&client->cmd_lock); mutex_lock(&client->cmd_lock);
sm = &client->stage_cfg[stage_idx].sound_model;
mutex_lock(&lsm_common.cal_data[LSM_CAL_IDX]->lock); if (!sm->data) {
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) {
/* /*
* 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 * Then memory needs to be allocated for
* set_param payload as well. * set_param payload as well.
*/ */
if (allocate_module_data) if (p_info->param_id != 0)
len += sizeof(union param_hdrs); len += sizeof(union param_hdrs);
client->sound_model.size = len; sm->size = len;
pad_zero = (LSM_ALIGN_BOUNDARY - total_mem = PAGE_ALIGN(len);
(len % LSM_ALIGN_BOUNDARY)); pr_debug("%s: sm param size %zd Total mem %zd, stage_idx %d\n",
if ((len > SIZE_MAX - pad_zero) || __func__, len, total_mem, stage_idx);
(len + pad_zero > rc = msm_audio_ion_alloc(&sm->dma_buf, total_mem,
SIZE_MAX - cal_block->cal_data.size)) { &sm->phys, &len, &sm->data);
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);
if (rc) { if (rc) {
pr_err("%s: Audio ION alloc is failed, rc = %d\n", pr_err("%s: Audio ION alloc is failed, rc = %d, stage_idx = %d\n",
__func__, rc); __func__, rc, stage_idx);
goto fail; 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 { } else {
pr_err("%s: sound model busy\n", __func__); pr_err("%s: sound model busy, stage_idx %d\n", __func__, stage_idx);
rc = -EBUSY; rc = -EBUSY;
goto fail; 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, rc = q6lsm_memory_map_regions(client, sm->phys, len, &sm->mem_map_handle);
len,
&client->sound_model.mem_map_handle);
if (rc) { if (rc) {
pr_err("%s: CMD Memory_map_regions failed %d\n", __func__, rc); pr_err("%s: CMD Memory_map_regions failed %d, stage_idx %d\n",
goto exit; __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); 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; return rc;
} }
EXPORT_SYMBOL(q6lsm_snd_model_buf_alloc); 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 * Returns 0 on success or error on failure
*/ */
int q6lsm_set_one_param(struct lsm_client *client, 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) uint32_t param_type)
{ {
struct param_hdr_v3 param_info; struct param_hdr_v3 param_info;
@@ -1822,7 +2005,7 @@ int q6lsm_set_one_param(struct lsm_client *client,
switch (param_type) { switch (param_type) {
case LSM_ENDPOINT_DETECT_THRESHOLD: { case LSM_ENDPOINT_DETECT_THRESHOLD: {
param_info.module_id = p_info->module_id; 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_id = p_info->param_id;
rc = q6lsm_send_param_epd_thres(client, data, &param_info); rc = q6lsm_send_param_epd_thres(client, data, &param_info);
if (rc) if (rc)
@@ -1847,7 +2030,7 @@ int q6lsm_set_one_param(struct lsm_client *client,
client->mode |= det_mode->detect_failure << 2; client->mode |= det_mode->detect_failure << 2;
param_info.module_id = p_info->module_id; 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_id = p_info->param_id;
rc = q6lsm_send_param_opmode(client, &param_info, rc = q6lsm_send_param_opmode(client, &param_info,
@@ -1861,7 +2044,7 @@ int q6lsm_set_one_param(struct lsm_client *client,
case LSM_GAIN: { case LSM_GAIN: {
struct snd_lsm_gain *lsm_gain = (struct snd_lsm_gain *) data; struct snd_lsm_gain *lsm_gain = (struct snd_lsm_gain *) data;
param_info.module_id = p_info->module_id; 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_id = p_info->param_id;
rc = q6lsm_send_param_gain(client, lsm_gain->gain, &param_info); rc = q6lsm_send_param_gain(client, lsm_gain->gain, &param_info);
if (rc) if (rc)
@@ -1872,7 +2055,7 @@ int q6lsm_set_one_param(struct lsm_client *client,
case LSM_MIN_CONFIDENCE_LEVELS: case LSM_MIN_CONFIDENCE_LEVELS:
param_info.module_id = p_info->module_id; 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_id = p_info->param_id;
rc = q6lsm_send_confidence_levels( rc = q6lsm_send_confidence_levels(
client, &param_info, LSM_SESSION_CMD_SET_PARAMS_V2); 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 *lsm_poll_enable =
(struct snd_lsm_poll_enable *) data; (struct snd_lsm_poll_enable *) data;
param_info.module_id = p_info->module_id; 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_id = p_info->param_id;
rc = q6lsm_send_param_polling_enable( rc = q6lsm_send_param_polling_enable(
client, lsm_poll_enable->poll_en, &param_info, 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: { case LSM_REG_SND_MODEL: {
struct mem_mapping_hdr mem_hdr; struct mem_mapping_hdr mem_hdr;
u32 payload_size; u32 payload_size;
struct lsm_sound_model *sm = NULL;
memset(&mem_hdr, 0, sizeof(mem_hdr)); 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 + payload_size = p_info->param_size +
sizeof(struct param_hdr_v2); sizeof(struct param_hdr_v2);
sm = &client->stage_cfg[p_info->stage_idx].sound_model;
mem_hdr.data_payload_addr_lsw = mem_hdr.data_payload_addr_lsw =
lower_32_bits(client->sound_model.phys); lower_32_bits(sm->phys);
mem_hdr.data_payload_addr_msw = mem_hdr.data_payload_addr_msw =
msm_audio_populate_upper_32_bits( msm_audio_populate_upper_32_bits(
client->sound_model.phys), sm->phys),
mem_hdr.mem_map_handle = client->sound_model.mem_map_handle; mem_hdr.mem_map_handle = sm->mem_map_handle;
rc = q6lsm_set_params(client, &mem_hdr, NULL, payload_size, rc = q6lsm_set_params(client, &mem_hdr, NULL, payload_size,
LSM_SESSION_CMD_SET_PARAMS_V2); LSM_SESSION_CMD_SET_PARAMS_V2);
@@ -1923,7 +2109,7 @@ int q6lsm_set_one_param(struct lsm_client *client,
return rc; 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) if (rc)
pr_err("%s: Failed to send lsm cal, err = %d\n", pr_err("%s: Failed to send lsm cal, err = %d\n",
__func__, rc); __func__, rc);
@@ -1932,7 +2118,7 @@ int q6lsm_set_one_param(struct lsm_client *client,
case LSM_DEREG_SND_MODEL: { case LSM_DEREG_SND_MODEL: {
param_info.module_id = p_info->module_id; 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_id = p_info->param_id;
param_info.param_size = 0; param_info.param_size = 0;
rc = q6lsm_pack_and_set_params(client, &param_info, NULL, 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; (struct snd_lsm_det_event_type *)data;
param_info.module_id = p_info->module_id; 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_id = p_info->param_id;
param_info.param_size = sizeof(det_event_type); param_info.param_size = sizeof(det_event_type);
@@ -2044,10 +2230,12 @@ EXPORT_SYMBOL(q6lsm_close);
* *
* @client: LSM client handle * @client: LSM client handle
* @enable: bool flag to enable or disable LAB on DSP * @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 * 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 lsm_param_lab_enable lab_enable;
struct param_hdr_v3 lab_enable_hdr; 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 */ /* enable/disable lab on dsp */
lab_enable_hdr.module_id = LSM_MODULE_ID_LAB; lab_enable_hdr.module_id = p_info->module_id;
lab_enable_hdr.instance_id = INSTANCE_ID_0; lab_enable_hdr.instance_id = p_info->instance_id;
lab_enable_hdr.param_id = LSM_PARAM_ID_LAB_ENABLE; lab_enable_hdr.param_id = LSM_PARAM_ID_LAB_ENABLE;
lab_enable_hdr.param_size = sizeof(lab_enable); lab_enable_hdr.param_size = sizeof(lab_enable);
lab_enable.enable = (enable) ? 1 : 0; lab_enable.enable = (enable) ? 1 : 0;
@@ -2082,8 +2270,8 @@ int q6lsm_lab_control(struct lsm_client *client, u32 enable)
goto exit; goto exit;
/* lab session is being enabled set the config values */ /* lab session is being enabled set the config values */
lab_config_hdr.module_id = LSM_MODULE_ID_LAB; lab_config_hdr.module_id = p_info->module_id;
lab_config_hdr.instance_id = INSTANCE_ID_0; lab_config_hdr.instance_id = p_info->instance_id;
lab_config_hdr.param_id = LSM_PARAM_ID_LAB_CONFIG; lab_config_hdr.param_id = LSM_PARAM_ID_LAB_CONFIG;
lab_config_hdr.param_size = sizeof(lab_config); lab_config_hdr.param_size = sizeof(lab_config);
lab_config.minor_version = 1; lab_config.minor_version = 1;
@@ -2114,11 +2302,12 @@ EXPORT_SYMBOL(q6lsm_lab_control);
* @client: LSM client handle * @client: LSM client handle
* @ch_map: Channel map indicating the order * @ch_map: Channel map indicating the order
* of channels to be configured. * 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 * Returns 0 on success or error on failure
*/ */
int q6lsm_lab_out_ch_cfg(struct lsm_client *client, 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; u8 *param_buf;
struct lsm_param_lab_out_ch_cfg *lab_out_cfg; 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]; lab_out_cfg->channel_indices[i] = ch_map[i];
memset(&lab_out_cfg_hdr, 0, sizeof(lab_out_cfg_hdr)); 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.module_id = p_info->module_id;
lab_out_cfg_hdr.instance_id = INSTANCE_ID_0; 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_id = LSM_PARAM_ID_LAB_OUTPUT_CHANNEL_CONFIG;
lab_out_cfg_hdr.param_size = param_len; lab_out_cfg_hdr.param_size = param_len;

View File

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

View File

@@ -26,6 +26,8 @@
#define LSM_MAX_NUM_CHANNELS 8 #define LSM_MAX_NUM_CHANNELS 8
#define LSM_V3P0_MAX_NUM_CHANNELS 9 #define LSM_V3P0_MAX_NUM_CHANNELS 9
#define LSM_API_VERSION_V3 3
typedef void (*lsm_app_cb)(uint32_t opcode, uint32_t token, typedef void (*lsm_app_cb)(uint32_t opcode, uint32_t token,
uint32_t *payload, void *priv); uint32_t *payload, void *priv);
@@ -60,6 +62,24 @@ struct lsm_hw_params {
u16 num_chs; 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 { struct lsm_client {
int session; int session;
lsm_app_cb cb; lsm_app_cb cb;
@@ -68,7 +88,6 @@ struct lsm_client {
struct apr_svc *apr; struct apr_svc *apr;
struct apr_svc *mmap_apr; struct apr_svc *mmap_apr;
struct mutex cmd_lock; struct mutex cmd_lock;
struct lsm_sound_model sound_model;
wait_queue_head_t cmd_wait; wait_queue_head_t cmd_wait;
uint32_t cmd_err_code; uint32_t cmd_err_code;
uint16_t mode; uint16_t mode;
@@ -77,8 +96,6 @@ struct lsm_client {
uint8_t *confidence_levels; uint8_t *confidence_levels;
bool opened; bool opened;
bool started; bool started;
dma_addr_t lsm_cal_phy_addr;
uint32_t lsm_cal_size;
uint32_t app_id; uint32_t app_id;
bool lab_enable; bool lab_enable;
bool lab_started; bool lab_started;
@@ -91,6 +108,8 @@ struct lsm_client {
int perf_mode; int perf_mode;
uint32_t event_mode; uint32_t event_mode;
uint32_t event_type; 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 { struct lsm_stream_cmd_open_tx {
@@ -105,6 +124,17 @@ struct lsm_stream_cmd_open_tx_v2 {
uint32_t topology_id; uint32_t topology_id;
} __packed; } __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 lsm_custom_topologies {
struct apr_hdr hdr; struct apr_hdr hdr;
uint32_t data_payload_addr_lsw; 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_start(struct lsm_client *client, bool wait);
int q6lsm_stop(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, 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 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 q6lsm_close(struct lsm_client *client); int q6lsm_close(struct lsm_client *client);
int q6lsm_register_sound_model(struct lsm_client *client, int q6lsm_register_sound_model(struct lsm_client *client,
enum lsm_detection_mode mode, 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); int q6lsm_deregister_sound_model(struct lsm_client *client);
void set_lsm_port(int lsm_port); void set_lsm_port(int lsm_port);
int get_lsm_port(void); 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_stop_lab(struct lsm_client *client);
int q6lsm_read(struct lsm_client *client, struct lsm_cmd_read *read); 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_lab_buffer_alloc(struct lsm_client *client, bool alloc);
int q6lsm_set_one_param(struct lsm_client *client, 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); uint32_t param_type);
void q6lsm_sm_set_param_data(struct lsm_client *client, 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); size_t *offset);
int q6lsm_set_port_connected(struct lsm_client *client); 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_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_params(struct lsm_client *client);
int q6lsm_set_media_fmt_v2_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__ */ #endif /* __Q6LSM_H__ */