Merge "ASoC: msm: flush if prior and current backends rate not matching"
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index 6b4c17b..dcdd816 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -74,10 +74,12 @@
/* Enable Sample_Rate/Channel_Mode notification event from Decoder */
#define SR_CM_NOTIFY_ENABLE 0x0004
-#define ASYNC_IO_MODE 0x0002
-#define SYNC_IO_MODE 0x0001
-#define NO_TIMESTAMP 0xFF00
-#define SET_TIMESTAMP 0x0000
+#define TUN_WRITE_IO_MODE 0x0008 /* tunnel read write mode */
+#define TUN_READ_IO_MODE 0x0004 /* tunnel read write mode */
+#define ASYNC_IO_MODE 0x0002
+#define SYNC_IO_MODE 0x0001
+#define NO_TIMESTAMP 0xFF00
+#define SET_TIMESTAMP 0x0000
#define SOFT_PAUSE_ENABLE 1
#define SOFT_PAUSE_DISABLE 0
diff --git a/sound/soc/msm/msm-pcm-q6.c b/sound/soc/msm/msm-pcm-q6.c
index 74136dc..8e29b5c 100644
--- a/sound/soc/msm/msm-pcm-q6.c
+++ b/sound/soc/msm/msm-pcm-q6.c
@@ -97,6 +97,25 @@
.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)
{
@@ -143,18 +162,33 @@
pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
in_frame_info[token][0] = payload[2];
in_frame_info[token][1] = payload[3];
- 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))
- snd_pcm_period_elapsed(substream);
- if (atomic_read(&prtd->in_count) <= prtd->periods)
- atomic_inc(&prtd->in_count);
- wake_up(&the_locks.read_wait);
- if (prtd->mmap_flag
- && q6asm_is_cpu_buf_avail_nolock(OUT,
+
+ /* 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))
+ snd_pcm_period_elapsed(substream);
+ if (atomic_read(&prtd->in_count) <= prtd->periods)
+ 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,
&size, &idx))
- q6asm_read_nolock(prtd->audio_client);
+ 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: {
@@ -627,6 +661,7 @@
struct audio_buffer *buf;
int dir, ret;
int format = FORMAT_LINEAR_PCM;
+ struct msm_pcm_routing_evt event;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dir = IN;
@@ -650,10 +685,13 @@
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,
- prtd->audio_client->perf_mode,
- prtd->session_id, substream->stream);
- }
+ 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, event);
+ }
ret = q6asm_audio_client_buf_alloc_contiguous(dir,
prtd->audio_client,
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 8237d81..6cf74d5 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -41,6 +41,12 @@
bool perf_mode;
};
+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
@@ -242,25 +248,35 @@
/* 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} } },
/* PSEUDO */
- {INVALID_SESSION, INVALID_SESSION},
+ {{0, INVALID_SESSION, {NULL, NULL} },
+ {0, INVALID_SESSION, {NULL, NULL} } },
};
static uint8_t is_be_dai_extproc(int be_dai)
@@ -320,10 +336,12 @@
}
mutex_lock(&routing_lock);
+
if (enable)
- fe_dai_map[fedai_id][session_type] = dspst_id;
+ fe_dai_map[fedai_id][session_type].strm_id = dspst_id;
else
- fe_dai_map[fedai_id][session_type] = INVALID_SESSION;
+ fe_dai_map[fedai_id][session_type].strm_id = INVALID_SESSION;
+
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) &&
@@ -422,7 +440,7 @@
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;
/* re-enable EQ if active */
if (eq_data[fedai_id].enable)
msm_send_eq_values(fedai_id);
@@ -472,6 +490,19 @@
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_pseudo_stream(int fedai_id, int dspst_id)
{
@@ -530,8 +561,8 @@
}
}
- 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);
}
@@ -556,6 +587,7 @@
{
int session_type, path_type;
u32 channels;
+ struct msm_pcm_routing_fdai_data *fdai;
pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
@@ -582,11 +614,24 @@
voc_start_playback(set);
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 due 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 ((session_type == SESSION_TYPE_RX) &&
((channels == 1) || (channels == 2))
&& msm_bedais[reg].perf_mode) {
@@ -614,7 +659,7 @@
msm_pcm_routing_build_matrix(val,
- fe_dai_map[val][session_type], path_type);
+ fdai->strm_id, path_type);
srs_port_id = msm_bedais[reg].port_id;
srs_send_params(srs_port_id, 1, 0);
}
@@ -623,11 +668,13 @@
(msm_bedais[reg].port_id == VOICE_PLAYBACK_TX))
voc_start_playback(set);
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) {
+ fdai->be_srate = msm_bedais[reg].sample_rate;
adm_close(msm_bedais[reg].port_id);
msm_pcm_routing_build_matrix(val,
- fe_dai_map[val][session_type], path_type);
+ fdai->strm_id, path_type);
}
}
if ((msm_bedais[reg].port_id == VOICE_RECORD_RX)
@@ -1212,12 +1259,12 @@
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;
}
@@ -3081,7 +3128,9 @@
mutex_lock(&routing_lock);
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);
srs_port_id = -1;
}
@@ -3104,6 +3153,7 @@
struct msm_pcm_routing_bdai_data *bedai;
u32 channels;
bool playback, capture;
+ 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);
@@ -3135,7 +3185,21 @@
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 due 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->port_id == PSEUDOPORT_01) {
adm_multi_ch_copp_pseudo_open_v3(bedai->port_id,
@@ -3169,7 +3233,7 @@
DEFAULT_COPP_TOPOLOGY);
msm_pcm_routing_build_matrix(i,
- fe_dai_map[i][session_type], path_type);
+ fdai->strm_id, path_type);
srs_port_id = bedai->port_id;
srs_send_params(srs_port_id, 1, 0);
}
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index 0c0d3b4..b571483 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -113,6 +113,10 @@
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
@@ -128,6 +132,15 @@
void msm_pcm_routing_dereg_pseudo_stream(int fedai_id, int dspst_id);
+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 lpa_set_volume(unsigned volume);
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 52e481a..8fd5840 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -220,7 +220,7 @@
int rc = 0;
pr_debug("%s: Session id %d\n", __func__, ac->session);
mutex_lock(&ac->cmd_lock);
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
port = &ac->port[dir];
if (!port->buf) {
mutex_unlock(&ac->cmd_lock);
@@ -351,7 +351,7 @@
if (!ac || !ac->session)
return;
pr_debug("%s: Session id %d\n", __func__, ac->session);
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
port = &ac->port[loopcnt];
if (!port->buf)
@@ -386,14 +386,20 @@
pr_err("%s APR handle NULL\n", __func__);
return -EINVAL;
}
- if ((mode == ASYNC_IO_MODE) || (mode == SYNC_IO_MODE)) {
- ac->io_mode = mode;
- pr_debug("%s:Set Mode to %d\n", __func__, ac->io_mode);
- return 0;
+
+ if (mode == ASYNC_IO_MODE) {
+ ac->io_mode &= ~SYNC_IO_MODE;
+ ac->io_mode |= ASYNC_IO_MODE;
+ } else if (mode == SYNC_IO_MODE) {
+ ac->io_mode &= ~ASYNC_IO_MODE;
+ ac->io_mode |= SYNC_IO_MODE;
} else {
pr_err("%s:Not an valid IO Mode:%d\n", __func__, ac->io_mode);
return -EINVAL;
}
+
+ pr_debug("%s:Set Mode to %d\n", __func__, ac->io_mode);
+ return 0;
}
struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv)
@@ -498,7 +504,7 @@
if (ac->session <= 0 || ac->session > 8)
goto fail;
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
if (ac->port[dir].buf) {
pr_debug("%s: buffer already allocated\n", __func__);
return 0;
@@ -942,7 +948,7 @@
pr_debug("%s: Rxed opcode[0x%x] status[0x%x] token[%d]",
__func__, payload[0], payload[1],
data->token);
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
if (port->buf == NULL) {
pr_err("%s: Unexpected Write Done\n",
__func__);
@@ -1024,7 +1030,7 @@
if (in_enable_flag)
in_cont_index++;
#endif
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
if (port->buf == NULL) {
pr_err("%s: Unexpected Write Done\n", __func__);
return -EINVAL;
@@ -1203,7 +1209,7 @@
if (!ac || ((dir != IN) && (dir != OUT)))
return NULL;
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
port = &ac->port[dir];
mutex_lock(&port->lock);
@@ -1297,7 +1303,7 @@
if (!ac || (dir != OUT))
return ret;
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
port = &ac->port[dir];
mutex_lock(&port->lock);
@@ -1430,6 +1436,9 @@
rc);
goto fail_cmd;
}
+
+ ac->io_mode |= TUN_READ_IO_MODE;
+
return 0;
fail_cmd:
return -EINVAL;
@@ -1716,6 +1725,9 @@
pr_err("%s: format = %x not supported\n", __func__, format);
goto fail_cmd;
}
+
+ ac->io_mode |= TUN_WRITE_IO_MODE;
+
return 0;
fail_cmd:
return -EINVAL;
@@ -3440,7 +3452,7 @@
pr_err("APR handle NULL\n");
return -EINVAL;
}
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
port = &ac->port[OUT];
q6asm_add_hdr(ac, &read.hdr, sizeof(read), FALSE);
@@ -3492,7 +3504,7 @@
pr_err("APR handle NULL\n");
return -EINVAL;
}
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
port = &ac->port[OUT];
q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
@@ -3516,7 +3528,7 @@
read.hdr.token = port->dsp_buf;
port->dsp_buf = (port->dsp_buf + 1) & (port->max_buf_cnt - 1);
- pr_debug("%s:buf add[0x%x] token[%d] uid[%d]\n", __func__,
+ pr_info("%s:buf add[0x%x] token[%d] uid[%d]\n", __func__,
read.buf_add,
read.hdr.token,
read.uid);
@@ -3677,7 +3689,7 @@
return -EINVAL;
}
pr_debug("%s: session[%d] len=%d", __func__, ac->session, len);
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
port = &ac->port[IN];
q6asm_add_hdr(ac, &write.hdr, sizeof(write),
@@ -3759,7 +3771,7 @@
return -EINVAL;
}
pr_debug("%s: session[%d] len=%d", __func__, ac->session, len);
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
port = &ac->port[IN];
q6asm_add_hdr_async(ac, &write.hdr, sizeof(write),
@@ -3961,9 +3973,11 @@
{
int cnt = 0;
int loopcnt = 0;
+ int used;
struct audio_port_data *port = NULL;
- if (ac->io_mode == SYNC_IO_MODE) {
+ 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];
@@ -3973,7 +3987,7 @@
while (cnt >= 0) {
if (!port->buf)
continue;
- port->buf[cnt].used = 1;
+ port->buf[cnt].used = used;
cnt--;
}
}