Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 34901e04 authored by Derek Chen's avatar Derek Chen Committed by Gerrit - the friendly Code Review server
Browse files

ASoC: msm: qdsp6v2: Add ASM low latency loopback support



Add ASM low latency loopback support.
ICC (in-car communication) use case needs the low latency
ASM loopback to satisfy the latency requirement.

CRs-fixed: 998118
Change-Id: If225e809072f4296bc22028da29e589137e5799d
Signed-off-by: default avatarDerek Chen <chenche@codeaurora.org>
parent 2705efa5
Loading
Loading
Loading
Loading
+21 −2
Original line number Diff line number Diff line
@@ -391,6 +391,18 @@ Required properties:
                                           group configuration.
 - pinctrl-x:                              Defines pinctrl state for each pin
                                           group.

* msm-pcm-loopback-low-latency

Required properties:

 - compatible : "qcom,msm-pcm-loopback"

   Optional properties

      - qcom,msm-pcm-loopback-low-latency : Flag indicating whether
        the device node is of type low latency.

Example:

	qcom,msm-pcm {
@@ -404,6 +416,11 @@ Example:
		qcom,msm-pcm-low-latency;
	};

	qcom,msm-pcm-loopback-low-latency {
		compatible = "qcom,msm-pcm-loopback";
		qcom,msm-pcm-loopback-low-latency;
	};

        qcom,msm-pcm-routing {
                compatible = "qcom,msm-pcm-routing";
        };
@@ -1965,13 +1982,15 @@ Example:

		asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
				<&loopback>, <&compress>, <&hostless>,
				<&afe>, <&lsm>, <&routing>, <&compr>;
				<&afe>, <&lsm>, <&routing>, <&compr>,
				<&loopback1>;
		asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
				"msm-pcm-dsp.2", "msm-voip-dsp",
				"msm-pcm-voice", "msm-pcm-loopback",
				"msm-compress-dsp", "msm-pcm-hostless",
				"msm-pcm-afe", "msm-lsm-client",
				"msm-pcm-routing", "msm-compr-dsp";
				"msm-pcm-routing", "msm-compr-dsp",
				"msm-pcm-loopback.1";
		asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>,
				<&dai_mi2s>, <&dai_mi2s_quat>,
				<&afe_pcm_rx>, <&afe_pcm_tx>,
+132 −0
Original line number Diff line number Diff line
@@ -5185,6 +5185,138 @@ struct asm_stream_cmd_open_loopback_v2 {
/* Reserved for future use. This field must be set to zero. */
} __packed;


#define ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK    0x00010DBA

/* Bitmask for the stream's Performance mode. */
#define ASM_BIT_MASK_STREAM_PERF_MODE_FLAG_IN_OPEN_TRANSCODE_LOOPBACK \
	(0x70000000UL)

/* Bit shift for the stream's Performance mode. */
#define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_TRANSCODE_LOOPBACK    28

/* Bitmask for the decoder converter enable flag. */
#define ASM_BIT_MASK_DECODER_CONVERTER_FLAG    (0x00000078UL)

/* Shift value for the decoder converter enable flag. */
#define ASM_SHIFT_DECODER_CONVERTER_FLAG                              3

/* Converter mode is None (Default). */
#define ASM_CONVERTER_MODE_NONE                                       0

/* Converter mode is DDP-to-DD. */
#define ASM_DDP_DD_CONVERTER_MODE                                     1

/*  Identifies a special converter mode where source and sink formats
 *  are the same but postprocessing must applied. Therefore, Decode
 *  @rarrow Re-encode is necessary.
 */
#define ASM_POST_PROCESS_CONVERTER_MODE                               2


