@@ -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;
}
@@ -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;
@@ -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,
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@linaro.org> --- 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(-)