[PATCH 8/8] ASoC: q6asm: allow to specify buffer offset in q6asm_write

From: Srinivas Kandagatla
Date: Thu Jun 11 2020 - 08:42:27 EST


In usecase like gapless, its possible that next stream/track
can start an offset where previous track ends, and this offset
may not be at period boundary.

So adding offset parameter to write function will provide ablity
to send buffers with an offset inside period boundary.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@xxxxxxxxxx>
---
sound/soc/qcom/qdsp6/q6asm-dai.c | 15 +++++++++------
sound/soc/qcom/qdsp6/q6asm.c | 21 ++++++++++++++-------
sound/soc/qcom/qdsp6/q6asm.h | 3 ++-
3 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index 7aba3c07810b..113929e79407 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -187,7 +187,7 @@ static void event_handler(uint32_t opcode, uint32_t token,
case ASM_CLIENT_EVENT_CMD_RUN_DONE:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
q6asm_write_async(prtd->audio_client, prtd->stream_id,
- prtd->pcm_count, 0, 0, 0);
+ 0, prtd->pcm_count, 0, 0, 0);
break;
case ASM_CLIENT_EVENT_CMD_EOS_DONE:
prtd->state = Q6ASM_STREAM_STOPPED;
@@ -197,7 +197,7 @@ static void event_handler(uint32_t opcode, uint32_t token,
snd_pcm_period_elapsed(substream);
if (prtd->state == Q6ASM_STREAM_RUNNING)
q6asm_write_async(prtd->audio_client, prtd->stream_id,
- prtd->pcm_count, 0, 0, 0);
+ 0, prtd->pcm_count, 0, 0, 0);

break;
}
@@ -509,14 +509,14 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,
struct snd_compr_stream *substream = prtd->cstream;
unsigned long flags;
uint64_t avail;
- uint32_t bytes_written;
+ uint32_t bytes_written, offset;

switch (opcode) {
case ASM_CLIENT_EVENT_CMD_RUN_DONE:
spin_lock_irqsave(&prtd->lock, flags);
if (!prtd->bytes_sent) {
q6asm_write_async(prtd->audio_client, prtd->stream_id,
- prtd->pcm_count, 0, 0, 0);
+ 0, prtd->pcm_count, 0, 0, 0);
prtd->bytes_sent += prtd->pcm_count;
}

@@ -532,7 +532,10 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,

bytes_written = token >> ASM_WRITE_TOKEN_LEN_SHIFT;
prtd->copied_total += bytes_written;
- snd_compr_fragment_elapsed(substream);
+ offset = prtd->copied_total % prtd->pcm_count;
+
+ if (bytes_written && !offset)
+ snd_compr_fragment_elapsed(substream);

avail = prtd->bytes_received - prtd->bytes_sent;
if (prtd->state != Q6ASM_STREAM_RUNNING || avail <= 0) {
@@ -542,7 +545,7 @@ static void compress_event_handler(uint32_t opcode, uint32_t token,

if (avail >= prtd->pcm_count) {
q6asm_write_async(prtd->audio_client, prtd->stream_id,
- prtd->pcm_count, 0, 0, 0);
+ 0, prtd->pcm_count, 0, 0, 0);
prtd->bytes_sent += prtd->pcm_count;
}

diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
index 205453d1c1fc..8e3746ce4fa4 100644
--- a/sound/soc/qcom/qdsp6/q6asm.c
+++ b/sound/soc/qcom/qdsp6/q6asm.c
@@ -238,6 +238,7 @@ struct asm_session_cmd_run_v2 {
struct audio_buffer {
phys_addr_t phys;
uint32_t size; /* size of buffer */
+ uint32_t offset;
};

struct audio_port_data {
@@ -671,6 +672,7 @@ static int32_t q6asm_stream_callback(struct apr_device *adev,
phys_addr_t phys;
unsigned long flags;
int token = hdr->token & ASM_WRITE_TOKEN_MASK;
+ struct audio_buffer *ab;

spin_lock_irqsave(&ac->lock, flags);

@@ -682,12 +684,13 @@ static int32_t q6asm_stream_callback(struct apr_device *adev,
goto done;
}

- phys = port->buf[token].phys;
+ ab = &port->buf[token];
+ phys = ab->phys + ab->offset;

- if (lower_32_bits(phys) != result->opcode ||
+ if (lower_32_bits(phys) != (result->opcode) ||
upper_32_bits(phys) != result->status) {
dev_err(ac->dev, "Expected addr %pa\n",
- &port->buf[token].phys);
+ &ab->phys + ab->offset);
spin_unlock_irqrestore(&ac->lock, flags);
ret = -EINVAL;
goto done;
@@ -1504,6 +1507,7 @@ EXPORT_SYMBOL_GPL(q6asm_open_read);
*
* @ac: audio client pointer
* @stream_id: stream id
+ * @offset: offset in the period buffer
* @len: length in bytes
* @msw_ts: timestamp msw
* @lsw_ts: timestamp lsw
@@ -1511,8 +1515,9 @@ EXPORT_SYMBOL_GPL(q6asm_open_read);
*
* Return: Will be an negative value on error or zero on success
*/
-int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len,
- uint32_t msw_ts, uint32_t lsw_ts, uint32_t wflags)
+int q6asm_write_async(struct audio_client *ac, uint32_t stream_id,
+ uint32_t offset, uint32_t len, uint32_t msw_ts,
+ uint32_t lsw_ts, uint32_t wflags)
{
struct asm_data_cmd_write_v2 *write;
struct audio_port_data *port;
@@ -1538,7 +1543,7 @@ int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len,
ab = &port->buf[port->dsp_buf];
pkt->hdr.token = port->dsp_buf | (len << ASM_WRITE_TOKEN_LEN_SHIFT);
pkt->hdr.opcode = ASM_DATA_CMD_WRITE_V2;
- write->buf_addr_lsw = lower_32_bits(ab->phys);
+ write->buf_addr_lsw = lower_32_bits(ab->phys + offset);
write->buf_addr_msw = upper_32_bits(ab->phys);
write->buf_size = len;
write->seq_id = port->dsp_buf;
@@ -1549,7 +1554,9 @@ int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len,

write->flags = wflags;

- port->dsp_buf++;
+ ab->offset = offset;
+ if ((offset + len) == ab->size)
+ port->dsp_buf++;

if (port->dsp_buf >= port->num_periods)
port->dsp_buf = 0;
diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h
index 0379580f0742..ad7e2f6f122f 100644
--- a/sound/soc/qcom/qdsp6/q6asm.h
+++ b/sound/soc/qcom/qdsp6/q6asm.h
@@ -96,7 +96,8 @@ struct audio_client *q6asm_audio_client_alloc(struct device *dev,
q6asm_cb cb, void *priv,
int session_id, int perf_mode);
void q6asm_audio_client_free(struct audio_client *ac);
-int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len,
+int q6asm_write_async(struct audio_client *ac, uint32_t stream_id,
+ uint32_t offset, uint32_t len,
uint32_t msw_ts, uint32_t lsw_ts, uint32_t flags);
int q6asm_open_write(struct audio_client *ac, uint32_t stream_id,
uint32_t format, u32 codec_profile,
--
2.21.0