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

Commit 444ef0c3 authored by Damir Didjusto's avatar Damir Didjusto Committed by Gerrit - the friendly Code Review server
Browse files

ASoC: msm: flush if prior and current backends rate not matching



It is found that during device switch from one backend
with one sample rate to another backend with another sample rate
the command to QDSP6 ADM which maps audio stream session to a
particular backend would not get carried out until pending
data of audio stream session from previous backend is either
read out or flushed. This scenario occurs when application
stops providing more buffers to retrieve captured data.
Remedy is to flush upon detection of rate mismatching.

Change-Id: I8284dd076af4c625268a9c6a5f45c3f6146e5c14
Signed-off-by: default avatarDamir Didjusto <damird@codeaurora.org>
Signed-off-by: default avatarVimal Puthanveed <vimalp@codeaurora.org>
parent de061d01
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -67,6 +67,8 @@
/* Enable Sample_Rate/Channel_Mode notification event from Decoder */
#define SR_CM_NOTIFY_ENABLE	0x0004

#define TUN_WRITE_IO_MODE 0x0008 /* tunnel read write mode */
#define TUN_READ_IO_MODE  0x0004 /* tunnel read write mode */
#define SYNC_IO_MODE	0x0001
#define ASYNC_IO_MODE	0x0002
#define COMPRESSED_IO	0x0040
+51 −14
Original line number Diff line number Diff line
@@ -109,6 +109,25 @@ static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
	.mask = 0,
};

static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
					void *priv_data)
{
	struct msm_audio *prtd = priv_data;

	BUG_ON(!prtd);

	pr_debug("%s: event %x\n", __func__, event);

	switch (event) {
	case MSM_PCM_RT_EVT_BUF_RECFG:
		q6asm_cmd(prtd->audio_client, CMD_PAUSE);
		q6asm_cmd(prtd->audio_client, CMD_FLUSH);
		q6asm_run(prtd->audio_client, 0, 0, 0);
	default:
		break;
	}
}

