[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, &current->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, &current->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, &current->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