struct asm_stream_cmd_open_transcode_loopback_t {
	struct apr_hdr         hdr;
	u32                    mode_flags;
/* Mode Flags specifies the performance mode in which this stream
 * is to be opened.
 * Supported values{for bits 30 to 28}(stream_perf_mode flag)
 *
 * #ASM_LEGACY_STREAM_SESSION -- This mode ensures backward
 *       compatibility to the original behavior
 *       of ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK
 *
 * #ASM_LOW_LATENCY_STREAM_SESSION -- Opens a loopback session by using
 *  shortened buffers in low latency POPP
 *  - Recommendation: Do not enable high latency algorithms. They might
 *    negate the benefits of opening a low latency stream, and they
 *    might also suffer quality degradation from unexpected jitter.
 *  - This Low Latency mode is supported only for PCM In and PCM Out
 *    loopbacks. An error is returned if Low Latency mode is opened for
 *    other transcode loopback modes.
 *  - To configure this subfield, use
 *     ASM_BIT_MASK_STREAM_PERF_MODE_FLAG_IN_OPEN_TRANSCODE_LOOPBACK and
 *     ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_TRANSCODE_LOOPBACK.
 *
 * Supported values{for bits 6 to 3} (decoder-converter compatibility)
 * #ASM_CONVERTER_MODE_NONE (0x0) -- Default
 * #ASM_DDP_DD_CONVERTER_MODE (0x1)
 * #ASM_POST_PROCESS_CONVERTER_MODE (0x2)
 * 0x3-0xF -- Reserved for future use
 * - Use #ASM_BIT_MASK_DECODER_CONVERTER_FLAG and
 *        ASM_SHIFT_DECODER_CONVERTER_FLAG to set this bit
 * All other bits are reserved; clients must set them to 0.
 */

	u32                    src_format_id;
/* Specifies the media format of the input audio stream.
 *
 * Supported values
 * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2
 * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3
 * - #ASM_MEDIA_FMT_DTS
 * - #ASM_MEDIA_FMT_EAC3_DEC
 * - #ASM_MEDIA_FMT_EAC3
 * - #ASM_MEDIA_FMT_AC3_DEC
 * - #ASM_MEDIA_FMT_AC3
 */
	u32                    sink_format_id;
/* Specifies the media format of the output stream.
 *
 * Supported values
 * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2
 * - #ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V3
 * - #ASM_MEDIA_FMT_DTS (not supported in Low Latency mode)
 * - #ASM_MEDIA_FMT_EAC3_DEC (not supported in Low Latency mode)
 * - #ASM_MEDIA_FMT_EAC3 (not supported in Low Latency mode)
 * - #ASM_MEDIA_FMT_AC3_DEC (not supported in Low Latency mode)
 * - #ASM_MEDIA_FMT_AC3 (not supported in Low Latency mode)
 */

	u32                    audproc_topo_id;
/* Postprocessing topology ID, which specifies the topology (order of
 *        processing) of postprocessing algorithms.
 *
 * Supported values
 *    - #ASM_STREAM_POSTPROC_TOPO_ID_DEFAULT
 *    - #ASM_STREAM_POSTPROC_TOPO_ID_PEAKMETER
 *    - #ASM_STREAM_POSTPROC_TOPO_ID_MCH_PEAK_VOL
 *    - #ASM_STREAM_POSTPROC_TOPO_ID_NONE
 *  Topologies can be added through #ASM_CMD_ADD_TOPOLOGIES.
 *  This field is ignored for the Converter mode, in which no
 *  postprocessing is performed.
 */

	u16                    src_endpoint_type;
/* Specifies the source endpoint that provides the input samples.
 *
 * Supported values
 *  - 0 -- Tx device matrix or stream router (gateway to the hardware
 *    ports)
 *  - All other values are reserved
 *  Clients must set this field to 0. Otherwise, an error is returned.
 */

	u16                    sink_endpoint_type;
/*  Specifies the sink endpoint type.
 *
 *  Supported values
 *  - 0 -- Rx device matrix or stream router (gateway to the hardware
 *    ports)
 *  - All other values are reserved
 *   Clients must set this field to 0. Otherwise, an error is returned.
 */

	u16                    bits_per_sample;
/*   Number of bits per sample processed by the ASM modules.
 *   Supported values 16, 24
 */

	u16                    reserved;
/*   This field must be set to 0.
 */
} __packed;


#define ASM_STREAM_CMD_CLOSE             0x00010BCD
#define ASM_STREAM_CMD_FLUSH             0x00010BCE

+29 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <sound/control.h>
#include <sound/tlv.h>
#include <asm/dma.h>
#include <sound/q6audio-v2.h>

#include "msm-pcm-routing-v2.h"

@@ -65,6 +66,10 @@ static struct fe_dai_session_map session_map[LOOPBACK_SESSION_MAX] = {
	{ {}, NULL},
};

struct msm_pcm_pdata {
	int perf_mode;
};

static void stop_pcm(struct msm_pcm_loopback *pcm);
static int msm_pcm_loopback_get_session(struct snd_soc_pcm_runtime *rtd,
					struct msm_pcm_loopback **pcm);
