x86: tsc: Add driver model timer support

This adds driver model timer support to x86 tsc timer driver.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Acked-by: Simon Glass <sjg@chromium.org>
diff --git a/arch/x86/lib/tsc_timer.c b/arch/x86/lib/tsc_timer.c
index 5a962ce..4a95959 100644
--- a/arch/x86/lib/tsc_timer.c
+++ b/arch/x86/lib/tsc_timer.c
@@ -8,7 +8,9 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <malloc.h>
+#include <timer.h>
 #include <asm/io.h>
 #include <asm/i8254.h>
 #include <asm/ibmpc.h>
@@ -278,6 +280,7 @@
 	return delta / 1000;
 }
 
+#ifndef CONFIG_TIMER
 void timer_set_base(u64 base)
 {
 	gd->arch.tsc_base = base;
@@ -297,10 +300,14 @@
 		panic("No tick base available");
 	return now_tick - gd->arch.tsc_base;
 }
+#endif /* CONFIG_TIMER */
 
 /* Get the speed of the TSC timer in MHz */
 unsigned notrace long get_tbclk_mhz(void)
 {
+#ifdef CONFIG_TIMER
+	return get_tbclk() / 1000000;
+#else
 	unsigned long fast_calibrate;
 
 	if (gd->arch.tsc_mhz)
@@ -320,12 +327,15 @@
 
 	gd->arch.tsc_mhz = fast_calibrate;
 	return fast_calibrate;
+#endif
 }
 
+#ifndef CONFIG_TIMER
 unsigned long get_tbclk(void)
 {
 	return get_tbclk_mhz() * 1000 * 1000;
 }
+#endif
 
 static ulong get_ms_timer(void)
 {
@@ -375,3 +385,58 @@
 
 	return 0;
 }
+
+#ifdef CONFIG_TIMER
+static int tsc_timer_get_count(struct udevice *dev, u64 *count)
+{
+	u64 now_tick = rdtsc();
+
+	*count = now_tick - gd->arch.tsc_base;
+
+	return 0;
+}
+
+static int tsc_timer_probe(struct udevice *dev)
+{
+	struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+	gd->arch.tsc_base = rdtsc();
+
+	/*
+	 * If there is no clock frequency specified in the device tree,
+	 * calibrate it by ourselves.
+	 */
+	if (!uc_priv->clock_rate) {
+		unsigned long fast_calibrate;
+
+		fast_calibrate = try_msr_calibrate_tsc();
+		if (!fast_calibrate) {
+			fast_calibrate = quick_pit_calibrate();
+			if (!fast_calibrate)
+				panic("TSC frequency is ZERO");
+		}
+
+		uc_priv->clock_rate = fast_calibrate * 1000000;
+	}
+
+	return 0;
+}
+
+static const struct timer_ops tsc_timer_ops = {
+	.get_count = tsc_timer_get_count,
+};
+
+static const struct udevice_id tsc_timer_ids[] = {
+	{ .compatible = "x86,tsc-timer", },
+	{ }
+};
+
+U_BOOT_DRIVER(tsc_timer) = {
+	.name	= "tsc_timer",
+	.id	= UCLASS_TIMER,
+	.of_match = tsc_timer_ids,
+	.probe = tsc_timer_probe,
+	.ops	= &tsc_timer_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+#endif /* CONFIG_TIMER */