1*74a4d8c2SCharles.Forsyth #include "boot.h"
2*74a4d8c2SCharles.Forsyth
3*74a4d8c2SCharles.Forsyth /*
4*74a4d8c2SCharles.Forsyth * Control Word Read/Write Counter (mode 0) LSB, MSB
5*74a4d8c2SCharles.Forsyth */
6*74a4d8c2SCharles.Forsyth #define PIT_RW_COUNTER0 0x30
7*74a4d8c2SCharles.Forsyth #define PIT_RW_COUNTER1 0x70
8*74a4d8c2SCharles.Forsyth #define PIT_RW_COUNTER2 0xB0
9*74a4d8c2SCharles.Forsyth #define PIT_COUNTERLATCH0 0x00
10*74a4d8c2SCharles.Forsyth #define PIT_COUNTERLATCH1 0x40
11*74a4d8c2SCharles.Forsyth #define PIT_COUNTERLATCH2 0x80
12*74a4d8c2SCharles.Forsyth
13*74a4d8c2SCharles.Forsyth #define PIT_MODE_0 0 /* Interrupt on Terminal Count */
14*74a4d8c2SCharles.Forsyth #define PIT_MODE_1 2 /* Hardware Retriggeable One-shot */
15*74a4d8c2SCharles.Forsyth #define PIT_MODE_2 4 /* Rate Generator */
16*74a4d8c2SCharles.Forsyth #define PIT_MODE_3 6 /* Square Wave Mode */
17*74a4d8c2SCharles.Forsyth #define PIT_MODE_4 8 /* Software Triggered Mode */
18*74a4d8c2SCharles.Forsyth #define PIT_MODE_5 10 /* Hardware Triggered Mode (Retriggeable) */
19*74a4d8c2SCharles.Forsyth
20*74a4d8c2SCharles.Forsyth /*
21*74a4d8c2SCharles.Forsyth * Harris 82C54 Programmable Interval Timer
22*74a4d8c2SCharles.Forsyth * On the Puma board the PIT is memory mapped
23*74a4d8c2SCharles.Forsyth * starting at 0xf2000000 and with each of the 8-bit
24*74a4d8c2SCharles.Forsyth * registers addressed on a consecutive 4-byte boundary.
25*74a4d8c2SCharles.Forsyth */
26*74a4d8c2SCharles.Forsyth #undef inb
27*74a4d8c2SCharles.Forsyth #undef outb
28*74a4d8c2SCharles.Forsyth #define inb(port) ((*(uchar *)(port))&0xff)
29*74a4d8c2SCharles.Forsyth #define outb(port, data) (*(uchar *)(port) = (data))
30*74a4d8c2SCharles.Forsyth enum
31*74a4d8c2SCharles.Forsyth {
32*74a4d8c2SCharles.Forsyth Cnt0= 0xf2000000, /* counter locations */
33*74a4d8c2SCharles.Forsyth Cnt1= 0xf2000004, /* ... */
34*74a4d8c2SCharles.Forsyth Cnt2= 0xf2000008, /* ... */
35*74a4d8c2SCharles.Forsyth Ctlw= 0xf200000c, /* control word register*/
36*74a4d8c2SCharles.Forsyth
37*74a4d8c2SCharles.Forsyth /* commands */
38*74a4d8c2SCharles.Forsyth Latch0= 0x00, /* latch counter 0's value */
39*74a4d8c2SCharles.Forsyth Load0= 0x30, /* load counter 0 with 2 bytes */
40*74a4d8c2SCharles.Forsyth Latch1= 0x40, /* latch counter 1's value */
41*74a4d8c2SCharles.Forsyth Load1= 0x70, /* load counter 1 with 2 bytes */
42*74a4d8c2SCharles.Forsyth
43*74a4d8c2SCharles.Forsyth /* modes */
44*74a4d8c2SCharles.Forsyth Square= 0x06, /* periodic square wave */
45*74a4d8c2SCharles.Forsyth RateGen= 0x04, /* rate generator */
46*74a4d8c2SCharles.Forsyth
47*74a4d8c2SCharles.Forsyth Freq= 3686400, /* Real clock frequency */
48*74a4d8c2SCharles.Forsyth };
49*74a4d8c2SCharles.Forsyth
50*74a4d8c2SCharles.Forsyth static int cpufreq = 233000000;
51*74a4d8c2SCharles.Forsyth static int aalcycles = 14;
52*74a4d8c2SCharles.Forsyth
53*74a4d8c2SCharles.Forsyth static void
clockintr(Ureg *,void *)54*74a4d8c2SCharles.Forsyth clockintr(Ureg*, void*)
55*74a4d8c2SCharles.Forsyth {
56*74a4d8c2SCharles.Forsyth m->ticks++;
57*74a4d8c2SCharles.Forsyth checkalarms();
58*74a4d8c2SCharles.Forsyth }
59*74a4d8c2SCharles.Forsyth
60*74a4d8c2SCharles.Forsyth /*
61*74a4d8c2SCharles.Forsyth * delay for l milliseconds more or less. delayloop is set by
62*74a4d8c2SCharles.Forsyth * clockinit() to match the actual CPU speed.
63*74a4d8c2SCharles.Forsyth */
64*74a4d8c2SCharles.Forsyth void
delay(int l)65*74a4d8c2SCharles.Forsyth delay(int l)
66*74a4d8c2SCharles.Forsyth {
67*74a4d8c2SCharles.Forsyth l *= m->delayloop;
68*74a4d8c2SCharles.Forsyth if(l <= 0)
69*74a4d8c2SCharles.Forsyth l = 1;
70*74a4d8c2SCharles.Forsyth aamloop(l);
71*74a4d8c2SCharles.Forsyth }
72*74a4d8c2SCharles.Forsyth
73*74a4d8c2SCharles.Forsyth void
microdelay(int l)74*74a4d8c2SCharles.Forsyth microdelay(int l)
75*74a4d8c2SCharles.Forsyth {
76*74a4d8c2SCharles.Forsyth l *= m->delayloop;
77*74a4d8c2SCharles.Forsyth l /= 1000;
78*74a4d8c2SCharles.Forsyth if(l <= 0)
79*74a4d8c2SCharles.Forsyth l = 1;
80*74a4d8c2SCharles.Forsyth aamloop(l);
81*74a4d8c2SCharles.Forsyth }
82*74a4d8c2SCharles.Forsyth
83*74a4d8c2SCharles.Forsyth void
clockinit(void)84*74a4d8c2SCharles.Forsyth clockinit(void)
85*74a4d8c2SCharles.Forsyth {
86*74a4d8c2SCharles.Forsyth int x, y; /* change in counter */
87*74a4d8c2SCharles.Forsyth int loops, incr;
88*74a4d8c2SCharles.Forsyth
89*74a4d8c2SCharles.Forsyth /*
90*74a4d8c2SCharles.Forsyth * set vector for clock interrupts
91*74a4d8c2SCharles.Forsyth */
92*74a4d8c2SCharles.Forsyth setvec(V_TIMER0, clockintr, 0);
93*74a4d8c2SCharles.Forsyth
94*74a4d8c2SCharles.Forsyth /*
95*74a4d8c2SCharles.Forsyth * set clock for 1/HZ seconds
96*74a4d8c2SCharles.Forsyth */
97*74a4d8c2SCharles.Forsyth outb(Ctlw, Load0|Square);
98*74a4d8c2SCharles.Forsyth outb(Cnt0, (Freq/HZ)); /* low byte */
99*74a4d8c2SCharles.Forsyth outb(Cnt0, (Freq/HZ)>>8); /* high byte */
100*74a4d8c2SCharles.Forsyth
101*74a4d8c2SCharles.Forsyth /* find biggest loop that doesn't wrap */
102*74a4d8c2SCharles.Forsyth incr = 16000000/(aalcycles*HZ*2);
103*74a4d8c2SCharles.Forsyth x = 2000;
104*74a4d8c2SCharles.Forsyth for(loops = incr; loops < 64*1024; loops += incr) {
105*74a4d8c2SCharles.Forsyth /*
106*74a4d8c2SCharles.Forsyth * measure time for the loop
107*74a4d8c2SCharles.Forsyth * TEXT aamloop(SB), $-4
108*74a4d8c2SCharles.Forsyth * _aamloop:
109*74a4d8c2SCharles.Forsyth * MOVW R0, R0
110*74a4d8c2SCharles.Forsyth * MOVW R0, R0
111*74a4d8c2SCharles.Forsyth * MOVW R0, R0
112*74a4d8c2SCharles.Forsyth * SUB $1, R0
113*74a4d8c2SCharles.Forsyth * CMP $0, R0
114*74a4d8c2SCharles.Forsyth * BNE _aamloop
115*74a4d8c2SCharles.Forsyth * RET
116*74a4d8c2SCharles.Forsyth *
117*74a4d8c2SCharles.Forsyth * the time for the loop should be independent of external
118*74a4d8c2SCharles.Forsyth * cache and memory system since it fits in the execution
119*74a4d8c2SCharles.Forsyth * prefetch buffer.
120*74a4d8c2SCharles.Forsyth *
121*74a4d8c2SCharles.Forsyth */
122*74a4d8c2SCharles.Forsyth outb(Ctlw, Latch0);
123*74a4d8c2SCharles.Forsyth x = inb(Cnt0);
124*74a4d8c2SCharles.Forsyth x |= inb(Cnt0)<<8;
125*74a4d8c2SCharles.Forsyth aamloop(loops);
126*74a4d8c2SCharles.Forsyth outb(Ctlw, Latch0);
127*74a4d8c2SCharles.Forsyth y = inb(Cnt0);
128*74a4d8c2SCharles.Forsyth y |= inb(Cnt0)<<8;
129*74a4d8c2SCharles.Forsyth x -= y;
130*74a4d8c2SCharles.Forsyth
131*74a4d8c2SCharles.Forsyth if(x < 0)
132*74a4d8c2SCharles.Forsyth x += Freq/HZ;
133*74a4d8c2SCharles.Forsyth
134*74a4d8c2SCharles.Forsyth if(x > Freq/(3*HZ))
135*74a4d8c2SCharles.Forsyth break;
136*74a4d8c2SCharles.Forsyth }
137*74a4d8c2SCharles.Forsyth
138*74a4d8c2SCharles.Forsyth /*
139*74a4d8c2SCharles.Forsyth * counter goes at twice the frequency, once per transition,
140*74a4d8c2SCharles.Forsyth * i.e., twice per square wave
141*74a4d8c2SCharles.Forsyth */
142*74a4d8c2SCharles.Forsyth x >>= 1;
143*74a4d8c2SCharles.Forsyth
144*74a4d8c2SCharles.Forsyth /*
145*74a4d8c2SCharles.Forsyth * figure out clock frequency and a loop multiplier for delay().
146*74a4d8c2SCharles.Forsyth */
147*74a4d8c2SCharles.Forsyth cpufreq = loops*((aalcycles*Freq)/x);
148*74a4d8c2SCharles.Forsyth m->delayloop = (cpufreq/1000)/aalcycles; /* AAMLOOPs for 1 ms */
149*74a4d8c2SCharles.Forsyth
150*74a4d8c2SCharles.Forsyth /*
151*74a4d8c2SCharles.Forsyth * add in possible .2% error and convert to MHz
152*74a4d8c2SCharles.Forsyth */
153*74a4d8c2SCharles.Forsyth m->speed = (cpufreq + cpufreq/500)/1000000;
154*74a4d8c2SCharles.Forsyth }
155