1818#include "q6apm.h"
1919
2020#define DRV_NAME "q6apm-dai"
21+ #define POS_BUFFER_BYTES 4096
2122
2223#define PLAYBACK_MIN_NUM_PERIODS 2
2324#define PLAYBACK_MAX_NUM_PERIODS 8
@@ -62,8 +63,12 @@ struct q6apm_dai_rtd {
6263 struct snd_codec codec ;
6364 struct snd_compr_params codec_param ;
6465 struct snd_dma_buffer dma_buffer ;
66+ struct sh_mem_pull_push_mode_position_buffer * pos_buffer ;
67+ uint32_t last_pos_index ;
6568 phys_addr_t phys ;
69+ phys_addr_t pos_phys ;
6670 unsigned int pcm_size ;
71+ unsigned int push_pull_size ;
6772 unsigned int pcm_count ;
6873 unsigned int periods ;
6974 uint64_t bytes_sent ;
@@ -128,6 +133,9 @@ static void event_handler(uint32_t opcode, uint32_t token, void *payload, void *
128133 struct snd_pcm_substream * substream = prtd -> substream ;
129134
130135 switch (opcode ) {
136+ case APM_CLIENT_EVENT_WATERMARK_EVENT :
137+ snd_pcm_period_elapsed (substream );
138+ break ;
131139 case APM_CLIENT_EVENT_CMD_EOS_DONE :
132140 prtd -> state = Q6APM_STREAM_STOPPED ;
133141 break ;
@@ -234,24 +242,47 @@ static int q6apm_dai_prepare(struct snd_soc_component *component,
234242 q6apm_free_fragments (prtd -> graph , substream -> stream );
235243 }
236244
245+ prtd -> last_pos_index = 0 ;
237246 prtd -> pcm_count = snd_pcm_lib_period_bytes (substream );
238- /* rate and channels are sent to audio driver */
239- ret = q6apm_graph_media_format_shmem (prtd -> graph , & cfg );
240- if (ret < 0 ) {
241- dev_err (dev , "%s: q6apm_open_write failed\n" , __func__ );
242- return ret ;
247+ if (q6apm_is_graph_in_push_pull_mode (prtd -> graph )) {
248+ if (prtd -> pcm_size != prtd -> push_pull_size ) {
249+ ret = q6apm_push_pull_config (prtd -> graph , prtd -> phys , prtd -> pos_phys ,
250+ prtd -> pcm_size );
251+ if (ret < 0 ) {
252+ dev_err (dev , "Push/Pull config failed rc = %d\n" , ret );
253+ return ret ;
254+ }
255+
256+ ret = q6apm_register_watermark_event (prtd -> graph ,
257+ prtd -> pcm_size / prtd -> periods ,
258+ prtd -> periods );
259+ if (ret < 0 ) {
260+ dev_err (dev , "WaterMark event config failed rc = %d\n" , ret );
261+ return ret ;
262+ }
263+ prtd -> push_pull_size = prtd -> pcm_size ;
264+ }
265+ } else {
266+ ret = q6apm_alloc_fragments (prtd -> graph , substream -> stream , prtd -> phys ,
267+ (prtd -> pcm_size / prtd -> periods ), prtd -> periods );
268+ if (ret < 0 ) {
269+ dev_err (dev , "Audio Start: Buffer Allocation failed rc = %d\n" , ret );
270+ return ret ;
271+ }
272+
243273 }
244274
245275 ret = q6apm_graph_media_format_pcm (prtd -> graph , & cfg );
246- if (ret < 0 )
276+ if (ret < 0 ) {
247277 dev_err (dev , "%s: CMD Format block failed\n" , __func__ );
278+ return ret ;
279+ }
248280
249- ret = q6apm_alloc_fragments (prtd -> graph , substream -> stream , prtd -> phys ,
250- (prtd -> pcm_size / prtd -> periods ), prtd -> periods );
251-
281+ /* rate and channels are sent to audio driver */
282+ ret = q6apm_graph_media_format_shmem (prtd -> graph , & cfg );
252283 if (ret < 0 ) {
253- dev_err (dev , "Audio Start: Buffer Allocation failed rc = %d\n" , ret );
254- return - ENOMEM ;
284+ dev_err (dev , "Failed to set media format %d\n" , ret );
285+ return ret ;
255286 }
256287
257288 ret = q6apm_graph_prepare (prtd -> graph );
@@ -265,13 +296,13 @@ static int q6apm_dai_prepare(struct snd_soc_component *component,
265296 dev_err (dev , "Failed to Start Graph %d\n" , ret );
266297 return ret ;
267298 }
268-
269- if (substream -> stream == SNDRV_PCM_STREAM_CAPTURE ) {
270- int i ;
271- /* Queue the buffers for Capture ONLY after graph is started */
272- for (i = 0 ; i < runtime -> periods ; i ++ )
273- q6apm_read (prtd -> graph );
274-
299+ if (! q6apm_is_graph_in_push_pull_mode ( prtd -> graph )) {
300+ if (substream -> stream == SNDRV_PCM_STREAM_CAPTURE ) {
301+ int i ;
302+ /* Queue the buffers for Capture ONLY after graph is started */
303+ for (i = 0 ; i < runtime -> periods ; i ++ )
304+ q6apm_read (prtd -> graph );
305+ }
275306 }
276307
277308 /* Now that graph as been prepared and started update the internal state accordingly */
@@ -286,6 +317,9 @@ static int q6apm_dai_ack(struct snd_soc_component *component, struct snd_pcm_sub
286317 struct q6apm_dai_rtd * prtd = runtime -> private_data ;
287318 int i , ret = 0 , avail_periods ;
288319
320+ if (q6apm_is_graph_in_push_pull_mode (prtd -> graph ))
321+ return 0 ;
322+
289323 if (substream -> stream == SNDRV_PCM_STREAM_PLAYBACK ) {
290324 avail_periods = (runtime -> control -> appl_ptr - prtd -> queue_ptr )/runtime -> period_size ;
291325 for (i = 0 ; i < avail_periods ; i ++ ) {
@@ -317,6 +351,7 @@ static int q6apm_dai_trigger(struct snd_soc_component *component,
317351 /* TODO support be handled via SoftPause Module */
318352 prtd -> state = Q6APM_STREAM_STOPPED ;
319353 prtd -> queue_ptr = 0 ;
354+ prtd -> last_pos_index = 0 ;
320355 break ;
321356 case SNDRV_PCM_TRIGGER_SUSPEND :
322357 case SNDRV_PCM_TRIGGER_PAUSE_PUSH :
@@ -402,6 +437,14 @@ static int q6apm_dai_open(struct snd_soc_component *component,
402437 else
403438 prtd -> phys = substream -> dma_buffer .addr | (pdata -> sid << 32 );
404439
440+ if (q6apm_is_graph_in_push_pull_mode (prtd -> graph )) {
441+ void * pos_buffer ;
442+
443+ prtd -> pos_phys = prtd -> phys + BUFFER_BYTES_MAX ;
444+ pos_buffer = (void * )(substream -> dma_buffer .area + BUFFER_BYTES_MAX );
445+ prtd -> pos_buffer = (struct sh_mem_pull_push_mode_position_buffer * )(pos_buffer );
446+ }
447+
405448 return 0 ;
406449err :
407450 kfree (prtd );
@@ -436,6 +479,25 @@ static snd_pcm_uframes_t q6apm_dai_pointer(struct snd_soc_component *component,
436479 struct q6apm_dai_rtd * prtd = runtime -> private_data ;
437480 snd_pcm_uframes_t ptr ;
438481
482+ if (q6apm_is_graph_in_push_pull_mode (prtd -> graph )) {
483+ int retries = 10 ;
484+ uint32_t index , fc1 , fc2 ;
485+
486+ /* index is valid if frame_counter does not change while reading. */
487+ do {
488+ fc1 = READ_ONCE (prtd -> pos_buffer -> frame_counter );
489+ index = READ_ONCE (prtd -> pos_buffer -> index );
490+ fc2 = READ_ONCE (prtd -> pos_buffer -> frame_counter );
491+ } while (fc1 != fc2 && -- retries );
492+
493+ if (fc1 != fc2 )
494+ index = prtd -> last_pos_index ;
495+ else
496+ prtd -> last_pos_index = index ;
497+
498+ ptr = bytes_to_frames (runtime , index );
499+ return ptr ;
500+ }
439501 ptr = q6apm_get_hw_pointer (prtd -> graph , substream -> stream ) * runtime -> period_size ;
440502 if (ptr )
441503 return ptr - 1 ;
@@ -468,7 +530,8 @@ static int q6apm_dai_hw_params(struct snd_soc_component *component,
468530}
469531
470532static int q6apm_dai_memory_map (struct snd_soc_component * component ,
471- struct snd_pcm_substream * substream , int graph_id )
533+ struct snd_pcm_substream * substream ,
534+ int graph_id , bool is_push_pull )
472535{
473536 struct q6apm_dai_data * pdata ;
474537 struct device * dev = component -> dev ;
@@ -490,6 +553,19 @@ static int q6apm_dai_memory_map(struct snd_soc_component *component,
490553 if (ret < 0 )
491554 dev_err (dev , "Audio Start: Buffer Allocation failed rc = %d\n" , ret );
492555
556+ if (is_push_pull ) {
557+ if (pdata -> sid < 0 )
558+ phys = substream -> dma_buffer .addr + BUFFER_BYTES_MAX ;
559+ else
560+ phys = (substream -> dma_buffer .addr + BUFFER_BYTES_MAX ) | (pdata -> sid << 32 );
561+
562+ ret = q6apm_map_pos_buffer (dev , graph_id , phys , POS_BUFFER_BYTES );
563+ if (ret < 0 )
564+ dev_err (dev , "Audio Start: Buffer Allocation failed rc = %d\n" , ret );
565+ } else {
566+
567+ }
568+
493569 return ret ;
494570}
495571
@@ -504,25 +580,30 @@ static int q6apm_dai_pcm_new(struct snd_soc_component *component, struct snd_soc
504580 */
505581 int size = BUFFER_BYTES_MAX + PAGE_SIZE ;
506582 int graph_id , ret ;
507- struct snd_pcm_substream * substream ;
583+ bool is_push_pull ;
584+ struct snd_pcm_substream * substream = NULL ;
508585
509586 graph_id = cpu_dai -> driver -> id ;
510587
511- ret = snd_pcm_set_fixed_buffer_all (pcm , SNDRV_DMA_TYPE_DEV , component -> dev , size );
512- if (ret )
513- return ret ;
514-
515588 /* Note: DSP backend dais are uni-directional ONLY(either playback or capture) */
516- if (pcm -> streams [SNDRV_PCM_STREAM_PLAYBACK ].substream ) {
589+ if (pcm -> streams [SNDRV_PCM_STREAM_PLAYBACK ].substream )
517590 substream = pcm -> streams [SNDRV_PCM_STREAM_PLAYBACK ].substream ;
518- ret = q6apm_dai_memory_map (component , substream , graph_id );
591+ else if (pcm -> streams [SNDRV_PCM_STREAM_CAPTURE ].substream )
592+ substream = pcm -> streams [SNDRV_PCM_STREAM_CAPTURE ].substream ;
593+
594+
595+ if (substream ) {
596+ is_push_pull = q6apm_is_graph_in_push_pull_mode_from_id (component -> dev ,
597+ graph_id ,
598+ substream -> stream );
599+ if (is_push_pull )
600+ size += POS_BUFFER_BYTES ;
601+
602+ ret = snd_pcm_set_fixed_buffer_all (pcm , SNDRV_DMA_TYPE_DEV , component -> dev , size );
519603 if (ret )
520604 return ret ;
521- }
522605
523- if (pcm -> streams [SNDRV_PCM_STREAM_CAPTURE ].substream ) {
524- substream = pcm -> streams [SNDRV_PCM_STREAM_CAPTURE ].substream ;
525- ret = q6apm_dai_memory_map (component , substream , graph_id );
606+ ret = q6apm_dai_memory_map (component , substream , graph_id , is_push_pull );
526607 if (ret )
527608 return ret ;
528609 }
@@ -547,6 +628,9 @@ static void q6apm_dai_memory_unmap(struct snd_soc_component *component,
547628
548629 graph_id = cpu_dai -> driver -> id ;
549630 q6apm_unmap_memory_fixed_region (component -> dev , graph_id );
631+
632+ if (q6apm_is_graph_in_push_pull_mode_from_id (component -> dev , graph_id , substream -> stream ))
633+ q6apm_unmap_pos_buffer (component -> dev , graph_id );
550634}
551635
552636static void q6apm_dai_pcm_free (struct snd_soc_component * component , struct snd_pcm * pcm )
0 commit comments