@@ -233,6 +238,7 @@ static int msm_pcm_open(struct snd_pcm_substream *substream)
	struct msm_pcm_routing_evt event;
	struct asm_session_mtmx_strtr_param_window_v2_t asm_mtmx_strtr_window;
	uint32_t param_id;
	struct msm_pcm_pdata *pdata;

	ret =  msm_pcm_loopback_get_session(rtd, &pcm);
	if (ret)
@@ -258,6 +264,15 @@ static int msm_pcm_open(struct snd_pcm_substream *substream)
		if (pcm->audio_client != NULL)
			stop_pcm(pcm);

		pdata = (struct msm_pcm_pdata *)
			dev_get_drvdata(rtd->platform->dev);
		if (!pdata) {
			dev_err(rtd->platform->dev,
				"%s: platform data not populated\n", __func__);
			mutex_unlock(&pcm->lock);
			return -EINVAL;
		}

		pcm->audio_client = q6asm_audio_client_alloc(
				(app_cb)msm_pcm_loopback_event_handler, pcm);
		if (!pcm->audio_client) {
@@ -267,7 +282,7 @@ static int msm_pcm_open(struct snd_pcm_substream *substream)
			return -ENOMEM;
		}
		pcm->session_id = pcm->audio_client->session;
		pcm->audio_client->perf_mode = false;
		pcm->audio_client->perf_mode = pdata->perf_mode;
		ret = q6asm_open_loopback_v2(pcm->audio_client,
					     bits_per_sample);
		if (ret < 0) {
@@ -508,10 +523,23 @@ static struct snd_soc_platform_driver msm_soc_platform = {

static int msm_pcm_probe(struct platform_device *pdev)
{
	struct msm_pcm_pdata *pdata;

	dev_dbg(&pdev->dev, "%s: dev name %s\n",
		__func__, dev_name(&pdev->dev));

	pdata = kzalloc(sizeof(struct msm_pcm_pdata), GFP_KERNEL);
	if (!pdata)
		return -ENOMEM;

	if (of_property_read_bool(pdev->dev.of_node,
				"qcom,msm-pcm-loopback-low-latency"))
		pdata->perf_mode = LOW_LATENCY_PCM_MODE;
	else
		pdata->perf_mode = LEGACY_PCM_MODE;

	dev_set_drvdata(&pdev->dev, pdata);

	return snd_soc_register_platform(&pdev->dev,
				   &msm_soc_platform);
}
+63 −0
Original line number Diff line number Diff line
@@ -3999,6 +3999,57 @@ static const struct snd_kcontrol_new mmul8_mixer_controls[] = {
	msm_routing_put_audio_mixer),
};

static const struct snd_kcontrol_new mmul9_mixer_controls[] = {
	SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
	msm_routing_put_audio_mixer),
	SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
	msm_routing_put_audio_mixer),
	SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
	msm_routing_put_audio_mixer),
	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
	msm_routing_put_audio_mixer),
	SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
	msm_routing_put_audio_mixer),
	SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
	msm_routing_put_audio_mixer),
	SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
	msm_routing_put_audio_mixer),
	SOC_SINGLE_EXT("SLIM_6_TX", MSM_BACKEND_DAI_SLIMBUS_6_TX,
	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
	msm_routing_put_audio_mixer),
	SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0,
	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
	msm_routing_put_audio_mixer),
	SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1,
	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
	msm_routing_put_audio_mixer),
	SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2,
	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
	msm_routing_put_audio_mixer),
	SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3,
	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
	msm_routing_put_audio_mixer),
	SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0,
	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
	msm_routing_put_audio_mixer),
	SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1,
	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
	msm_routing_put_audio_mixer),
	SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2,
	MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
	msm_routing_put_audio_mixer),
	SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3,
	MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer,
	msm_routing_put_audio_mixer),
};

