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

This commit is contained in:
Linux Build Service Account 2013-01-10 07:20:44 -08:00 committed by Gerrit - the friendly Code Review server
commit 887a9bbbb0
5 changed files with 192 additions and 61 deletions

View File

@ -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

View File

@ -97,6 +97,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)
{
@ -143,18 +162,33 @@ static void event_handler(uint32_t opcode,
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 @@ static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
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 @@ 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,
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,

View File

@ -41,6 +41,12 @@ struct msm_pcm_routing_bdai_data {
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 @@ 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} } },
/* 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 @@ void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
}
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 @@ void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode, int dspst_id,
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 @@ void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode, int dspst_id,
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 @@ 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);
}
@ -556,6 +587,7 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set)
{
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 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set)
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 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set)
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 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set)
(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 int msm_routing_set_srs_SS3D_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;
}
@ -3081,7 +3128,9 @@ static int msm_pcm_routing_close(struct snd_pcm_substream *substream)
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 @@ static int msm_pcm_routing_prepare(struct snd_pcm_substream *substream)
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 @@ 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 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 @@ static int msm_pcm_routing_prepare(struct snd_pcm_substream *substream)
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);
}

View File

@ -113,6 +113,10 @@ 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
@ -128,6 +132,15 @@ void msm_pcm_routing_reg_pseudo_stream(int fedai_id, bool perf_mode,
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);

View File

@ -220,7 +220,7 @@ int q6asm_audio_client_buf_free(unsigned int dir,
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 @@ void q6asm_audio_client_free(struct audio_client *ac)
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 @@ int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode)
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 @@ int q6asm_audio_client_buf_alloc(unsigned int dir,
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 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
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 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
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 @@ void *q6asm_is_cpu_buf_avail(int dir, struct audio_client *ac, uint32_t *size,
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 @@ int q6asm_is_dsp_buf_avail(int dir, struct audio_client *ac)
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 @@ 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;
@ -1716,6 +1725,9 @@ int q6asm_open_write(struct audio_client *ac, uint32_t format)
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 @@ int q6asm_read(struct audio_client *ac)
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 @@ int q6asm_read_nolock(struct audio_client *ac)
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 @@ int q6asm_read_nolock(struct audio_client *ac)
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 @@ int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
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 @@ int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
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 @@ 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) {
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 @@ 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--;
}
}