tsc: provide monotonic timer

Implement the timer_monotonic_get() using the TSC.

Change-Id: I5118da6fb9bccc75d2ce012317612e0ab20a2cac
Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/3155
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
diff --git a/src/cpu/x86/Kconfig b/src/cpu/x86/Kconfig
index 6b70ae7..5cf40fa 100644
--- a/src/cpu/x86/Kconfig
+++ b/src/cpu/x86/Kconfig
@@ -25,6 +25,13 @@
 	bool
 	default n
 
+config TSC_MONOTONIC_TIMER
+	def_bool n
+	depends on UDELAY_TSC
+	select HAVE_MONOTONIC_TIMER
+	help
+	  Expose monotonic time using the TSC.
+
 config UDELAY_TIMER2
 	bool
 	default n
diff --git a/src/cpu/x86/tsc/delay_tsc.c b/src/cpu/x86/tsc/delay_tsc.c
index 1907a9c..e4993d0 100644
--- a/src/cpu/x86/tsc/delay_tsc.c
+++ b/src/cpu/x86/tsc/delay_tsc.c
@@ -164,3 +164,40 @@
 		count = rdtscll();
         }
 }
+
+#if CONFIG_TSC_MONOTONIC_TIMER
+#include <timer.h>
+
+static struct monotonic_counter {
+	int initialized;
+	struct mono_time time;
+	uint64_t last_value;
+} mono_counter;
+
+void timer_monotonic_get(struct mono_time *mt)
+{
+	uint64_t current_tick;
+	uint64_t ticks_elapsed;
+
+	if (!mono_counter.initialized) {
+		init_timer();
+		mono_counter.last_value = rdtscll();
+		mono_counter.initialized = 1;
+	}
+
+	current_tick = rdtscll();
+	ticks_elapsed = current_tick - mono_counter.last_value;
+
+	/* Update current time and tick values only if a full tick occurred. */
+	if (ticks_elapsed >= clocks_per_usec) {
+		uint64_t usecs_elapsed;
+
+		usecs_elapsed = ticks_elapsed / clocks_per_usec;
+		mono_time_add_usecs(&mono_counter.time, (long)usecs_elapsed);
+		mono_counter.last_value = current_tick;
+	}
+
+	/* Save result. */
+	*mt = mono_counter.time;
+}
+#endif