From 5b6404e4195157eac8d97ae5bf30f45612109d57 Mon Sep 17 00:00:00 2001 From: Stefan Reinauer Date: Tue, 3 Apr 2012 16:11:02 -0700 Subject: Fix timer frequency detection on Sandybridge Change-Id: Ide720bd91cde56a0afdd231d93500c371b1ffbe8 Signed-off-by: Duncan Laurie Signed-off-by: Stefan Reinauer Reviewed-on: http://review.coreboot.org/870 Reviewed-by: Ronald G. Minnich Tested-by: build bot (Jenkins) --- src/cpu/x86/lapic/apic_timer.c | 48 +++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 12 deletions(-) (limited to 'src/cpu/x86') diff --git a/src/cpu/x86/lapic/apic_timer.c b/src/cpu/x86/lapic/apic_timer.c index 826f5b6ad4..bb6cca7d9a 100644 --- a/src/cpu/x86/lapic/apic_timer.c +++ b/src/cpu/x86/lapic/apic_timer.c @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -27,14 +28,40 @@ * memory init. */ -#define FSB_CLOCK_STS 0xcd +static u32 timer_fsb = 0; -static u32 timer_fsb = 200; // default to 200MHz +static int set_timer_fsb(void) +{ + struct cpuinfo_x86 c; + int core_fsb[8] = { -1, 133, -1, 166, -1, 100, -1, -1 }; + int core2_fsb[8] = { 266, 133, 200, 166, -1, 100, -1, -1 }; + + get_fms(&c, cpuid_eax(1)); + if (c.x86 != 6) + return -1; + + switch (c.x86_model) { + case 0xe: /* Core Solo/Duo */ + case 0x1c: /* Atom */ + timer_fsb = core_fsb[rdmsr(0xcd).lo & 7]; + break; + case 0xf: /* Core 2*/ + case 0x17: /* Enhanced Core */ + timer_fsb = core2_fsb[rdmsr(0xcd).lo & 7]; + break; + case 0x2a: /* SandyBridge BCLK fixed at 100MHz*/ + timer_fsb = 100; + break; + default: + timer_fsb = 200; + break; + } + + return 0; +} void init_timer(void) { - msr_t fsb_clock_sts; - /* Set the apic timer to no interrupts and periodic mode */ lapic_write(LAPIC_LVTT, (LAPIC_LVT_TIMER_PERIODIC | LAPIC_LVT_MASKED)); @@ -45,19 +72,16 @@ void init_timer(void) lapic_write(LAPIC_TMICT, 0xffffffff); /* Set FSB frequency to a reasonable value */ - fsb_clock_sts = rdmsr(FSB_CLOCK_STS); - switch ((fsb_clock_sts.lo >> 4) & 0x07) { - case 0: timer_fsb = 266; break; - case 1: timer_fsb = 133; break; - case 2: timer_fsb = 200; break; - case 3: timer_fsb = 166; break; - case 5: timer_fsb = 100; break; - } + set_timer_fsb(); } void udelay(u32 usecs) { u32 start, value, ticks; + + if (!timer_fsb) + init_timer(); + /* Calculate the number of ticks to run, our FSB runs at timer_fsb Mhz */ ticks = usecs * timer_fsb; start = lapic_read(LAPIC_TMCCT); -- cgit v1.2.3