Skip to content

Commit 4cfbd3a

Browse files
Srinivas Kandagatlabroonie
authored andcommitted
ASoC: qcom: q6apm-dai: add push-pull and watermark event support
Wire q6apm-dai to use push-pull shared memory graphs. For push-pull graphs, configure the circular buffer and position buffer, register watermark events, and use watermark notifications to report PCM period elapsed. Skip legacy fragment queueing and ACK handling because the DSP reads/writes directly from the shared circular buffer. Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com> Link: https://patch.msgid.link/20260528185806.6316-7-srinivas.kandagatla@oss.qualcomm.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent ed56ac9 commit 4cfbd3a

1 file changed

Lines changed: 114 additions & 30 deletions

File tree

sound/soc/qcom/qdsp6/q6apm-dai.c

Lines changed: 114 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
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;
406449
err:
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

470532
static 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

552636
static void q6apm_dai_pcm_free(struct snd_soc_component *component, struct snd_pcm *pcm)

0 commit comments

Comments
 (0)