[Sound-open-firmware] [PATCH] ipc: pipeline: Add pipeline position/timestamp readback to IPC
Liam Girdwood
liam.r.girdwood at linux.intel.com
Tue Aug 15 17:39:26 CEST 2017
Allow the IPC to send and receive pipeline position and timestamp data.
Signed-off-by: Liam Girdwood <liam.r.girdwood at linux.intel.com>
---
src/audio/dai.c | 20 ++++++++++++++++++
src/audio/host.c | 22 +++++++++++++++++++-
src/include/reef/ipc.h | 2 +-
src/ipc/intel-ipc.c | 56 ++++++++++++++++++++++++++++++++++++++++----------
4 files changed, 87 insertions(+), 13 deletions(-)
diff --git a/src/audio/dai.c b/src/audio/dai.c
index f7868cd..4464398 100644
--- a/src/audio/dai.c
+++ b/src/audio/dai.c
@@ -68,6 +68,7 @@ struct dai_data {
uint32_t dai_pos_blks; /* position in bytes (nearest block) */
volatile uint64_t *dai_pos; /* host can read back this value without IPC */
+ uint64_t wallclock; /* wall clock at stream start */
};
static int dai_cmd(struct comp_dev *dev, int cmd, void *data);
@@ -485,6 +486,9 @@ static int dai_cmd(struct comp_dev *dev, int cmd, void *data)
if (dev->state == COMP_STATE_PAUSED) {
dai_trigger(dd->dai, cmd, dev->params.direction);
dma_release(dd->dma, dd->chan);
+
+ /* update starting wallclock */
+ platform_dai_wallclock(dev, &dd->wallclock);
dev->state = COMP_STATE_RUNNING;
}
break;
@@ -495,6 +499,9 @@ static int dai_cmd(struct comp_dev *dev, int cmd, void *data)
if (ret < 0)
return ret;
dai_trigger(dd->dai, cmd, dev->params.direction);
+
+ /* update starting wallclock */
+ platform_dai_wallclock(dev, &dd->wallclock);
dev->state = COMP_STATE_RUNNING;
}
break;
@@ -525,6 +532,18 @@ static int dai_preload(struct comp_dev *dev)
return 0;
}
+static int dai_position(struct comp_dev *dev, struct sof_ipc_stream_posn *posn)
+{
+ struct dai_data *dd = comp_get_drvdata(dev);
+
+ /* TODO: improve accuracy by adding current DMA position */
+ posn->dai_posn = dev->position;
+
+ /* set stream start wallclock */
+ posn->wallclock = dd->wallclock;
+ return 0;
+}
+
static int dai_config(struct comp_dev *dev, struct dai_config *dai_config)
{
struct dai_data *dd = comp_get_drvdata(dev);
@@ -562,6 +581,7 @@ static struct comp_driver comp_dai = {
.reset = dai_reset,
.dai_config = dai_config,
.preload = dai_preload,
+ .position = dai_position,
},
};
diff --git a/src/audio/host.c b/src/audio/host.c
index 5cdc4da..27b5418 100644
--- a/src/audio/host.c
+++ b/src/audio/host.c
@@ -152,14 +152,19 @@ static void host_dma_cb(void *data, uint32_t type, struct dma_sg_elem *next)
/* send IPC message to driver if needed */
hd->report_pos += local_elem->size;
hd->posn.host_posn += local_elem->size;
+
+ /* NO_IRQ mode if host_period_size == 0 */
if (dev->params.host_period_bytes != 0 &&
hd->report_pos >= dev->params.host_period_bytes) {
hd->report_pos = 0;
/* update for host side */
if (hd->host_pos) {
*hd->host_pos = hd->local_pos;
- ipc_stream_send_notification(dev, &hd->posn);
}
+
+ /* send timestamps to host */
+ pipeline_get_timestamp(dev->pipeline, dev, &hd->posn);
+ ipc_stream_send_position(dev, &hd->posn);
}
/* update src and dest positions and check for overflow */
@@ -271,6 +276,9 @@ static struct comp_dev *host_new(struct sof_ipc_comp *comp)
/* set up callback */
dma_set_cb(hd->dma, hd->chan, DMA_IRQ_TYPE_LLIST, host_dma_cb, dev);
+ /* init posn data. TODO: other fields */
+ hd->posn.comp_id = comp->id;
+
return dev;
error:
@@ -523,6 +531,17 @@ static int host_stop(struct comp_dev *dev)
return 0;
}
+static int host_position(struct comp_dev *dev,
+ struct sof_ipc_stream_posn *posn)
+{
+ struct host_data *hd = comp_get_drvdata(dev);
+
+ /* TODO: improve accuracy by adding current DMA position */
+ posn->host_posn = hd->local_pos;
+
+ return 0;
+}
+
/* used to pass standard and bespoke commands (with data) to component */
static int host_cmd(struct comp_dev *dev, int cmd, void *data)
{
@@ -641,6 +660,7 @@ struct comp_driver comp_host = {
.prepare = host_prepare,
.preload = host_preload,
.host_buffer = host_buffer,
+ .position = host_position,
},
};
diff --git a/src/include/reef/ipc.h b/src/include/reef/ipc.h
index 92a6f6e..96f2924 100644
--- a/src/include/reef/ipc.h
+++ b/src/include/reef/ipc.h
@@ -114,7 +114,7 @@ void ipc_free(struct ipc *ipc);
int ipc_process_msg_queue(void);
-int ipc_stream_send_notification(struct comp_dev *cdev,
+int ipc_stream_send_position(struct comp_dev *cdev,
struct sof_ipc_stream_posn *posn);
int ipc_queue_host_message(struct ipc *ipc, uint32_t header,
void *tx_data, size_t tx_bytes, void *rx_data,
diff --git a/src/ipc/intel-ipc.c b/src/ipc/intel-ipc.c
index d122b30..dbb0db1 100644
--- a/src/ipc/intel-ipc.c
+++ b/src/ipc/intel-ipc.c
@@ -274,9 +274,52 @@ static int ipc_stream_pcm_free(uint32_t header)
/* reset the pipeline */
pipeline_reset(pcm_dev->cd->pipeline, pcm_dev->cd);
+
+/* get stream position */
+static int ipc_stream_position(uint32_t header)
+{
+ struct sof_ipc_stream *stream = _ipc->comp_data;
+ struct sof_ipc_stream_posn posn;
+ struct ipc_comp_dev *pcm_dev;
+
+ trace_ipc("pos");
+
+ memset(&posn, 0, sizeof(posn));
+
+ /* get the pcm_dev */
+ pcm_dev = ipc_get_comp(_ipc, stream->comp_id);
+ if (pcm_dev == NULL) {
+ trace_ipc_error("epo");
+ return -ENODEV;
+ }
+
+ /* set message fields - TODO; get others */
+ posn.rhdr.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_POSITION;
+ posn.rhdr.hdr.size = sizeof(posn);
+ posn.comp_id = stream->comp_id;
+
+ /* get the stream positions and timestamps */
+ pipeline_get_timestamp(pcm_dev->cd->pipeline, pcm_dev->cd, &posn);
+
+ /* copy positions to outbox */
+ mailbox_outbox_write(0, &posn, sizeof(posn));
return 0;
}
+/* send stream position */
+int ipc_stream_send_position(struct comp_dev *cdev,
+ struct sof_ipc_stream_posn *posn)
+{
+ uint32_t header;
+
+ header = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_POSITION;
+ posn->rhdr.hdr.cmd = header;
+ posn->rhdr.hdr.size = sizeof(*posn);
+
+ return ipc_queue_host_message(_ipc, header, posn, sizeof(*posn),
+ NULL, 0, NULL, NULL);
+}
+
static int ipc_stream_trigger(uint32_t header)
{
struct ipc_comp_dev *pcm_dev;
@@ -343,6 +386,8 @@ static int ipc_glb_stream_message(uint32_t header)
case iCS(SOF_IPC_STREAM_TRIG_DRAIN):
case iCS(SOF_IPC_STREAM_TRIG_XRUN):
return ipc_stream_trigger(header);
+ case iCS(SOF_IPC_STREAM_POSITION):
+ return ipc_stream_position(header);
default:
return -EINVAL;
}
@@ -712,17 +757,6 @@ static inline struct ipc_msg *msg_get_empty(struct ipc *ipc)
return msg;
}
-/* Send stream command */
-int ipc_stream_send_notification(struct comp_dev *cdev,
- struct sof_ipc_stream_posn *posn)
-{
- uint32_t header;
-
- header = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_POSITION;
-trace_value(header);
- return ipc_queue_host_message(_ipc, header, posn, sizeof(*posn),
- NULL, 0, NULL, NULL);
-}
int ipc_queue_host_message(struct ipc *ipc, uint32_t header,
void *tx_data, size_t tx_bytes, void *rx_data,
--
2.11.0
More information about the Sound-open-firmware
mailing list