asoc: dsp: Add support for adaptive bitrate
Add support for adaptive bitrate with A2DP offload.
Set up Tx feedback path on SLIMBUS_7_TX from BT SoC
to LPASS. Configure AFE encoder and decoder for ABR.
Add bit width support to configure AFE port with
32bit for BT A2DP.
Change-Id: I8e0afaf52561e5dc70318240ba238fc42844501f
Signed-off-by: Aniket Kumar Lata <alata@codeaurora.org>
diff --git a/dsp/q6afe.c b/dsp/q6afe.c
index 5a92fa5..ce67a19 100644
--- a/dsp/q6afe.c
+++ b/dsp/q6afe.c
@@ -2997,6 +2997,93 @@
return ret;
}
+static int q6afe_send_dec_config(u16 port_id,
+ union afe_port_config afe_config,
+ struct afe_dec_config *cfg)
+{
+ struct afe_audioif_config_command config;
+ int index = 0;
+ int ret = 0;
+ size_t payload_size = sizeof(config) - sizeof(struct apr_hdr) -
+ sizeof(config.param) - sizeof(config.port);
+
+ index = q6audio_get_port_index(port_id);
+ if (index < 0) {
+ pr_err("%s: Invalid index number: %d\n", __func__, index);
+ return -EINVAL;
+ }
+ memset(&config, 0, sizeof(config));
+
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = index;
+
+ config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
+ config.param.port_id = q6audio_get_port_id(port_id);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+ config.pdata.module_id = AFE_MODULE_ID_DECODER;
+ config.param.payload_size =
+ payload_size + sizeof(config.port.dec_depkt_id_param);
+ pr_debug("%s:sending AFE_DECODER_PARAM_ID_DEPACKETIZER to DSP payload = %d\n",
+ __func__, config.param.payload_size);
+ config.pdata.param_id = AFE_DECODER_PARAM_ID_DEPACKETIZER_ID;
+ config.pdata.param_size = sizeof(config.port.dec_depkt_id_param);
+ config.port.dec_depkt_id_param.dec_depacketizer_id =
+ AFE_MODULE_ID_DEPACKETIZER_COP;
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE_DECODER_PARAM_ID_DEPACKETIZER for port 0x%x failed %d\n",
+ __func__, port_id, ret);
+ goto exit;
+ }
+
+ config.param.payload_size =
+ payload_size + sizeof(config.port.imc_info_param);
+ pr_debug("%s:sending AFE_ENCDEC_PARAM_ID_DEC_TO_ENC_COMMUNICATION to DSP payload = %d\n",
+ __func__, config.param.payload_size);
+ config.pdata.param_id = AFE_ENCDEC_PARAM_ID_DEC_TO_ENC_COMMUNICATION;
+ config.pdata.param_size = sizeof(config.port.imc_info_param);
+ config.port.imc_info_param.imc_info = cfg->abr_dec_cfg.imc_info;
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE_ENCDEC_PARAM_ID_DEC_TO_ENC_COMMUNICATION for port 0x%x failed %d\n",
+ __func__, port_id, ret);
+ goto exit;
+ }
+
+ config.param.payload_size =
+ payload_size + sizeof(config.port.media_type);
+ config.pdata.param_size = sizeof(config.port.media_type);
+
+ pr_debug("%s:Sending AFE_API_VERSION_PORT_MEDIA_TYPE to DSP\n",
+ __func__);
+ config.pdata.module_id = AFE_MODULE_PORT;
+ config.pdata.param_id = AFE_PARAM_ID_PORT_MEDIA_TYPE;
+ config.port.media_type.minor_version = AFE_API_VERSION_PORT_MEDIA_TYPE;
+ config.port.media_type.sample_rate = afe_config.slim_sch.sample_rate;
+ config.port.media_type.bit_width =
+ afe_config.slim_sch.bit_width;
+ config.port.media_type.num_channels =
+ afe_config.slim_sch.num_channels;
+ config.port.media_type.data_format = AFE_PORT_DATA_FORMAT_PCM;
+ config.port.media_type.reserved = 0;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE_API_VERSION_PORT_MEDIA_TYPE for port 0x%x failed %d\n",
+ __func__, port_id, ret);
+ goto exit;
+ }
+
+exit:
+ return ret;
+}
+
static int q6afe_send_enc_config(u16 port_id,
union afe_enc_config_data *cfg, u32 format,
union afe_port_config afe_config,
@@ -3048,15 +3135,25 @@
__func__);
goto exit;
}
-
- config.param.payload_size = payload_size
+ if (format == ASM_MEDIA_FMT_LDAC) {
+ config.param.payload_size = payload_size
+ + sizeof(config.port.enc_blk_param)
+ - sizeof(struct afe_abr_enc_cfg_t);
+ config.pdata.param_size = sizeof(config.port.enc_blk_param)
+ - sizeof(struct afe_abr_enc_cfg_t);
+ config.port.enc_blk_param.enc_cfg_blk_size =
+ sizeof(config.port.enc_blk_param.enc_blk_config)
+ - sizeof(struct afe_abr_enc_cfg_t);
+ } else {
+ config.param.payload_size = payload_size
+ sizeof(config.port.enc_blk_param);
+ config.pdata.param_size = sizeof(config.port.enc_blk_param);
+ config.port.enc_blk_param.enc_cfg_blk_size =
+ sizeof(config.port.enc_blk_param.enc_blk_config);
+ }
pr_debug("%s:send AFE_ENCODER_PARAM_ID_ENC_CFG_BLK to DSP payload:%d\n",
__func__, config.param.payload_size);
config.pdata.param_id = AFE_ENCODER_PARAM_ID_ENC_CFG_BLK;
- config.pdata.param_size = sizeof(config.port.enc_blk_param);
- config.port.enc_blk_param.enc_cfg_blk_size =
- sizeof(config.port.enc_blk_param.enc_blk_config);
config.port.enc_blk_param.enc_blk_config = *cfg;
ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
if (ret) {
@@ -3112,22 +3209,54 @@
goto exit;
}
+ if (format == ASM_MEDIA_FMT_LDAC) {
+ config.param.payload_size =
+ payload_size + sizeof(config.port.map_param);
+ pr_debug("%s:sending AFE_ENCODER_PARAM_ID_BIT_RATE_LEVEL_MAP to DSP payload = %d\n",
+ __func__, config.param.payload_size);
+ config.pdata.param_id = AFE_ENCODER_PARAM_ID_BIT_RATE_LEVEL_MAP;
+ config.pdata.param_size = sizeof(config.port.map_param);
+ config.port.map_param.mapping_table =
+ cfg->ldac_config.abr_config.mapping_info;
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE_ENCODER_PARAM_ID_BIT_RATE_LEVEL_MAP for port 0x%x failed %d\n",
+ __func__, port_id, ret);
+ goto exit;
+ }
+
+ config.param.payload_size =
+ payload_size + sizeof(config.port.imc_info_param);
+ pr_debug("%s:sending AFE_ENCDEC_PARAM_ID_DEC_TO_ENC_COMMUNICATION to DSP payload = %d\n",
+ __func__, config.param.payload_size);
+ config.pdata.param_id =
+ AFE_ENCDEC_PARAM_ID_DEC_TO_ENC_COMMUNICATION;
+ config.pdata.param_size = sizeof(config.port.imc_info_param);
+ config.port.imc_info_param.imc_info =
+ cfg->ldac_config.abr_config.imc_info;
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE_ENCDEC_PARAM_ID_DEC_TO_ENC_COMMUNICATION for port 0x%x failed %d\n",
+ __func__, port_id, ret);
+ goto exit;
+ }
+ }
+
config.param.payload_size =
payload_size + sizeof(config.port.media_type);
config.pdata.param_size = sizeof(config.port.media_type);
- pr_debug("%s:Sending AFE_API_VERSION_PORT_MEDIA_TYPE to DSP", __func__);
+ pr_debug("%s:Sending AFE_API_VERSION_PORT_MEDIA_TYPE to DSP\n",
+ __func__);
config.pdata.module_id = AFE_MODULE_PORT;
config.pdata.param_id = AFE_PARAM_ID_PORT_MEDIA_TYPE;
config.port.media_type.minor_version = AFE_API_VERSION_PORT_MEDIA_TYPE;
- if (format == ASM_MEDIA_FMT_LDAC) {
+ if (format == ASM_MEDIA_FMT_LDAC)
config.port.media_type.sample_rate =
- config.port.enc_blk_param.enc_blk_config.ldac_config.
- custom_config.sample_rate;
- } else {
+ cfg->ldac_config.custom_config.sample_rate;
+ else
config.port.media_type.sample_rate =
afe_config.slim_sch.sample_rate;
- }
if (afe_in_bit_width)
config.port.media_type.bit_width = afe_in_bit_width;
@@ -3156,8 +3285,9 @@
static int __afe_port_start(u16 port_id, union afe_port_config *afe_config,
u32 rate, u16 afe_in_channels, u16 afe_in_bit_width,
- union afe_enc_config_data *cfg, u32 enc_format,
- u32 scrambler_mode)
+ union afe_enc_config_data *enc_cfg,
+ u32 codec_format, u32 scrambler_mode,
+ struct afe_dec_config *dec_cfg)
{
struct afe_audioif_config_command config;
int ret = 0;
@@ -3402,7 +3532,8 @@
config.pdata.param_size = sizeof(config.port);
config.port = *afe_config;
- if ((enc_format != ASM_MEDIA_FMT_NONE) &&
+ if (((enc_cfg != NULL) || (dec_cfg != NULL)) &&
+ (codec_format != ASM_MEDIA_FMT_NONE) &&
(cfg_type == AFE_PARAM_ID_SLIMBUS_CONFIG)) {
config.port.slim_sch.data_format =
AFE_SB_DATA_FORMAT_GENERIC_COMPRESSED;
@@ -3414,18 +3545,32 @@
goto fail_cmd;
}
- if ((enc_format != ASM_MEDIA_FMT_NONE) &&
+ if ((codec_format != ASM_MEDIA_FMT_NONE) &&
(cfg_type == AFE_PARAM_ID_SLIMBUS_CONFIG)) {
- pr_debug("%s: Found AFE encoder support for SLIMBUS enc_format = %d\n",
- __func__, enc_format);
- ret = q6afe_send_enc_config(port_id, cfg, enc_format,
- *afe_config, afe_in_channels,
- afe_in_bit_width,
- scrambler_mode);
- if (ret) {
- pr_err("%s: AFE encoder config for port 0x%x failed %d\n",
- __func__, port_id, ret);
- goto fail_cmd;
+ if (enc_cfg != NULL) {
+ pr_debug("%s: Found AFE encoder support for SLIMBUS enc_format = %d\n",
+ __func__, codec_format);
+ ret = q6afe_send_enc_config(port_id, enc_cfg,
+ codec_format, *afe_config,
+ afe_in_channels,
+ afe_in_bit_width,
+ scrambler_mode);
+ if (ret) {
+ pr_err("%s: AFE encoder config for port 0x%x failed %d\n",
+ __func__, port_id, ret);
+ goto fail_cmd;
+ }
+ }
+ if (dec_cfg != NULL) {
+ pr_debug("%s: Found AFE decoder support for SLIMBUS dec_format = %d\n",
+ __func__, codec_format);
+ ret = q6afe_send_dec_config(port_id, *afe_config,
+ dec_cfg);
+ if (ret) {
+ pr_err("%s: AFE decoder config for port 0x%x failed %d\n",
+ __func__, port_id, ret);
+ goto fail_cmd;
+ }
}
}
@@ -3474,31 +3619,42 @@
u32 rate)
{
return __afe_port_start(port_id, afe_config, rate,
- 0, 0, NULL, ASM_MEDIA_FMT_NONE, 0);
+ 0, 0, NULL, ASM_MEDIA_FMT_NONE, 0, NULL);
}
EXPORT_SYMBOL(afe_port_start);
/**
* afe_port_start_v2 - to configure AFE session with
- * specified port configuration and encoder params
+ * specified port configuration and encoder/decoder params
*
* @port_id: AFE port id number
* @afe_config: port configutation
* @rate: sampling rate of port
- * @cfg: AFE encoder configuration information to setup encoder
+ * @enc_cfg: AFE enc configuration information to setup encoder
* @afe_in_channels: AFE input channel configuration, this needs
* update only if input channel is differ from AFE output
+ * @dec_cfg: AFE dec configuration information to set up decoder
*
* Returns 0 on success or error value on port start failure.
*/
int afe_port_start_v2(u16 port_id, union afe_port_config *afe_config,
u32 rate, u16 afe_in_channels, u16 afe_in_bit_width,
- struct afe_enc_config *enc_cfg)
+ struct afe_enc_config *enc_cfg,
+ struct afe_dec_config *dec_cfg)
{
- return __afe_port_start(port_id, afe_config, rate,
- afe_in_channels, afe_in_bit_width,
- &enc_cfg->data, enc_cfg->format,
- enc_cfg->scrambler_mode);
+ int ret = 0;
+
+ if (enc_cfg != NULL)
+ ret = __afe_port_start(port_id, afe_config, rate,
+ afe_in_channels, afe_in_bit_width,
+ &enc_cfg->data, enc_cfg->format,
+ enc_cfg->scrambler_mode, NULL);
+ else if (dec_cfg != NULL)
+ ret = __afe_port_start(port_id, afe_config, rate,
+ afe_in_channels, afe_in_bit_width,
+ NULL, dec_cfg->format, 0, dec_cfg);
+
+ return ret;
}
EXPORT_SYMBOL(afe_port_start_v2);