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