xref: /inferno-os/os/boot/puma/clock.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
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