From 217286880e51e04393bb495105f431e7a877dd92 Mon Sep 17 00:00:00 2001 From: "Ronald G. Minnich" Date: Mon, 22 Jul 2002 21:28:16 +0000 Subject: [PATCH] Changes to make udelay a bit easier to compile in. There are now three version. --- src/cpu/p5/Config | 3 +- src/cpu/p5/delay_tsc.c | 69 ++++++++++++++++++++++++++++++- src/lib/delay.c | 55 ------------------------ src/pc80/Config | 1 + src/pc80/udelay_timer2.c | 56 +++++++++++++++++++++++++ src/southbridge/amd/amd766/Config | 4 +- 6 files changed, 128 insertions(+), 60 deletions(-) create mode 100644 src/pc80/udelay_timer2.c diff --git a/src/cpu/p5/Config b/src/cpu/p5/Config index 758a6902ac..4e462ffaba 100644 --- a/src/cpu/p5/Config +++ b/src/cpu/p5/Config @@ -1,4 +1,5 @@ +option CONFIG_TSC_X86RDTSC_CALIBRATE_WITH_TIMER2=0 option i586=1 object cpuid.o -object delay_tsc.o +object delay_tsc.o CONFIG_UDELAY_TSC #object tsc.o diff --git a/src/cpu/p5/delay_tsc.c b/src/cpu/p5/delay_tsc.c index 4e84ff4d6f..c96f3642db 100644 --- a/src/cpu/p5/delay_tsc.c +++ b/src/cpu/p5/delay_tsc.c @@ -4,7 +4,7 @@ static unsigned long clocks_per_usec; - +#if (CONFIG_TSC_X86RDTSC_CALIBRATE_WITH_TIMER2 == 1) #define CLOCK_TICK_RATE 1193180U /* Underlying HZ */ /* ------ Calibrate the TSC ------- @@ -79,6 +79,73 @@ bad_ctc: return 0; } +#else /* CONFIG_TSC_X86RDTSC_CALIBRATE_WITH_TIMER2 */ + +/* + * this is the "no timer2" version. + * to calibrate tsc, we get a TSC reading, then do 1,000,000 outbs to port 0x80 + * then we read TSC again, and divide the difference by 1,000,000 + * we have found on a wide range of machines that this gives us a a + * good microsecond value + * to +- 10%. On a dual AMD 1.6 Ghz box, it gives us .97 microseconds, and on a + * 267 Mhz. p5, it gives us 1.1 microseconds. + * also, since gcc now supports long long, we use that. + * also no unsigned long long / operator, so we play games. + * about the only thing you can do with long longs, it seems, + *is return them and assign them. + * (and do asm on them, yuck) + * so avoid all ops on long longs. + */ +static unsigned long long calibrate_tsc(void) +{ + unsigned long long retval, start, end, delta; + unsigned long allones = (unsigned long) -1, result; + unsigned long startlow, starthigh; + unsigned long endlow, endhigh; + unsigned long count; + + rdtsc(startlow,starthigh); + // no udivdi3, dammit. + // so we count to 1<< 20 and then right shift 20 + for(count = 0; count < (1<<20); count ++) + outb(0x80, 0x80); + rdtsc(endlow,endhigh); + + // make delta be (endhigh - starthigh) + (endlow - startlow) + // but >> 20 + // do it this way to avoid gcc warnings. + start = starthigh; + start <<= 32; + start |= startlow; + end = endhigh; + end <<= 32; + end |= endlow; + delta = end - start; + // at this point we have a delta for 1,000,000 outbs. Now rescale for one microsecond. + delta >>= 20; + // save this for microsecond timing. + clocks_per_usec = delta; +#ifdef DEBUG + printf("end %x:%x, start %x:%x\n", + endhigh, endlow, starthigh, startlow); + printf("32-bit delta %d\n", (unsigned long) delta); +#endif + + // ok now we don't have divide for unsigned long long. + // so what we do is set an unsigned long to all 1's, which is just 1 less than + // 1 << 32. then we divide by an unsigned long version of delta (we now that delta fits + // easily in 32 bits). that way we avoid assembly code. + // avoid gcc complaints. + result = allones / (unsigned long) delta; + retval = result; +#ifdef DEBUG + printf(__FUNCTION__ " 32-bit result is %d\n", result); +#endif + return retval; +} + + +#endif /* CONFIG_TSC_X86RDTSC_CALIBRATE_WITH_TIMER2*/ void udelay(unsigned long us) { diff --git a/src/lib/delay.c b/src/lib/delay.c index 9b922b550d..af5f78613e 100644 --- a/src/lib/delay.c +++ b/src/lib/delay.c @@ -1,59 +1,4 @@ #include -#include - -/* Ports for the 8254 timer chip */ -#define TIMER2_PORT 0x42 -#define TIMER_MODE_PORT 0x43 - -/* Meaning of the mode bits */ -#define TIMER0_SEL 0x00 -#define TIMER1_SEL 0x40 -#define TIMER2_SEL 0x80 -#define READBACK_SEL 0xC0 - -#define LATCH_COUNT 0x00 -#define LOBYTE_ACCESS 0x10 -#define HIBYTE_ACCESS 0x20 -#define WORD_ACCESS 0x30 - -#define MODE0 0x00 -#define MODE1 0x02 -#define MODE2 0x04 -#define MODE3 0x06 -#define MODE4 0x08 -#define MODE5 0x0A - -#define BINARY_COUNT 0x00 -#define BCD_COUNT 0x01 - -/* Timers tick over at this rate */ -#define TICKS_PER_MS 1193 - -/* Parallel Peripheral Controller Port B */ -#define PPC_PORTB 0x61 - -/* Meaning of the port bits */ -#define PPCB_T2OUT 0x20 /* Bit 5 */ -#define PPCB_SPKR 0x02 /* Bit 1 */ -#define PPCB_T2GATE 0x01 /* Bit 0 */ - - -static void load_timer2(unsigned int ticks) -{ - /* Set up the timer gate, turn off the speaker */ - outb((inb(PPC_PORTB) & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB); - outb(TIMER2_SEL|WORD_ACCESS|MODE0|BINARY_COUNT, TIMER_MODE_PORT); - outb(ticks & 0xFF, TIMER2_PORT); - outb(ticks >> 8, TIMER2_PORT); -} - - -void udelay(int usecs) -{ - load_timer2((usecs*TICKS_PER_MS)/1000); - while ((inb(PPC_PORTB) & PPCB_T2OUT) == 0) - ; -} void mdelay(int msecs) { int i; diff --git a/src/pc80/Config b/src/pc80/Config index 9bac92b107..d21000e40f 100644 --- a/src/pc80/Config +++ b/src/pc80/Config @@ -2,5 +2,6 @@ object keyboard.o object mc146818rtc.o object isa-dma.o object i8259.o +object udelay_timer2.o CONFIG_UDELAY_TIMER2 dir ide diff --git a/src/pc80/udelay_timer2.c b/src/pc80/udelay_timer2.c new file mode 100644 index 0000000000..964f5fea2d --- /dev/null +++ b/src/pc80/udelay_timer2.c @@ -0,0 +1,56 @@ +#include +#include + +/* Ports for the 8254 timer chip */ +#define TIMER2_PORT 0x42 +#define TIMER_MODE_PORT 0x43 + +/* Meaning of the mode bits */ +#define TIMER0_SEL 0x00 +#define TIMER1_SEL 0x40 +#define TIMER2_SEL 0x80 +#define READBACK_SEL 0xC0 + +#define LATCH_COUNT 0x00 +#define LOBYTE_ACCESS 0x10 +#define HIBYTE_ACCESS 0x20 +#define WORD_ACCESS 0x30 + +#define MODE0 0x00 +#define MODE1 0x02 +#define MODE2 0x04 +#define MODE3 0x06 +#define MODE4 0x08 +#define MODE5 0x0A + +#define BINARY_COUNT 0x00 +#define BCD_COUNT 0x01 + +/* Timers tick over at this rate */ +#define TICKS_PER_MS 1193 + +/* Parallel Peripheral Controller Port B */ +#define PPC_PORTB 0x61 + +/* Meaning of the port bits */ +#define PPCB_T2OUT 0x20 /* Bit 5 */ +#define PPCB_SPKR 0x02 /* Bit 1 */ +#define PPCB_T2GATE 0x01 /* Bit 0 */ + + +static void load_timer2(unsigned int ticks) +{ + /* Set up the timer gate, turn off the speaker */ + outb((inb(PPC_PORTB) & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB); + outb(TIMER2_SEL|WORD_ACCESS|MODE0|BINARY_COUNT, TIMER_MODE_PORT); + outb(ticks & 0xFF, TIMER2_PORT); + outb(ticks >> 8, TIMER2_PORT); +} + + +void udelay(int usecs) +{ + load_timer2((usecs*TICKS_PER_MS)/1000); + while ((inb(PPC_PORTB) & PPCB_T2OUT) == 0) + ; +} diff --git a/src/southbridge/amd/amd766/Config b/src/southbridge/amd/amd766/Config index efd92c8415..7b41e7a42d 100644 --- a/src/southbridge/amd/amd766/Config +++ b/src/southbridge/amd/amd766/Config @@ -1,3 +1,4 @@ +option CONFIG_UDELAY_TSC object southbridge.o object nvram.o object amd766_ioapic.o @@ -11,6 +12,3 @@ object amd766_power.o object amd766_reboot.o object amd766_ide.o - - -