static void event_handler(uint32_t opcode,
		uint32_t token, uint32_t *payload, void *priv)
{
@@ -151,6 +170,8 @@ static void event_handler(uint32_t opcode,
		pr_debug("token = 0x%08x\n", token);
		in_frame_info[token][0] = payload[4];
		in_frame_info[token][1] = payload[5];
		/* assume data size = 0 during flushing */
		if (in_frame_info[token][0]) {
			prtd->pcm_irq_pos += in_frame_info[token][0];
			pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
			if (atomic_read(&prtd->start))
@@ -159,11 +180,23 @@ static void event_handler(uint32_t opcode,
				atomic_inc(&prtd->in_count);
			wake_up(&the_locks.read_wait);
			if (prtd->mmap_flag &&
		    q6asm_is_cpu_buf_avail_nolock(OUT, prtd->audio_client,
			    q6asm_is_cpu_buf_avail_nolock(OUT,
				prtd->audio_client,
				&size, &idx) &&
			    (substream->runtime->status->state ==
			     SNDRV_PCM_STATE_RUNNING))
				q6asm_read_nolock(prtd->audio_client);
		} else {
			pr_debug("%s: reclaim flushed buf in_count %x\n",
				__func__, atomic_read(&prtd->in_count));
			atomic_inc(&prtd->in_count);
			if (atomic_read(&prtd->in_count) == prtd->periods) {
				pr_info("%s: reclaimed all bufs\n", __func__);
				if (atomic_read(&prtd->start))
					snd_pcm_period_elapsed(substream);
				wake_up(&the_locks.read_wait);
			}
		}
		break;
	}
	case APR_BASIC_RSP_RESULT: {
@@ -682,6 +715,7 @@ static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
	int dir, ret;
	struct msm_plat_data *pdata;
	uint16_t bits_per_sample = 16;
	struct msm_pcm_routing_evt event;

	pdata = (struct msm_plat_data *)
				dev_get_drvdata(soc_prtd->platform->dev);
@@ -738,9 +772,12 @@ static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
		pr_debug("%s: session ID %d\n",
				__func__, prtd->audio_client->session);
		prtd->session_id = prtd->audio_client->session;
		msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
		event.event_func = msm_pcm_route_event_handler;
		event.priv_data = (void *) prtd;
		msm_pcm_routing_reg_phy_stream_v2(soc_prtd->dai_link->be_id,
				prtd->audio_client->perf_mode,
				prtd->session_id, substream->stream);
				prtd->session_id, substream->stream,
				event);
	}

	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
+88 −27
Original line number Diff line number Diff line
@@ -50,6 +50,12 @@ struct msm_pcm_routing_bdai_data {
	unsigned int  format;
};

struct msm_pcm_routing_fdai_data {
	u16 be_srate; /* track prior backend sample rate for flushing purpose */
	int strm_id; /* ASM stream ID */
	struct msm_pcm_routing_evt event_info;
};

#define INVALID_SESSION -1
#define SESSION_TYPE_RX 0
#define SESSION_TYPE_TX 1
@@ -252,25 +258,35 @@ static struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = {


/* Track ASM playback & capture sessions of DAI */
static int fe_dai_map[MSM_FRONTEND_DAI_MM_SIZE][2] = {
static struct msm_pcm_routing_fdai_data
	fe_dai_map[MSM_FRONTEND_DAI_MM_SIZE][2] = {
	/* MULTIMEDIA1 */
	{INVALID_SESSION, INVALID_SESSION},
	{{0, INVALID_SESSION, {NULL, NULL} },
	{0, INVALID_SESSION, {NULL, NULL} } },
	/* MULTIMEDIA2 */
	{INVALID_SESSION, INVALID_SESSION},
	{{0, INVALID_SESSION, {NULL, NULL} },
	{0, INVALID_SESSION, {NULL, NULL} } },
	/* MULTIMEDIA3 */
	{INVALID_SESSION, INVALID_SESSION},
	{{0, INVALID_SESSION, {NULL, NULL} },
	{0, INVALID_SESSION, {NULL, NULL} } },
	/* MULTIMEDIA4 */
	{INVALID_SESSION, INVALID_SESSION},
	{{0, INVALID_SESSION, {NULL, NULL} },
	{0, INVALID_SESSION,  {NULL, NULL} } },
	/* MULTIMEDIA5 */
	{INVALID_SESSION, INVALID_SESSION},
	{{0, INVALID_SESSION, {NULL, NULL} },
	{0, INVALID_SESSION, {NULL, NULL} } },
	/* MULTIMEDIA6 */
	{INVALID_SESSION, INVALID_SESSION},
	{{0, INVALID_SESSION, {NULL, NULL} },
	{0, INVALID_SESSION, {NULL, NULL} } },
	/* MULTIMEDIA7*/
	{INVALID_SESSION, INVALID_SESSION},
	{{0, INVALID_SESSION, {NULL, NULL} },
	{0, INVALID_SESSION, {NULL, NULL} } },
	/* MULTIMEDIA8 */
	{INVALID_SESSION, INVALID_SESSION},
	{{0, INVALID_SESSION, {NULL, NULL} },
	{0, INVALID_SESSION, {NULL, NULL} } },
	/* MULTIMEDIA9 */
	{INVALID_SESSION, INVALID_SESSION},
	{{0, INVALID_SESSION, {NULL, NULL} },
	{0, INVALID_SESSION, {NULL, NULL} } },
};

static int send_stereo_to_custom_stereo_cmd(int port_id,
@@ -411,7 +427,7 @@ void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,

	mutex_lock(&routing_lock);

	fe_dai_map[fedai_id][session_type] = dspst_id;
	fe_dai_map[fedai_id][session_type].strm_id = dspst_id;
	for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
		if (!is_be_dai_extproc(i) &&
		    (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
@@ -454,7 +470,7 @@ void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode,
	mutex_lock(&routing_lock);

	payload.num_copps = 0; /* only RX needs to use payload */
	fe_dai_map[fedai_id][session_type] = dspst_id;
	fe_dai_map[fedai_id][session_type].strm_id = dspst_id;
	fe_dai_perf_mode[fedai_id][session_type] = perf_mode;

	/* re-enable EQ if active */
@@ -525,6 +541,19 @@ void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode,
	mutex_unlock(&routing_lock);
}

void msm_pcm_routing_reg_phy_stream_v2(int fedai_id, bool perf_mode,
				       int dspst_id, int stream_type,
				       struct msm_pcm_routing_evt event_info)
{
	msm_pcm_routing_reg_phy_stream(fedai_id, perf_mode, dspst_id,
				       stream_type);

	if (stream_type == SNDRV_PCM_STREAM_PLAYBACK)
		fe_dai_map[fedai_id][SESSION_TYPE_RX].event_info = event_info;
	else
		fe_dai_map[fedai_id][SESSION_TYPE_TX].event_info = event_info;
}

void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type)
{
	int i, port_type, session_type, path_type, topology;
@@ -560,8 +589,8 @@ void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type)
		}
	}

	fe_dai_map[fedai_id][session_type] = INVALID_SESSION;

	fe_dai_map[fedai_id][session_type].strm_id = INVALID_SESSION;
	fe_dai_map[fedai_id][session_type].be_srate = 0;
	mutex_unlock(&routing_lock);
}

@@ -587,6 +616,7 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set)
	int session_type, path_type, port_id, topology;
	u32 channels;
	uint16_t bits_per_sample = 16;
	struct msm_pcm_routing_fdai_data *fdai;

	pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);

