diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
| commit | 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch) | |
| tree | c6e220ba61db3a6ea4052e6841296d829654e664 /os/boot/puma/clock.c | |
| parent | 46439007cf417cbd9ac8049bb4122c890097a0fa (diff) | |
20060303
Diffstat (limited to 'os/boot/puma/clock.c')
| -rw-r--r-- | os/boot/puma/clock.c | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/os/boot/puma/clock.c b/os/boot/puma/clock.c new file mode 100644 index 00000000..6c8902b7 --- /dev/null +++ b/os/boot/puma/clock.c @@ -0,0 +1,154 @@ +#include "boot.h" + + /* + * Control Word Read/Write Counter (mode 0) LSB, MSB + */ +#define PIT_RW_COUNTER0 0x30 +#define PIT_RW_COUNTER1 0x70 +#define PIT_RW_COUNTER2 0xB0 +#define PIT_COUNTERLATCH0 0x00 +#define PIT_COUNTERLATCH1 0x40 +#define PIT_COUNTERLATCH2 0x80 + +#define PIT_MODE_0 0 /* Interrupt on Terminal Count */ +#define PIT_MODE_1 2 /* Hardware Retriggeable One-shot */ +#define PIT_MODE_2 4 /* Rate Generator */ +#define PIT_MODE_3 6 /* Square Wave Mode */ +#define PIT_MODE_4 8 /* Software Triggered Mode */ +#define PIT_MODE_5 10 /* Hardware Triggered Mode (Retriggeable) */ + +/* + * Harris 82C54 Programmable Interval Timer + * On the Puma board the PIT is memory mapped + * starting at 0xf2000000 and with each of the 8-bit + * registers addressed on a consecutive 4-byte boundary. + */ +#undef inb +#undef outb +#define inb(port) ((*(uchar *)(port))&0xff) +#define outb(port, data) (*(uchar *)(port) = (data)) +enum +{ + Cnt0= 0xf2000000, /* counter locations */ + Cnt1= 0xf2000004, /* ... */ + Cnt2= 0xf2000008, /* ... */ + Ctlw= 0xf200000c, /* control word register*/ + + /* commands */ + Latch0= 0x00, /* latch counter 0's value */ + Load0= 0x30, /* load counter 0 with 2 bytes */ + Latch1= 0x40, /* latch counter 1's value */ + Load1= 0x70, /* load counter 1 with 2 bytes */ + + /* modes */ + Square= 0x06, /* periodic square wave */ + RateGen= 0x04, /* rate generator */ + + Freq= 3686400, /* Real clock frequency */ +}; + +static int cpufreq = 233000000; +static int aalcycles = 14; + +static void +clockintr(Ureg*, void*) +{ + m->ticks++; + checkalarms(); +} + +/* + * delay for l milliseconds more or less. delayloop is set by + * clockinit() to match the actual CPU speed. + */ +void +delay(int l) +{ + l *= m->delayloop; + if(l <= 0) + l = 1; + aamloop(l); +} + +void +microdelay(int l) +{ + l *= m->delayloop; + l /= 1000; + if(l <= 0) + l = 1; + aamloop(l); +} + +void +clockinit(void) +{ + int x, y; /* change in counter */ + int loops, incr; + + /* + * set vector for clock interrupts + */ + setvec(V_TIMER0, clockintr, 0); + + /* + * set clock for 1/HZ seconds + */ + outb(Ctlw, Load0|Square); + outb(Cnt0, (Freq/HZ)); /* low byte */ + outb(Cnt0, (Freq/HZ)>>8); /* high byte */ + + /* find biggest loop that doesn't wrap */ + incr = 16000000/(aalcycles*HZ*2); + x = 2000; + for(loops = incr; loops < 64*1024; loops += incr) { + /* + * measure time for the loop + * TEXT aamloop(SB), $-4 + * _aamloop: + * MOVW R0, R0 + * MOVW R0, R0 + * MOVW R0, R0 + * SUB $1, R0 + * CMP $0, R0 + * BNE _aamloop + * RET + * + * the time for the loop should be independent of external + * cache and memory system since it fits in the execution + * prefetch buffer. + * + */ + outb(Ctlw, Latch0); + x = inb(Cnt0); + x |= inb(Cnt0)<<8; + aamloop(loops); + outb(Ctlw, Latch0); + y = inb(Cnt0); + y |= inb(Cnt0)<<8; + x -= y; + + if(x < 0) + x += Freq/HZ; + + if(x > Freq/(3*HZ)) + break; + } + + /* + * counter goes at twice the frequency, once per transition, + * i.e., twice per square wave + */ + x >>= 1; + + /* + * figure out clock frequency and a loop multiplier for delay(). + */ + cpufreq = loops*((aalcycles*Freq)/x); + m->delayloop = (cpufreq/1000)/aalcycles; /* AAMLOOPs for 1 ms */ + + /* + * add in possible .2% error and convert to MHz + */ + m->speed = (cpufreq + cpufreq/500)/1000000; +} |
