diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h index e8cef3f8341..b00cfc9576f 100644 --- a/include/sound/q6asm-v2.h +++ b/include/sound/q6asm-v2.h @@ -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 diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c index dc41948d219..f25f746922c 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c @@ -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, diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 537719fd019..6827ae1f583 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -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); diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h index 10be15088a3..f18f7249d69 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h @@ -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); diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index a31fdd2827e..631e9bd83b0 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -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--; } }