@@ -613,10 +643,23 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set)
			(msm_bedais[reg].port_id == VOICE2_PLAYBACK_TX)))
			voc_start_playback(set, msm_bedais[reg].port_id);
		set_bit(val, &msm_bedais[reg].fe_sessions);
		if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
		fdai = &fe_dai_map[val][session_type];
		if (msm_bedais[reg].active && fdai->strm_id !=
			INVALID_SESSION) {

			channels = msm_bedais[reg].channel;
			if (session_type == SESSION_TYPE_TX &&
			    fdai->be_srate &&
			    (fdai->be_srate != msm_bedais[reg].sample_rate)) {
				pr_debug("%s: flush strm %d diff BE rates\n",
					__func__, fdai->strm_id);

				if (fdai->event_info.event_func)
					fdai->event_info.event_func(
						MSM_PCM_RT_EVT_BUF_RECFG,
						fdai->event_info.priv_data);
				fdai->be_srate = 0; /* might not need it */
			}
			if (msm_bedais[reg].format == SNDRV_PCM_FORMAT_S24_LE)
				bits_per_sample = 24;

@@ -640,7 +683,7 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set)
				bits_per_sample);

			msm_pcm_routing_build_matrix(val,
				fe_dai_map[val][session_type], path_type,
				fdai->strm_id, path_type,
				fe_dai_perf_mode[val][session_type]);
			port_id = srs_port_id = msm_bedais[reg].port_id;
			srs_send_params(srs_port_id, 1, 0);
@@ -656,7 +699,8 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set)
			(msm_bedais[reg].port_id == VOICE2_PLAYBACK_TX)))
			voc_start_playback(set, msm_bedais[reg].port_id);
		clear_bit(val, &msm_bedais[reg].fe_sessions);
		if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
		fdai = &fe_dai_map[val][session_type];
		if (msm_bedais[reg].active && fdai->strm_id !=
			INVALID_SESSION) {
			adm_close(msm_bedais[reg].port_id,
				  fe_dai_perf_mode[val][session_type]);
@@ -664,7 +708,7 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set)
			    (fe_dai_perf_mode[val][session_type] == false))
				dolby_dap_deinit(msm_bedais[reg].port_id);
			msm_pcm_routing_build_matrix(val,
				fe_dai_map[val][session_type], path_type,
				fdai->strm_id, path_type,
				fe_dai_perf_mode[val][session_type]);
		}
	}
