Fix timer frequency detection on Sandybridge

Change-Id: Ide720bd91cde56a0afdd231d93500c371b1ffbe8
Signed-off-by: Duncan Laurie <dlaurie@google.com>
Signed-off-by: Stefan Reinauer <reinauer@google.com>
Reviewed-on: http://review.coreboot.org/870
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
Tested-by: build bot (Jenkins)
This commit is contained in:
Stefan Reinauer 2012-04-03 16:11:02 -07:00 committed by Stefan Reinauer
parent cab72d9b7b
commit 5b6404e419
1 changed files with 36 additions and 12 deletions

View File

@ -20,6 +20,7 @@
#include <stdint.h> #include <stdint.h>
#include <delay.h> #include <delay.h>
#include <arch/cpu.h>
#include <cpu/x86/msr.h> #include <cpu/x86/msr.h>
#include <cpu/x86/lapic.h> #include <cpu/x86/lapic.h>
@ -27,14 +28,40 @@
* memory init. * 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) void init_timer(void)
{ {
msr_t fsb_clock_sts;
/* Set the apic timer to no interrupts and periodic mode */ /* Set the apic timer to no interrupts and periodic mode */
lapic_write(LAPIC_LVTT, (LAPIC_LVT_TIMER_PERIODIC | LAPIC_LVT_MASKED)); lapic_write(LAPIC_LVTT, (LAPIC_LVT_TIMER_PERIODIC | LAPIC_LVT_MASKED));
@ -45,19 +72,16 @@ void init_timer(void)
lapic_write(LAPIC_TMICT, 0xffffffff); lapic_write(LAPIC_TMICT, 0xffffffff);
/* Set FSB frequency to a reasonable value */ /* Set FSB frequency to a reasonable value */
fsb_clock_sts = rdmsr(FSB_CLOCK_STS); set_timer_fsb();
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;
}
} }
void udelay(u32 usecs) void udelay(u32 usecs)
{ {
u32 start, value, ticks; u32 start, value, ticks;
if (!timer_fsb)
init_timer();
/* Calculate the number of ticks to run, our FSB runs at timer_fsb Mhz */ /* Calculate the number of ticks to run, our FSB runs at timer_fsb Mhz */
ticks = usecs * timer_fsb; ticks = usecs * timer_fsb;
start = lapic_read(LAPIC_TMCCT); start = lapic_read(LAPIC_TMCCT);