x86: Add TSC timer
authorSimon Glass <sjg@chromium.org>
Wed, 17 Apr 2013 16:13:36 +0000 (16:13 +0000)
committerSimon Glass <sjg@chromium.org>
Mon, 13 May 2013 20:33:21 +0000 (13:33 -0700)
This timer runs at a rate that can be calculated, well over 100MHz. It is
ideal for accurate timing and does not need interrupt servicing.

Tidy up some old broken and unneeded implementations at the same time.

To provide a consistent view of boot time, we use the same time
base as coreboot. Use the base timestamp supplied by coreboot
as U-Boot's base time.

Signed-off-by: Simon Glass <sjg@chromium.org>base
Signed-off-by: Simon Glass <sjg@chromium.org>
arch/x86/cpu/coreboot/timestamp.c
arch/x86/cpu/timer.c
arch/x86/include/asm/u-boot-x86.h
arch/x86/lib/Makefile
arch/x86/lib/tsc_timer.c [new file with mode: 0644]
include/configs/coreboot.h

index 2ca7a57..d26718e 100644 (file)
@@ -39,7 +39,9 @@ static struct timestamp_table *ts_table  __attribute__((section(".data")));
 void timestamp_init(void)
 {
        ts_table = lib_sysinfo.tstamp_table;
-       timer_set_tsc_base(ts_table->base_time);
+#ifdef CONFIG_SYS_X86_TSC_TIMER
+       timer_set_base(ts_table->base_time);
+#endif
        timestamp_add_now(TS_U_BOOT_INITTED);
 }
 
index 149109d..f95fce5 100644 (file)
 
 #include <common.h>
 
+/* Temporary patch to maintain bisectability, removed in next commit */
+#ifndef CONFIG_SYS_X86_TSC_TIMER
 unsigned long timer_get_us(void)
 {
        printf("timer_get_us used but not implemented.\n");
        return 0;
 }
+#endif
index 5a59db6..bec583f 100644 (file)
@@ -39,6 +39,8 @@ void panic_puts(const char *str);
 void timer_isr(void *);
 typedef void (timer_fnc_t) (void);
 int register_timer_isr (timer_fnc_t *isr_func);
+unsigned long get_tbclk_mhz(void);
+void timer_set_base(uint64_t base);
 
 /* Architecture specific - can be in arch/x86/cpu/, arch/x86/lib/, or $(BOARD)/ */
 int dram_init_f(void);
index 962593d..0bc8c2f 100644 (file)
@@ -37,6 +37,7 @@ COBJS-y       += relocate.o
 COBJS-y += physmem.o
 COBJS-y        += string.o
 COBJS-$(CONFIG_SYS_X86_ISR_TIMER)      += timer.o
+COBJS-$(CONFIG_SYS_X86_TSC_TIMER)      += tsc_timer.o
 COBJS-$(CONFIG_VIDEO_VGA)      += video.o
 COBJS-$(CONFIG_CMD_ZBOOT)      += zimage.o
 
diff --git a/arch/x86/lib/tsc_timer.c b/arch/x86/lib/tsc_timer.c
new file mode 100644 (file)
index 0000000..d931e5f
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2012 The Chromium OS Authors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/i8254.h>
+#include <asm/ibmpc.h>
+#include <asm/msr.h>
+#include <asm/u-boot-x86.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void timer_set_base(u64 base)
+{
+       gd->arch.tsc_base = base;
+}
+
+/*
+ * Get the number of CPU time counter ticks since it was read first time after
+ * restart. This yields a free running counter guaranteed to take almost 6
+ * years to wrap around even at 100GHz clock rate.
+ */
+u64 get_ticks(void)
+{
+       u64 now_tick = rdtsc();
+
+       /* We assume that 0 means the base hasn't been set yet */
+       if (!gd->arch.tsc_base)
+               panic("No tick base available");
+       return now_tick - gd->arch.tsc_base;
+}
+
+#define PLATFORM_INFO_MSR 0xce
+
+/* Get the speed of the TSC timer in MHz */
+unsigned long get_tbclk_mhz(void)
+{
+       u32 ratio;
+       u64 platform_info = native_read_msr(PLATFORM_INFO_MSR);
+
+       /* 100MHz times Max Non Turbo ratio */
+       ratio = (platform_info >> 8) & 0xff;
+       return 100 * ratio;
+}
+
+unsigned long get_tbclk(void)
+{
+       return get_tbclk_mhz() * 1000 * 1000;
+}
+
+static ulong get_ms_timer(void)
+{
+       return (get_ticks() * 1000) / get_tbclk();
+}
+
+ulong get_timer(ulong base)
+{
+       return get_ms_timer() - base;
+}
+
+ulong timer_get_us(void)
+{
+       return get_ticks() / get_tbclk_mhz();
+}
+
+ulong timer_get_boot_us(void)
+{
+       return timer_get_us();
+}
+
+void __udelay(unsigned long usec)
+{
+       u64 now = get_ticks();
+       u64 stop;
+
+       stop = now + usec * get_tbclk_mhz();
+
+       while ((int64_t)(stop - get_ticks()) > 0)
+               ;
+}
+
+int timer_init(void)
+{
+       /* Nothing to do here - the timer needs no init */
+       return 0;
+}
index 5bacc77..99408dc 100644 (file)
@@ -38,7 +38,6 @@
 #define CONFIG_SHOW_BOOT_PROGRESS
 #define CONFIG_LAST_STAGE_INIT
 #define CONFIG_SYS_VSNPRINTF
-#define CONFIG_INTEL_CORE_ARCH /* Sandy bridge and ivy bridge chipsets. */
 #define CONFIG_ZBOOT_32
 #define CONFIG_PHYSMEM
 #define CONFIG_SYS_EARLY_PCI_INIT
 #define CONFIG_SYS_MEMTEST_END                 0x01000000
 #define CONFIG_SYS_LOAD_ADDR                   0x100000
 #define CONFIG_SYS_HZ                          1000
-#define CONFIG_SYS_X86_ISR_TIMER
 
 /*-----------------------------------------------------------------------
  * SDRAM Configuration
  * CPU Features
  */
 
-#define CONFIG_SYS_GENERIC_TIMER
+#define CONFIG_SYS_X86_TSC_TIMER
 #define CONFIG_SYS_PCAT_INTERRUPTS
 #define CONFIG_SYS_NUM_IRQS                    16