@@ -1287,12 +1331,12 @@ static int msm_routing_set_srs_trumedia_control_HDMI(
static void msm_send_eq_values(int eq_idx)
{
	int result;
	struct audio_client *ac =
		q6asm_get_audio_client(fe_dai_map[eq_idx][SESSION_TYPE_RX]);
	struct audio_client *ac = q6asm_get_audio_client(
				  fe_dai_map[eq_idx][SESSION_TYPE_RX].strm_id);

	if (ac == NULL) {
		pr_err("%s: Could not get audio client for session: %d\n",
		      __func__, fe_dai_map[eq_idx][SESSION_TYPE_RX]);
		      __func__, fe_dai_map[eq_idx][SESSION_TYPE_RX].strm_id);
		goto done;
	}

@@ -2892,7 +2936,8 @@ static int msm_routing_put_stereo_to_custom_stereo_control(
				MSM_FRONTEND_DAI_MM_SIZE) {
				if (fe_dai_perf_mode[i][SESSION_TYPE_RX])
					goto skip_send_custom_stereo;
				session_id = fe_dai_map[i][SESSION_TYPE_RX];
				session_id =
					fe_dai_map[i][SESSION_TYPE_RX].strm_id;
				if (is_custom_stereo_on) {
					rc = send_stereo_to_custom_stereo_cmd(
						msm_bedais[be_index].port_id,
@@ -4116,7 +4161,9 @@ static int msm_pcm_routing_close(struct snd_pcm_substream *substream)
	mutex_lock(&routing_lock);
	topology = get_topology(path_type);
	for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
		if (fe_dai_map[i][session_type] != INVALID_SESSION) {
		if (fe_dai_map[i][session_type].strm_id != INVALID_SESSION) {
			fe_dai_map[i][session_type].be_srate =
				bedai->sample_rate;
			adm_close(bedai->port_id,
				  fe_dai_perf_mode[i][session_type]);
			srs_port_id = -1;
@@ -4143,6 +4190,7 @@ static int msm_pcm_routing_prepare(struct snd_pcm_substream *substream)
	u32 channels;
	bool playback, capture;
	uint16_t bits_per_sample = 16;
	struct msm_pcm_routing_fdai_data *fdai;

	if (be_id >= MSM_BACKEND_DAI_MAX) {
		pr_err("%s: unexpected be_id %d\n", __func__, be_id);
@@ -4174,8 +4222,21 @@ static int msm_pcm_routing_prepare(struct snd_pcm_substream *substream)
	capture = substream->stream == SNDRV_PCM_STREAM_CAPTURE;

	for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
		if (fe_dai_map[i][session_type] != INVALID_SESSION) {

		fdai = &fe_dai_map[i][session_type];
		if (fdai->strm_id != INVALID_SESSION) {
			if (session_type == SESSION_TYPE_TX &&
			    fdai->be_srate &&
			    (fdai->be_srate != bedai->sample_rate)) {
				pr_debug("%s: flush strm %d diff BE rates\n",
					__func__,
					fdai->strm_id);

				if (fdai->event_info.event_func)
					fdai->event_info.event_func(
						MSM_PCM_RT_EVT_BUF_RECFG,
						fdai->event_info.priv_data);
				fdai->be_srate = 0; /* might not need it */
			}
			channels = bedai->channel;
			if (bedai->format == SNDRV_PCM_FORMAT_S24_LE)
				bits_per_sample = 24;
@@ -4201,7 +4262,7 @@ static int msm_pcm_routing_prepare(struct snd_pcm_substream *substream)
			}

			msm_pcm_routing_build_matrix(i,
				fe_dai_map[i][session_type], path_type,
				fdai->strm_id, path_type,
				fe_dai_perf_mode[i][session_type]);
			port_id = srs_port_id = bedai->port_id;
			srs_send_params(srs_port_id, 1, 0);
+14 −0
Original line number Diff line number Diff line
@@ -137,6 +137,11 @@ enum {
	MSM_BACKEND_DAI_MAX,
};

enum msm_pcm_routing_event {
	MSM_PCM_RT_EVT_BUF_RECFG,
	MSM_PCM_RT_EVT_MAX,
};

/* dai_id: front-end ID,
 * dspst_id:  DSP audio stream ID
 * stream_type: playback or capture
@@ -146,6 +151,15 @@ void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode, int dspst_id,
void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
		int stream_type);

struct msm_pcm_routing_evt {
	void (*event_func)(enum msm_pcm_routing_event, void *);
	void *priv_data;
};

void msm_pcm_routing_reg_phy_stream_v2(int fedai_id, bool perf_mode,
				       int dspst_id, int stream_type,
				       struct msm_pcm_routing_evt event_info);

void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type);

int msm_routing_check_backend_enabled(int fedai_id);
+5 −1
Original line number Diff line number Diff line
@@ -1744,6 +1744,7 @@ static int __q6asm_open_read(struct audio_client *ac,
			rc);
		goto fail_cmd;
	}
	ac->io_mode |= TUN_READ_IO_MODE;
	return 0;
fail_cmd:
	return -EINVAL;
@@ -1837,6 +1838,7 @@ static int __q6asm_open_write(struct audio_client *ac, uint32_t format,
			rc);
		goto fail_cmd;
	}
	ac->io_mode |= TUN_WRITE_IO_MODE;
	return 0;
fail_cmd:
	return -EINVAL;
@@ -4287,9 +4289,11 @@ static void q6asm_reset_buf_state(struct audio_client *ac)
{
	int cnt = 0;
	int loopcnt = 0;
	int used;
	struct audio_port_data *port = NULL;

	if (ac->io_mode & SYNC_IO_MODE) {
		used = (ac->io_mode & TUN_WRITE_IO_MODE ? 1 : 0);
		mutex_lock(&ac->cmd_lock);
		for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
			port = &ac->port[loopcnt];
@@ -4299,7 +4303,7 @@ static void q6asm_reset_buf_state(struct audio_client *ac)
			while (cnt >= 0) {
				if (!port->buf)
					continue;
				port->buf[cnt].used = 1;
				port->buf[cnt].used = used;
				cnt--;
			}
		}