diff --git a/dsp/q6adm.c b/dsp/q6adm.c index f9a71d934a03..d606f7541a63 100644 --- a/dsp/q6adm.c +++ b/dsp/q6adm.c @@ -2988,15 +2988,21 @@ static int adm_arrange_mch_ep2_map_v8( return rc; } -static int adm_copp_set_ec_ref_mfc_cfg(int port_id, int copp_idx, +static int adm_copp_set_ec_ref_mfc_cfg_v2(int port_id, int copp_idx, int sample_rate, int bps, - int in_channels, int out_channels) + struct msm_pcm_channel_mixer *cfg) { struct audproc_mfc_param_media_fmt mfc_cfg; struct param_hdr_v3 param_hdr; u16 *chmixer_params = NULL; - int rc = 0, i = 0, j = 0, param_index = 0, param_size = 0; - struct adm_device_endpoint_payload ep_payload = {0, 0, 0, {0}}; + int rc = 0, i = 0, j = 0, param_index = 0, param_size = 0; + struct adm_device_endpoint_payload ep_payload = {0, 0, 0, {0} }; + int in_channels, out_channels; + + if (!cfg) + return -EINVAL; + in_channels = cfg->input_channel; + out_channels = cfg->output_channel; memset(&mfc_cfg, 0, sizeof(mfc_cfg)); memset(&ep_payload, 0, sizeof(ep_payload)); @@ -3010,7 +3016,8 @@ static int adm_copp_set_ec_ref_mfc_cfg(int port_id, int copp_idx, bps, in_channels, out_channels); if (out_channels <= 0 || out_channels > AUDPROC_MFC_OUT_CHANNELS_MAX) { - pr_err("%s: unsupported out channels=%d\n", __func__, out_channels); + pr_err("%s: unsupported out channels=%d\n", + __func__, out_channels); return -EINVAL; } @@ -3023,67 +3030,121 @@ static int adm_copp_set_ec_ref_mfc_cfg(int port_id, int copp_idx, mfc_cfg.num_channels = out_channels; ep_payload.dev_num_channel = out_channels; - rc = adm_arrange_mch_ep2_map_v8(&ep_payload, out_channels); - if (rc < 0) { - pr_err("%s: unable to get map for out channels=%d\n", - __func__, out_channels); - return -EINVAL; + if (cfg && cfg->override_out_ch_map) { + for (i = 0; i < out_channels; i++) { + ep_payload.dev_channel_mapping[i] = cfg->out_ch_map[i]; + pr_debug("%s: out_ch_map[%d] = %d", + __func__, i, ep_payload.dev_channel_mapping[i]); + } + } else { + rc = adm_arrange_mch_ep2_map_v8(&ep_payload, out_channels); + if (rc < 0) { + pr_err("%s: unable to get map for out channels=%d\n", + __func__, out_channels); + return -EINVAL; + } } for (i = 0; i < out_channels; i++) - mfc_cfg.channel_type[i] = (uint16_t) ep_payload.dev_channel_mapping[i]; + mfc_cfg.channel_type[i] = + (uint16_t) ep_payload.dev_channel_mapping[i]; rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, param_hdr, (uint8_t *) &mfc_cfg); if (rc) { - pr_err("%s: Failed to set media format, err %d\n", __func__, rc); + pr_err("%s: Failed to set media format, err %d\n", + __func__, rc); return rc; } /* 2. Send Channel Mixer params */ - param_size = 2 * (4 + out_channels + in_channels + (out_channels * in_channels)); + param_size = 2 * (4 + out_channels + in_channels + + (out_channels * in_channels)); param_size = round_up(param_size, 4); param_hdr.param_id = DEFAULT_CHMIXER_PARAM_ID_COEFF; param_hdr.param_size = param_size; pr_debug("%s: chmixer param sz = %d\n", __func__, param_size); chmixer_params = kzalloc(param_size, GFP_KERNEL); - if (!chmixer_params) { + if (!chmixer_params) return -ENOMEM; - } - param_index = 2; /* param[0] and [1] represents chmixer rule(always 0) */ + + /* param[0] and [1] represents chmixer rule(always 0) */ + param_index = 2; chmixer_params[param_index++] = out_channels; chmixer_params[param_index++] = in_channels; /* output channel map is same as one set in media format */ for (i = 0; i < out_channels; i++) - chmixer_params[param_index++] = ep_payload.dev_channel_mapping[i]; + chmixer_params[param_index++] = + ep_payload.dev_channel_mapping[i]; - /* input channel map should be same as one set for ep2 during copp open */ + /* input chmap should be same as one set for ep2 during copp open */ ep_payload.dev_num_channel = in_channels; - rc = adm_arrange_mch_ep2_map_v8(&ep_payload, in_channels); - if (rc < 0) { - pr_err("%s: unable to get in channal map\n", __func__); - goto exit; + if (cfg && cfg->override_in_ch_map) { + for (i = 0; i < in_channels; i++) { + ep_payload.dev_channel_mapping[i] = cfg->in_ch_map[i]; + pr_debug("%s: in_ch_map[%d] = %d", + __func__, i, ep_payload.dev_channel_mapping[i]); + } + } else { + rc = adm_arrange_mch_ep2_map_v8(&ep_payload, in_channels); + if (rc < 0) { + pr_err("%s: unable to get in channal map\n", __func__); + goto exit; + } } for (i = 0; i < in_channels; i++) - chmixer_params[param_index++] = ep_payload.dev_channel_mapping[i]; + chmixer_params[param_index++] = + ep_payload.dev_channel_mapping[i]; for (i = 0; i < out_channels; i++) - for (j = 0; j < in_channels; j++) - chmixer_params[param_index++] = this_adm.ec_ref_chmixer_weights[i][j]; + for (j = 0; j < in_channels; j++) { + chmixer_params[param_index++] = cfg->channel_weight[i][j]; + pr_debug("%s: ch_weight[%d][%d] = %d\n", + __func__, i, j, cfg->channel_weight[i][j]); + } rc = adm_pack_and_set_one_pp_param(port_id, copp_idx, - param_hdr, (uint8_t *) chmixer_params); + param_hdr, (uint8_t *) chmixer_params); if (rc) - pr_err("%s: Failed to set chmixer params, err %d\n", __func__, rc); + pr_err("%s: Failed to set chmixer params, err %d\n", + __func__, rc); exit: kfree(chmixer_params); return rc; } + +static int adm_copp_set_ec_ref_mfc_cfg(int port_id, int copp_idx, + int sample_rate, int bps, + int in_channels, int out_channels) +{ + struct msm_pcm_channel_mixer *cfg = NULL; + int rc =0, i, j; + + cfg =kzalloc(sizeof(struct msm_pcm_channel_mixer), + GFP_KERNEL); + if (!cfg) { + pr_err("%s: fail to allocate memory\n", __func__); + return -ENOMEM; + } + + cfg->input_channel = in_channels; + cfg->output_channel = out_channels; + for (i = 0; i < out_channels; i++) + for (j = 0; j < in_channels; j++) + cfg->channel_weight[i][j] = + this_adm.ec_ref_chmixer_weights[i][j]; + + rc = adm_copp_set_ec_ref_mfc_cfg_v2(port_id, copp_idx, + sample_rate, bps, cfg); + kfree(cfg); + return rc; +} + /** * adm_open - * command to send ADM open @@ -3104,6 +3165,38 @@ exit: int adm_open(int port_id, int path, int rate, int channel_mode, int topology, int perf_mode, uint16_t bit_width, int app_type, int acdb_id, int session_type, uint32_t passthr_mode, uint32_t copp_token) +{ + return adm_open_v2(port_id, path, rate, channel_mode, topology, + perf_mode, bit_width, app_type, acdb_id, + session_type, passthr_mode, copp_token, + NULL, NULL); +} +EXPORT_SYMBOL(adm_open); + +/** + * adm_open_v2 - + * command to send ADM open with ec_ref config + * + * @port_id: port id number + * @path: direction or ADM path type + * @rate: sample rate of session + * @channel_mode: number of channels set + * @topology: topology active for this session + * @perf_mode: performance mode like LL/ULL/.. + * @bit_width: bit width to set for copp + * @app_type: App type used for this session + * @acdb_id: ACDB ID of this device + * @session_type: type of session + * @ec_ref_port_cfg: ec_ref port configuration + * @ec_ref_chmix_cfg: ec_ref channel mixer configuration + * + * Returns 0 on success or error on failure + */ +int adm_open_v2(int port_id, int path, int rate, int channel_mode, int topology, + int perf_mode, uint16_t bit_width, int app_type, int acdb_id, + int session_type, uint32_t passthr_mode, uint32_t copp_token, + struct msm_ec_ref_port_cfg *ec_ref_port_cfg, + struct msm_pcm_channel_mixer *ec_ref_chmix_cfg) { struct adm_cmd_device_open_v5 open; struct adm_cmd_device_open_v6 open_v6; @@ -3118,7 +3211,23 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology, int tmp_port = q6audio_get_port_id(port_id); void *adm_params = NULL; int param_size; - int num_ec_ref_rx_chans = this_adm.num_ec_ref_rx_chans; + int i; + + int ec_ref_port_id = ec_ref_port_cfg ? + ec_ref_port_cfg->port_id : + this_adm.ec_ref_rx; + + int ec_ref_ch = ec_ref_port_cfg ? + ec_ref_port_cfg->ch : + this_adm.num_ec_ref_rx_chans; + + int ec_ref_bit = ec_ref_port_cfg ? + ec_ref_port_cfg->bit_width : + this_adm.ec_ref_rx_bit_width; + + int ec_ref_sampling_rate = ec_ref_port_cfg ? + ec_ref_port_cfg->sampling_rate : + this_adm.ec_ref_rx_sampling_rate; pr_debug("%s:port %#x path:%d rate:%d mode:%d perf_mode:%d,topo_id %d\n", __func__, port_id, path, rate, channel_mode, perf_mode, @@ -3209,7 +3318,8 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology, copp_idx = adm_get_idx_if_copp_exists(port_idx, topology, perf_mode, rate, bit_width, - app_type, session_type, copp_token); + app_type, session_type, + copp_token); if (copp_idx < 0) { copp_idx = adm_get_next_available_copp(port_idx); @@ -3306,17 +3416,16 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology, open_v8.endpoint_id_2 = 0xFFFF; open_v8.endpoint_id_3 = 0xFFFF; - if (((this_adm.ec_ref_rx & AFE_PORT_INVALID) != + if (((ec_ref_port_id & AFE_PORT_INVALID) != AFE_PORT_INVALID) && (path != ADM_PATH_PLAYBACK)) { - if (this_adm.num_ec_ref_rx_chans != 0) { + if (ec_ref_ch != 0) { open_v8.endpoint_id_2 = - this_adm.ec_ref_rx; - this_adm.ec_ref_rx = AFE_PORT_INVALID; + ec_ref_port_id; + ec_ref_port_id = AFE_PORT_INVALID; } else { pr_err("%s: EC channels not set %d\n", - __func__, - this_adm.num_ec_ref_rx_chans); + __func__, ec_ref_ch); return -EINVAL; } } @@ -3349,25 +3458,22 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology, + ep1_payload_size; atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1); - if ((this_adm.num_ec_ref_rx_chans != 0) + if ((ec_ref_ch != 0) && (path != ADM_PATH_PLAYBACK) && (open_v8.endpoint_id_2 != 0xFFFF)) { ep2_payload.dev_num_channel = - this_adm.num_ec_ref_rx_chans; + ec_ref_ch; - if (this_adm.ec_ref_rx_bit_width != 0) { - ep2_payload.bit_width = - this_adm.ec_ref_rx_bit_width; - } else { + if (ec_ref_bit != 0) + ep2_payload.bit_width = ec_ref_bit; + else ep2_payload.bit_width = bit_width; - } - if (this_adm.ec_ref_rx_sampling_rate != 0) { + if (ec_ref_sampling_rate != 0) ep2_payload.sample_rate = - this_adm.ec_ref_rx_sampling_rate; - } else { + ec_ref_sampling_rate; + else ep2_payload.sample_rate = rate; - } pr_debug("%s: adm open_v8 eid2_channels=%d eid2_bit_width=%d eid2_rate=%d\n", __func__, @@ -3375,11 +3481,22 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology, ep2_payload.bit_width, ep2_payload.sample_rate); - ret = adm_arrange_mch_ep2_map_v8(&ep2_payload, - ep2_payload.dev_num_channel); - - if (ret) - return ret; + if (ec_ref_chmix_cfg && + ec_ref_chmix_cfg->override_in_ch_map) { + for (i = 0; i < ec_ref_ch; i++) { + ep2_payload.dev_channel_mapping[i] = + ec_ref_chmix_cfg->in_ch_map[i]; + pr_debug("%s: in_ch_map[%d] = %d", + __func__, i, + ep2_payload.dev_channel_mapping[i]); + } + } else { + ret = adm_arrange_mch_ep2_map_v8( + &ep2_payload, + ep2_payload.dev_num_channel); + if (ret) + return ret; + } ep2_payload_size = 8 + roundup(ep2_payload.dev_num_channel, 4); param_size += ep2_payload_size; @@ -3394,7 +3511,7 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology, (void *)&ep1_payload, ep1_payload_size); - if ((this_adm.num_ec_ref_rx_chans != 0) + if ((ec_ref_ch != 0) && (path != ADM_PATH_PLAYBACK) && (open_v8.endpoint_id_2 != 0xFFFF)) { memcpy(adm_params + sizeof(open_v8) @@ -3431,7 +3548,7 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology, open.endpoint_id_2 = 0xFFFF; if (this_adm.ec_ref_rx && (path != 1) && - (afe_get_port_type(tmp_port) == MSM_AFE_PORT_TYPE_TX)) { + (afe_get_port_type(tmp_port) == MSM_AFE_PORT_TYPE_TX)) { open.endpoint_id_2 = this_adm.ec_ref_rx; } @@ -3454,7 +3571,7 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology, atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1); - if ((this_adm.num_ec_ref_rx_chans != 0) && + if ((ec_ref_ch != 0) && (path != 1) && (open.endpoint_id_2 != 0xFFFF)) { memset(&open_v6, 0, sizeof(struct adm_cmd_device_open_v6)); @@ -3463,21 +3580,18 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology, open_v6.hdr.opcode = ADM_CMD_DEVICE_OPEN_V6; open_v6.hdr.pkt_size = sizeof(open_v6); open_v6.dev_num_channel_eid2 = - this_adm.num_ec_ref_rx_chans; + ec_ref_ch; - if (this_adm.ec_ref_rx_bit_width != 0) { - open_v6.bit_width_eid2 = - this_adm.ec_ref_rx_bit_width; - } else { + if (ec_ref_bit != 0) + open_v6.bit_width_eid2 = ec_ref_bit; + else open_v6.bit_width_eid2 = bit_width; - } - if (this_adm.ec_ref_rx_sampling_rate != 0) { + if (ec_ref_sampling_rate != 0) open_v6.sample_rate_eid2 = - this_adm.ec_ref_rx_sampling_rate; - } else { + ec_ref_sampling_rate; + else open_v6.sample_rate_eid2 = rate; - } pr_debug("%s: eid2_channels=%d eid2_bit_width=%d eid2_rate=%d\n", __func__, open_v6.dev_num_channel_eid2, @@ -3526,24 +3640,40 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology, atomic_inc(&this_adm.copp.cnt[port_idx][copp_idx]); /* - * Configure MFC(in ec_ref path) if chmixing param is applicable and set. - * Except channels and channel maps the media format config for this module - * should match with the COPP(EP1) config values. + * Configure MFC(in ec_ref path) if chmix param is applicable and set. + * Except channels and channel maps the media format config for this + * module should match with the COPP(EP1) config values. */ - if (path != ADM_PATH_PLAYBACK && - this_adm.num_ec_ref_rx_chans_downmixed != 0 && - num_ec_ref_rx_chans != this_adm.num_ec_ref_rx_chans_downmixed) { - ret = adm_copp_set_ec_ref_mfc_cfg(port_id, copp_idx, - rate, bit_width, num_ec_ref_rx_chans, + if (ec_ref_chmix_cfg) { + if (path != ADM_PATH_PLAYBACK && + ec_ref_chmix_cfg->output_channel != 0 && + ec_ref_chmix_cfg->input_channel != + ec_ref_chmix_cfg->output_channel) { + ret = adm_copp_set_ec_ref_mfc_cfg_v2(port_id, copp_idx, + rate, bit_width, ec_ref_chmix_cfg); + ec_ref_chmix_cfg->output_channel = 0; + if (ret) + pr_err("%s: set EC REF MFC cfg v2 failed, err %d\n", + __func__, ret); + } + } else { + if (path != ADM_PATH_PLAYBACK && + this_adm.num_ec_ref_rx_chans_downmixed != 0 && + this_adm.num_ec_ref_rx_chans != + this_adm.num_ec_ref_rx_chans_downmixed) { + ret = adm_copp_set_ec_ref_mfc_cfg(port_id, copp_idx, + rate, bit_width, this_adm.num_ec_ref_rx_chans, this_adm.num_ec_ref_rx_chans_downmixed); - this_adm.num_ec_ref_rx_chans_downmixed = 0; - if (ret) - pr_err("%s: set EC REF MFC cfg failed, err %d\n", __func__, ret); + this_adm.num_ec_ref_rx_chans_downmixed = 0; + if (ret) + pr_err("%s: set EC REF MFC cfg failed, err %d\n", + __func__, ret); + } } return copp_idx; } -EXPORT_SYMBOL(adm_open); +EXPORT_SYMBOL(adm_open_v2); /** * adm_copp_mfc_cfg - diff --git a/include/dsp/q6adm-v2.h b/include/dsp/q6adm-v2.h index 6687c444910f..7bda3723c7dd 100644 --- a/include/dsp/q6adm-v2.h +++ b/include/dsp/q6adm-v2.h @@ -55,6 +55,14 @@ enum { #define ADSP_ADM_API_VERSION_V3 3 +struct msm_ec_ref_port_cfg { + int rx; + int port_id; + int ch; + int bit_width; + int sampling_rate; +}; + /* multiple copp per stream. */ struct route_payload { unsigned int copp_idx[MAX_COPPS_PER_PORT]; @@ -122,6 +130,13 @@ int adm_open(int port, int path, int rate, int mode, int topology, int app_type, int acdbdev_id, int session_type, uint32_t pass_thr, uint32_t copp_token); +int adm_open_v2(int port, int path, int rate, int mode, int topology, + int perf_mode, uint16_t bits_per_sample, + int app_type, int acdbdev_id, int session_type, + uint32_t pass_thr, uint32_t copp_token, + struct msm_ec_ref_port_cfg *ec_ref_port_cfg, + struct msm_pcm_channel_mixer *ec_ref_chmix_cfg); + int adm_map_rtac_block(struct rtac_cal_block_data *cal_block); int adm_unmap_rtac_block(uint32_t *mem_map_handle);