[Sound-open-firmware] [PATCH] pipeline: timestamp: Add support for pipeline timestamping
Liam Girdwood
liam.r.girdwood at linux.intel.com
Tue Aug 15 17:39:25 CEST 2017
Allow pipeline host and DAI components to be timestamped in a platform
specific manner so that host DMA & DAI DMA position alongside any local
DSP timestamp can be returned to the host drivers.
Signed-off-by: Liam Girdwood <liam.r.girdwood at linux.intel.com>
---
src/audio/pipeline.c | 103 ++++++++++++++++++++++++-
src/include/reef/audio/component.h | 13 ++++
src/include/reef/audio/pipeline.h | 5 ++
src/include/uapi/ipc.h | 29 ++++++-
src/platform/baytrail/include/platform/timer.h | 14 ++++
src/platform/baytrail/timer.c | 36 +++++++++
6 files changed, 196 insertions(+), 4 deletions(-)
diff --git a/src/audio/pipeline.c b/src/audio/pipeline.c
index 185b4f3..817ff08 100644
--- a/src/audio/pipeline.c
+++ b/src/audio/pipeline.c
@@ -679,7 +679,7 @@ static int pipeline_copy_to_downstream(struct comp_dev *start,
return 0;
}
- /* travel downstream to source end point(s) */
+ /* travel downstream to sink end point(s) */
list_for_item(clist, ¤t->bsink_list) {
struct comp_buffer *buffer;
@@ -702,6 +702,107 @@ static int pipeline_copy_to_downstream(struct comp_dev *start,
return err;
}
+static int timestamp_downstream(struct comp_dev *start,
+ struct comp_dev *current, struct sof_ipc_stream_posn *posn)
+{
+ struct list_item *clist;
+ int res = 0;
+
+ /* is component a DAI endpoint ? */
+ if (current != start) {
+
+ /* go downstream if we are not endpoint */
+ if (!current->is_endpoint)
+ goto downstream;
+
+ if (current->comp.id == SOF_COMP_DAI ||
+ current->comp.id == SOF_COMP_SG_DAI) {
+ platform_dai_timestamp(current, posn);
+ return 1;
+ }
+ }
+
+
+downstream:
+ /* travel downstream to sink end point(s) */
+ list_for_item(clist, ¤t->bsink_list) {
+ struct comp_buffer *buffer;
+
+ buffer = container_of(clist, struct comp_buffer, source_list);
+
+ /* dont go downstream if this component is not connected */
+ if (!buffer->connected || buffer->sink->state != COMP_STATE_RUNNING)
+ continue;
+
+ /* continue downstream */
+ res = timestamp_downstream(start, buffer->sink, posn);
+ if (res == 1)
+ break;
+ }
+
+ /* return back upstream */
+ return res;
+}
+
+
+static int timestamp_upstream(struct comp_dev *start,
+ struct comp_dev *current, struct sof_ipc_stream_posn *posn)
+{
+ struct list_item *clist;
+ int res = 0;
+
+ /* is component a DAI endpoint ? */
+ if (current != start) {
+
+ /* go downstream if we are not endpoint */
+ if (!current->is_endpoint)
+ goto upstream;
+
+ if (current->comp.id == SOF_COMP_DAI ||
+ current->comp.id == SOF_COMP_SG_DAI) {
+ platform_dai_timestamp(current, posn);
+ return 1;
+ }
+ }
+
+
+upstream:
+ /* travel upstream to source end point(s) */
+ list_for_item(clist, ¤t->bsource_list) {
+ struct comp_buffer *buffer;
+
+ buffer = container_of(clist, struct comp_buffer, sink_list);
+
+ /* dont go downstream if this component is not connected */
+ if (!buffer->connected || buffer->source->state != COMP_STATE_RUNNING)
+ continue;
+
+ /* continue downstream */
+ res = timestamp_upstream(start, buffer->sink, posn);
+ if (res == 1)
+ break;
+ }
+
+ /* return back upstream */
+ return res;
+}
+
+/*
+ * Get the timestamps for host and first active DAI found.
+ */
+void pipeline_get_timestamp(struct pipeline *p, struct comp_dev *host,
+ struct sof_ipc_stream_posn *posn)
+{
+ platform_host_timestamp(host, posn);
+
+ if (host->params.direction == SOF_IPC_STREAM_PLAYBACK) {
+ timestamp_downstream(host, host, posn);
+ } else {
+ timestamp_upstream(host, host, posn);
+ }
+}
+
+
/* notify pipeline that this component requires buffers emptied/filled */
void pipeline_schedule_copy(struct pipeline *p, struct comp_dev *dev)
{
diff --git a/src/include/reef/audio/component.h b/src/include/reef/audio/component.h
index 3238e13..a74395c 100644
--- a/src/include/reef/audio/component.h
+++ b/src/include/reef/audio/component.h
@@ -139,6 +139,10 @@ struct comp_ops {
/* host buffer config */
int (*host_buffer)(struct comp_dev *dev, struct dma_sg_elem *elem,
uint32_t host_size);
+
+ /* position */
+ int (*position)(struct comp_dev *dev,
+ struct sof_ipc_stream_posn *posn);
};
@@ -264,6 +268,15 @@ static inline int comp_dai_config(struct comp_dev *dev,
return 0;
}
+/* component rendering position */
+static inline int comp_position(struct comp_dev *dev,
+ struct sof_ipc_stream_posn *posn)
+{
+ if (dev->drv->ops.position)
+ return dev->drv->ops.position(dev, posn);
+ return 0;
+}
+
/* default base component initialisations */
void sys_comp_dai_init(void);
void sys_comp_host_init(void);
diff --git a/src/include/reef/audio/pipeline.h b/src/include/reef/audio/pipeline.h
index 8e029d8..ca1947a 100644
--- a/src/include/reef/audio/pipeline.h
+++ b/src/include/reef/audio/pipeline.h
@@ -108,8 +108,13 @@ int init_static_pipeline(struct ipc *ipc);
/* pipeline creation */
int init_pipeline(void);
+/* schedule a copy operation for this pipeline */
void pipeline_schedule_copy(struct pipeline *p, struct comp_dev *dev);
+/* get time pipeline timestamps from host to dai */
+void pipeline_get_timestamp(struct pipeline *p, struct comp_dev *host_dev,
+ struct sof_ipc_stream_posn *posn);
+
void pipeline_schedule(void *arg);
#endif
diff --git a/src/include/uapi/ipc.h b/src/include/uapi/ipc.h
index 38397dd..19ee898 100644
--- a/src/include/uapi/ipc.h
+++ b/src/include/uapi/ipc.h
@@ -360,12 +360,35 @@ struct sof_ipc_stream {
uint32_t comp_id;
} __attribute__((packed));
+
+/* flags indicating which time stamps are in sync with each other */
+#define SOF_TIME_HOST_SYNC (1 << 0)
+#define SOF_TIME_DAI_SYNC (1 << 1)
+#define SOF_TIME_WALL_SYNC (1 << 2)
+#define SOF_TIME_STAMP_SYNC (1 << 3)
+
+/* flags indicating which time stamps are valid */
+#define SOF_TIME_HOST_VALID (1 << 8)
+#define SOF_TIME_DAI_VALID (1 << 9)
+#define SOF_TIME_WALL_VALID (1 << 10)
+#define SOF_TIME_STAMP_VALID (1 << 11)
+
+/* flags indicating time stamps are 64bit else 3use low 32bit */
+#define SOF_TIME_HOST_64 (1 << 16)
+#define SOF_TIME_DAI_64 (1 << 17)
+#define SOF_TIME_WALL_64 (1 << 18)
+#define SOF_TIME_STAMP_64 (1 << 19)
+
struct sof_ipc_stream_posn {
struct sof_ipc_reply rhdr;
uint32_t comp_id;
- uint32_t host_posn; /* in frames */
- uint32_t dai_posn; /* in frames */
- uint64_t timestamp;
+ uint32_t flags; /* SOF_TIME_ */
+ uint32_t wallclock_hz; /* frequency of wallclock in Hz */
+ uint32_t timestamp_ns; /* resolution of timestamp in ns */
+ uint64_t host_posn; /* host DMA position in bytes */
+ uint64_t dai_posn; /* DAI DMA position in bytes */
+ uint64_t wallclock; /* audio wall clock */
+ uint64_t timestamp; /* system time stamp */
} __attribute__((packed));
/*
diff --git a/src/platform/baytrail/include/platform/timer.h b/src/platform/baytrail/include/platform/timer.h
index 0534958..309828c 100644
--- a/src/platform/baytrail/include/platform/timer.h
+++ b/src/platform/baytrail/include/platform/timer.h
@@ -46,10 +46,24 @@
#define TIMER_AUDIO TIMER3
+struct comp_dev;
+struct sof_ipc_stream_posn;
+
void platform_timer_set(struct timer *timer, uint32_t ticks);
void platform_timer_clear(struct timer *timer);
uint32_t platform_timer_get(struct timer *timer);
void platform_timer_start(struct timer *timer);
void platform_timer_stop(struct timer *timer);
+/* get timestamp for host stream DMA position */
+void platform_host_timestamp(struct comp_dev *host,
+ struct sof_ipc_stream_posn *posn);
+
+/* get timestamp for DAI stream DMA position */
+void platform_dai_timestamp(struct comp_dev *dai,
+ struct sof_ipc_stream_posn *posn);
+
+/* get current wallclock for componnent */
+void platform_dai_wallclock(struct comp_dev *dai, uint64_t *wallclock);
+
#endif
diff --git a/src/platform/baytrail/timer.c b/src/platform/baytrail/timer.c
index 4bcabc9..3d08f6f 100644
--- a/src/platform/baytrail/timer.c
+++ b/src/platform/baytrail/timer.c
@@ -33,6 +33,7 @@
#include <platform/timer.h>
#include <platform/shim.h>
#include <reef/debug.h>
+#include <reef/audio/component.h>
#include <stdint.h>
void platform_timer_start(struct timer *timer)
@@ -71,3 +72,38 @@ uint32_t platform_timer_get(struct timer *timer)
{
return shim_read(SHIM_EXT_TIMER_STAT);
}
+
+/* get timestamp for host stream DMA position */
+void platform_host_timestamp(struct comp_dev *host,
+ struct sof_ipc_stream_posn *posn)
+{
+ int err;
+
+ /* get host postion */
+ err = comp_position(host, posn);
+ if (err == 0)
+ posn->flags |= SOF_TIME_HOST_VALID;
+}
+
+/* get timestamp for DAI stream DMA position */
+void platform_dai_timestamp(struct comp_dev *dai,
+ struct sof_ipc_stream_posn *posn)
+{
+ int err;
+
+ /* get DAI postion */
+ err = comp_position(dai, posn);
+ if (err == 0)
+ posn->flags |= SOF_TIME_DAI_VALID;
+
+ /* get SSP wallclock - DAI sets this to stream start value */
+ posn->wallclock = shim_read(SHIM_EXT_TIMER_STAT) - posn->wallclock;
+ posn->flags |= SOF_TIME_WALL_VALID;
+}
+
+/* get current wallclock for componnent */
+void platform_dai_wallclock(struct comp_dev *dai, uint64_t *wallclock)
+{
+ /* only 1 wallclock on BYT */
+ *wallclock = shim_read(SHIM_EXT_TIMER_STAT);
+}
--
2.11.0
More information about the Sound-open-firmware
mailing list