timer: Provide an early timer

In some cases the timer must be accessible before driver model is active.
Examples include when using CONFIG_TRACE to trace U-Boot's execution before
driver model is set up. Enable this option to use an early timer. These
functions must be supported by your timer driver: timer_early_get_count()
and timer_early_get_rate().

Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index ff65a73..cb18f12 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -9,6 +9,16 @@
 	  will be used. The timer is usually a 32 bits free-running up
 	  counter. There may be no real tick, and no timer interrupt.
 
+config TIMER_EARLY
+	bool "Allow timer to be used early in U-Boot"
+	depends on TIMER
+	help
+	  In some cases the timer must be accessible before driver model is
+	  active. Examples include when using CONFIG_TRACE to trace U-Boot's
+	  execution before driver model is set up. Enable this option to
+	  use an early timer. These functions must be supported by your timer
+	  driver: timer_early_get_count() and timer_early_get_rate().
+
 config ALTERA_TIMER
 	bool "Altera timer support"
 	depends on TIMER
diff --git a/include/timer.h b/include/timer.h
index f14725c..dcc803c 100644
--- a/include/timer.h
+++ b/include/timer.h
@@ -67,4 +67,25 @@
 	unsigned long clock_rate;
 };
 
+/**
+ * timer_early_get_count() - Implement timer_get_count() before driver model
+ *
+ * If CONFIG_TIMER_EARLY is enabled, this function wil be called to return
+ * the current timer value before the proper driver model timer is ready.
+ * It should be implemented by one of the timer values. This is mostly useful
+ * for tracing.
+ */
+u64 timer_early_get_count(void);
+
+/**
+ * timer_early_get_rate() - Get the timer rate before driver model
+ *
+ * If CONFIG_TIMER_EARLY is enabled, this function wil be called to return
+ * the current timer rate in Hz before the proper driver model timer is ready.
+ * It should be implemented by one of the timer values. This is mostly useful
+ * for tracing. This corresponds to the clock_rate value in struct
+ * timer_dev_priv.
+ */
+unsigned long timer_early_get_rate(void);
+
 #endif	/* _TIMER_H_ */
diff --git a/lib/time.c b/lib/time.c
index e9f6861..f37150f 100644
--- a/lib/time.c
+++ b/lib/time.c
@@ -43,11 +43,17 @@
 #ifdef CONFIG_TIMER
 ulong notrace get_tbclk(void)
 {
-	int ret;
+	if (!gd->timer) {
+#ifdef CONFIG_TIMER_EARLY
+		return timer_early_get_rate();
+#else
+		int ret;
 
-	ret = dm_timer_init();
-	if (ret)
-		return ret;
+		ret = dm_timer_init();
+		if (ret)
+			return ret;
+#endif
+	}
 
 	return timer_get_rate(gd->timer);
 }
@@ -57,9 +63,17 @@
 	u64 count;
 	int ret;
 
-	ret = dm_timer_init();
-	if (ret)
-		return ret;
+	if (!gd->timer) {
+#ifdef CONFIG_TIMER_EARLY
+		return timer_early_get_count();
+#else
+		int ret;
+
+		ret = dm_timer_init();
+		if (ret)
+			return ret;
+#endif
+	}
 
 	ret = timer_get_count(gd->timer, &count);
 	if (ret)