x86: tsc: Add driver model timer support
authorBin Meng <bmeng.cn@gmail.com>
Fri, 13 Nov 2015 08:11:21 +0000 (00:11 -0800)
committerSimon Glass <sjg@chromium.org>
Tue, 1 Dec 2015 13:23:51 +0000 (06:23 -0700)
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>
arch/x86/lib/tsc_timer.c

index 5a962ce6297d4f7c0b4203782f2c4c83037737c7..4a95959e1b2336ceab080d7a0bbc900e2d9dbe0c 100644 (file)
@@ -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 @@ success:
        return delta / 1000;
 }
 
+#ifndef CONFIG_TIMER
 void timer_set_base(u64 base)
 {
        gd->arch.tsc_base = base;
@@ -297,10 +300,14 @@ u64 notrace get_ticks(void)
                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 @@ unsigned notrace long get_tbclk_mhz(void)
 
        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 @@ int timer_init(void)
 
        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 */