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

This commit is contained in:
Linux Build Service Account
2013-12-16 15:04:27 -08:00
committed by Gerrit - the friendly Code Review server
5 changed files with 154 additions and 38 deletions
+2
View File
@@ -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
+48 -12
View File
@@ -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,18 +170,31 @@ 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];
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: {
@@ -681,6 +713,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);
@@ -737,9 +770,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,
+85 -25
View File
@@ -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
@@ -250,25 +256,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},
/* MULTIMEDIA7 */
{INVALID_SESSION, INVALID_SESSION},
{{0, INVALID_SESSION, {NULL, NULL} },
{0, INVALID_SESSION, {NULL, NULL} } },
/* MULTIMEDIA7*/
{{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} } },
};
/* Track performance mode of all front-end multimedia sessions.
@@ -334,7 +350,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) &&
@@ -376,7 +392,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 */
@@ -435,6 +451,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;
@@ -470,8 +499,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);
}
@@ -497,6 +526,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);
@@ -523,10 +553,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;
@@ -550,7 +593,7 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set)
topology, false, 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);
@@ -566,7 +609,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]);
@@ -574,7 +618,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]);
}
}
@@ -1203,12 +1247,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;
}
@@ -3881,7 +3925,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;
@@ -3908,6 +3954,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);
@@ -3939,8 +3986,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;
@@ -3967,7 +4027,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);
@@ -133,6 +133,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
@@ -142,6 +147,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
View File
@@ -1745,6 +1745,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;
@@ -1838,6 +1839,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;
@@ -4261,9 +4263,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];
@@ -4273,7 +4277,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--;
}
}