dsp: adm: support adm open with ec_ref info

Add new version of adm open which accept stream based ec_ref information to
support per-stream ec_ref channel mixer.

Signed-off-by: Erin Yan <xinyey@codeaurora.org>
Change-Id: I2253d71aa107bdad6d3eea7d528ff7403d292a85
This commit is contained in:
Erin Yan 2021-03-23 21:33:32 +08:00 • committed by Gerrit - the friendly Code Review server
commit b1950d5cd3
2 changed files with 221 additions and 76 deletions

View file

@ -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 -

View file

@ -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);