diff --git a/dsp/q6voice.c b/dsp/q6voice.c index 7cd340f96177..6f70f57dc400 100644 --- a/dsp/q6voice.c +++ b/dsp/q6voice.c @@ -36,7 +36,9 @@ #define CMD_STATUS_FAIL 1 #define NUM_CHANNELS_MONO 1 #define NUM_CHANNELS_STEREO 2 +#define NUM_CHANNELS_QUAD 4 #define CVP_VERSION_2 2 +#define GAIN_Q14_FORMAT(a) (a << 14) enum { VOC_TOKEN_NONE, @@ -3889,11 +3891,15 @@ static int voice_send_cvp_channel_info_v2(struct voice_data *v, } else if (channel_info->num_channels == NUM_CHANNELS_STEREO) { channel_info->channel_mapping[0] = PCM_CHANNEL_FL; channel_info->channel_mapping[1] = PCM_CHANNEL_FR; + } else if (channel_info->num_channels == NUM_CHANNELS_QUAD && + param_type == TX_PATH) { + channel_info->channel_mapping[0] = PCM_CHANNEL_FL; + channel_info->channel_mapping[1] = PCM_CHANNEL_FR; + channel_info->channel_mapping[2] = PCM_CHANNEL_LS; + channel_info->channel_mapping[3] = PCM_CHANNEL_RS; } else { - pr_err("%s: Unsupported num channels: %d\n", - __func__, channel_info->num_channels); - ret = -EINVAL; - goto done; + pr_warn("%s: Unsupported num channels: %d for path: %d\n", + __func__, channel_info->num_channels, param_type); } v->cvp_state = CMD_STATUS_FAIL; @@ -3953,6 +3959,103 @@ done: return ret; } +static int voice_send_cvp_ch_mixer_info_v2(struct voice_data *v) +{ + int ret; + struct cvp_set_channel_mixer_info_cmd_v2 cvp_set_ch_mixer_info_cmd; + void *apr_cvp; + u16 cvp_handle; + struct vss_icommon_param_data_ch_mixer_v2_t *cvp_config_param_data = + &cvp_set_ch_mixer_info_cmd. + cvp_set_ch_mixer_param_v2.param_data; + struct vss_param_channel_mixer_info_t *ch_mixer_info = + &cvp_config_param_data->ch_mixer_info; + + if (v == NULL) { + pr_err("%s: v is NULL\n", __func__); + ret = -EINVAL; + goto done; + } + + apr_cvp = common.apr_q6_cvp; + if (!apr_cvp) { + pr_err("%s: apr_cvp is NULL\n", __func__); + ret = -EINVAL; + goto done; + } + + cvp_handle = voice_get_cvp_handle(v); + memset(&cvp_set_ch_mixer_info_cmd, 0, + sizeof(cvp_set_ch_mixer_info_cmd)); + + cvp_set_ch_mixer_info_cmd.hdr.hdr_field = + APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + cvp_set_ch_mixer_info_cmd.hdr.pkt_size = + APR_PKT_SIZE(APR_HDR_SIZE, + sizeof(cvp_set_ch_mixer_info_cmd) - APR_HDR_SIZE); + cvp_set_ch_mixer_info_cmd.hdr.src_svc = 0; + cvp_set_ch_mixer_info_cmd.hdr.src_domain = APR_DOMAIN_APPS; + cvp_set_ch_mixer_info_cmd.hdr.src_port = + voice_get_idx_for_session(v->session_id); + cvp_set_ch_mixer_info_cmd.hdr.dest_svc = 0; + cvp_set_ch_mixer_info_cmd.hdr.dest_domain = APR_DOMAIN_ADSP; + cvp_set_ch_mixer_info_cmd.hdr.dest_port = cvp_handle; + cvp_set_ch_mixer_info_cmd.hdr.token = VOC_GENERIC_SET_PARAM_TOKEN; + cvp_set_ch_mixer_info_cmd.hdr.opcode = VSS_ICOMMON_CMD_SET_PARAM_V2; + cvp_set_ch_mixer_info_cmd.cvp_set_ch_mixer_param_v2.mem_size = + sizeof(struct vss_icommon_param_data_ch_mixer_v2_t); + + cvp_config_param_data->module_id = AUDPROC_MODULE_ID_MFC; + cvp_config_param_data->param_id = + AUDPROC_CHMIXER_PARAM_ID_COEFF; + cvp_config_param_data->param_size = + sizeof(struct vss_param_channel_mixer_info_t); + + ch_mixer_info->index = 0; + ch_mixer_info->num_output_channels = v->dev_rx.no_of_channels; + /* + * Configure Rx input to be mono for channel mixer as the DSP + * configures vocproc input as mono. + */ + ch_mixer_info->num_input_channels = NUM_CHANNELS_MONO; + ch_mixer_info->out_channel_map[0] = PCM_CHANNEL_L; + ch_mixer_info->out_channel_map[1] = PCM_CHANNEL_R; + ch_mixer_info->in_channel_map[0] = PCM_CHANNEL_L; + ch_mixer_info->channel_weight_coeff[0][0] = GAIN_Q14_FORMAT(1); + ch_mixer_info->channel_weight_coeff[1][0] = GAIN_Q14_FORMAT(1); + ch_mixer_info->reserved = 0; + + v->cvp_state = CMD_STATUS_FAIL; + v->async_err = 0; + ret = apr_send_pkt(apr_cvp, (uint32_t *)&cvp_set_ch_mixer_info_cmd); + if (ret < 0) { + pr_err("%s: Failed to send VSS_ICOMMON_CMD_SET_PARAM_V2 %d\n", + __func__, ret); + goto done; + } + ret = wait_event_timeout(v->cvp_wait, + (v->cvp_state == CMD_STATUS_SUCCESS), + msecs_to_jiffies(TIMEOUT_MS)); + + if (!ret) { + pr_err("%s: wait_event timeout\n", __func__); + ret = -ETIMEDOUT; + goto done; + } + + if (v->async_err > 0) { + pr_err("%s: DSP returned error[%s] handle = %d\n", __func__, + adsp_err_get_err_str(v->async_err), cvp_handle); + ret = adsp_err_get_lnx_err_code(v->async_err); + goto done; + } + ret = 0; +done: + return ret; +} + static int voice_send_cvp_mfc_config_v2(struct voice_data *v) { int ret; @@ -4014,10 +4117,8 @@ static int voice_send_cvp_mfc_config_v2(struct voice_data *v) mfc_config_info->channel_type[0] = PCM_CHANNEL_FL; mfc_config_info->channel_type[1] = PCM_CHANNEL_FR; } else { - pr_err("%s: Unsupported num channels: %d\n", - __func__, mfc_config_info->num_channels); - ret = -EINVAL; - goto done; + pr_warn("%s: Unsupported num channels: %d\n", + __func__, mfc_config_info->num_channels); } v->cvp_state = CMD_STATUS_FAIL; @@ -4054,7 +4155,15 @@ static int voice_send_cvp_mfc_config_cmd(struct voice_data *v) int ret = 0; if (common.cvp_version >= CVP_VERSION_2) { + ret = voice_send_cvp_ch_mixer_info_v2(v); + if (ret < 0) + pr_warn("%s: Set channel mixer config failed err:%d", + __func__, ret); + ret = voice_send_cvp_mfc_config_v2(v); + if (ret < 0) + pr_warn("%s: Set MFC config failed err:%d", + __func__, ret); } else { pr_warn("%s: CVP Version not supported\n", __func__); ret = -EINVAL; diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h index 2256b7b4d9b8..8e9b6294156b 100644 --- a/include/dsp/apr_audio-v2.h +++ b/include/dsp/apr_audio-v2.h @@ -623,6 +623,9 @@ struct audproc_softvolume_params { */ #define AUDPROC_PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT 0x00010913 +/* Param ID of Channel Mixer used by AUDPROC_MODULE_ID_MFC */ +#define AUDPROC_CHMIXER_PARAM_ID_COEFF 0x00010342 + struct audproc_mfc_output_media_fmt { struct adm_cmd_set_pp_params_v5 params; diff --git a/include/dsp/q6voice.h b/include/dsp/q6voice.h index 7818707b5aa9..af7995a01cd9 100644 --- a/include/dsp/q6voice.h +++ b/include/dsp/q6voice.h @@ -245,6 +245,16 @@ struct vss_param_vocproc_dev_channel_info_t { uint8_t channel_mapping[VSS_NUM_CHANNELS_MAX]; } __packed; +struct vss_param_channel_mixer_info_t { + uint32_t index; + uint16_t num_output_channels; + uint16_t num_input_channels; + uint16_t out_channel_map[2]; + uint16_t in_channel_map[1]; + uint16_t channel_weight_coeff[2][1]; + uint16_t reserved; +} __packed; + struct vss_param_mfc_config_info_t { uint32_t sample_rate; uint16_t bits_per_sample; @@ -313,6 +323,47 @@ struct vss_icommon_cmd_set_param_channel_info_v2_t { struct vss_icommon_param_data_channel_info_v2_t param_data; } __packed; +struct vss_icommon_param_data_ch_mixer_v2_t { + /* Valid ID of the module. */ + uint32_t module_id; + /* Valid ID of the parameter. */ + uint32_t param_id; + /* + * Data size of the structure relating to the param_id/module_id + * combination in uint8_t bytes. + */ + uint16_t param_size; + /* This field must be set to zero. */ + uint16_t reserved; + struct vss_param_channel_mixer_info_t ch_mixer_info; +} __packed; + +struct vss_icommon_cmd_set_param_ch_mixer_v2_t { + /* + * Pointer to the unique identifier for an address (physical/virtual). + * + * If the parameter data payload is within the message payload + * (in-band), set this field to 0. The parameter data begins at the + * specified data payload address. + * + * If the parameter data is out-of-band, this field is the handle to + * the physical address in the shared memory that holds the parameter + * data. + */ + uint32_t mem_handle; + /* + * Location of the parameter data payload. + * + * The payload is an array of vss_icommon_param_data_t. If the + * mem_handle is 0, this field is ignored. + */ + uint64_t mem_address; + /* Size of the parameter data payload in bytes. */ + uint32_t mem_size; + + struct vss_icommon_param_data_ch_mixer_v2_t param_data; +} __packed; + struct vss_icommon_param_data_mfc_config_v2_t { /* Valid ID of the module. */ uint32_t module_id; @@ -1595,6 +1646,12 @@ struct cvp_set_channel_info_cmd_v2 { cvp_set_ch_info_param_v2; } __packed; +struct cvp_set_channel_mixer_info_cmd_v2 { + struct apr_hdr hdr; + struct vss_icommon_cmd_set_param_ch_mixer_v2_t + cvp_set_ch_mixer_param_v2; +} __packed; + struct cvp_set_mfc_config_cmd_v2 { struct apr_hdr hdr; struct vss_icommon_cmd_set_param_mfc_config_v2_t cvp_set_mfc_param_v2;