summaryrefslogtreecommitdiff
path: root/os/boot/puma/clock.c
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
commit74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch)
treec6e220ba61db3a6ea4052e6841296d829654e664 /os/boot/puma/clock.c
parent46439007cf417cbd9ac8049bb4122c890097a0fa (diff)
20060303
Diffstat (limited to 'os/boot/puma/clock.c')
-rw-r--r--os/boot/puma/clock.c154
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;
+}