static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
	SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
	MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -7247,6 +7298,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
	mmul6_mixer_controls, ARRAY_SIZE(mmul6_mixer_controls)),
	SND_SOC_DAPM_MIXER("MultiMedia8 Mixer", SND_SOC_NOPM, 0, 0,
	mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)),
	SND_SOC_DAPM_MIXER("MultiMedia9 Mixer", SND_SOC_NOPM, 0, 0,
	mmul9_mixer_controls, ARRAY_SIZE(mmul9_mixer_controls)),
	SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
	auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
	SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -7972,6 +8025,15 @@ static const struct snd_soc_dapm_route intercon[] = {
	{"MultiMedia8 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
	{"MultiMedia8 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},

	{"MultiMedia9 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"},
	{"MultiMedia9 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"},
	{"MultiMedia9 Mixer", "TERT_TDM_TX_2", "TERT_TDM_TX_2"},
	{"MultiMedia9 Mixer", "TERT_TDM_TX_3", "TERT_TDM_TX_3"},
	{"MultiMedia9 Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
	{"MultiMedia9 Mixer", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"},
	{"MultiMedia9 Mixer", "QUAT_TDM_TX_2", "QUAT_TDM_TX_2"},
	{"MultiMedia9 Mixer", "QUAT_TDM_TX_3", "QUAT_TDM_TX_3"},

	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
	{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
@@ -8070,6 +8132,7 @@ static const struct snd_soc_dapm_route intercon[] = {
	{"MM_UL5", NULL, "MultiMedia5 Mixer"},
	{"MM_UL6", NULL, "MultiMedia6 Mixer"},
	{"MM_UL8", NULL, "MultiMedia8 Mixer"},
	{"MM_UL9", NULL, "MultiMedia9 Mixer"},

	{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
	{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+58 −20
Original line number Diff line number Diff line
@@ -1674,6 +1674,7 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
		case ASM_STREAM_CMD_OPEN_PUSH_MODE_READ:
		case ASM_STREAM_CMD_OPEN_READWRITE_V2:
		case ASM_STREAM_CMD_OPEN_LOOPBACK_V2:
		case ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK:
		case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
		case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
		case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
@@ -2819,7 +2820,6 @@ int q6asm_open_read_write_v2(struct audio_client *ac, uint32_t rd_format,
int q6asm_open_loopback_v2(struct audio_client *ac, uint16_t bits_per_sample)
{
	int rc = 0x00;
	struct asm_stream_cmd_open_loopback_v2 open;

	if (ac == NULL) {
		pr_err("%s: APR handle NULL\n", __func__);
@@ -2831,6 +2831,42 @@ int q6asm_open_loopback_v2(struct audio_client *ac, uint16_t bits_per_sample)
	}
	pr_debug("%s: session[%d]\n", __func__, ac->session);

	if (ac->perf_mode == LOW_LATENCY_PCM_MODE) {
		struct asm_stream_cmd_open_transcode_loopback_t open;

		q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
		atomic_set(&ac->cmd_state, -1);
		open.hdr.opcode = ASM_STREAM_CMD_OPEN_TRANSCODE_LOOPBACK;

		open.mode_flags = 0;
		open.src_endpoint_type = 0;
		open.sink_endpoint_type = 0;
		open.src_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
		open.sink_format_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
		/* source endpoint : matrix */
		open.audproc_topo_id = q6asm_get_asm_topology_cal();

		ac->app_type = q6asm_get_asm_app_type_cal();
		if (ac->perf_mode == LOW_LATENCY_PCM_MODE)
			open.mode_flags |= ASM_LOW_LATENCY_STREAM_SESSION;
		else
			open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
		ac->topology = open.audproc_topo_id;
		open.bits_per_sample = bits_per_sample;
		open.reserved = 0;
		pr_debug("%s: opening a transcode_loopback with mode_flags =[%d] session[%d]\n",
				__func__, open.mode_flags, ac->session);

		rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
		if (rc < 0) {
			pr_err("%s: open failed op[0x%x]rc[%d]\n",
					__func__, open.hdr.opcode, rc);
			rc = -EINVAL;
			goto fail_cmd;
		}
	} else {/*if(ac->perf_mode == LEGACY_PCM_MODE)*/
		struct asm_stream_cmd_open_loopback_v2 open;

		q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
		atomic_set(&ac->cmd_state, -1);
		open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK_V2;
@@ -2845,15 +2881,17 @@ int q6asm_open_loopback_v2(struct audio_client *ac, uint16_t bits_per_sample)
		ac->topology = open.postprocopo_id;
		open.bits_per_sample = bits_per_sample;
		open.reserved = 0;
		pr_debug("%s: opening a loopback_v2 with mode_flags =[%d] session[%d]\n",
				__func__, open.mode_flags, ac->session);

		rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
		if (rc < 0) {
		pr_err("%s: open failed op[0x%x]rc[%d]\n", __func__,
				open.hdr.opcode, rc);
			pr_err("%s: open failed op[0x%x]rc[%d]\n",
					__func__, open.hdr.opcode, rc);
			rc = -EINVAL;
			goto fail_cmd;
		}

	}
	rc = wait_event_timeout(ac->cmd_wait,
			(atomic_read(&ac->cmd_state) >= 0), 5*HZ);
	if (!rc) {