xref: /inferno-os/os/mpc/cpmtimer.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
1*74a4d8c2SCharles.Forsyth #include "u.h"
2*74a4d8c2SCharles.Forsyth #include "lib.h"
3*74a4d8c2SCharles.Forsyth #include "mem.h"
4*74a4d8c2SCharles.Forsyth #include "dat.h"
5*74a4d8c2SCharles.Forsyth #include "fns.h"
6*74a4d8c2SCharles.Forsyth #include "io.h"
7*74a4d8c2SCharles.Forsyth 
8*74a4d8c2SCharles.Forsyth enum {
9*74a4d8c2SCharles.Forsyth 	Ntimer = 4	/* maximum allowed by hardware */
10*74a4d8c2SCharles.Forsyth };
11*74a4d8c2SCharles.Forsyth 
12*74a4d8c2SCharles.Forsyth static struct {
13*74a4d8c2SCharles.Forsyth 	Lock;
14*74a4d8c2SCharles.Forsyth 	int	init;
15*74a4d8c2SCharles.Forsyth 	int	ntimer;	/* actual timers on this chip revision */
16*74a4d8c2SCharles.Forsyth 	GTimer	t[Ntimer];
17*74a4d8c2SCharles.Forsyth } cpmtimers;
18*74a4d8c2SCharles.Forsyth 
19*74a4d8c2SCharles.Forsyth static	uchar	timerirq[] = {0x19, 0x12, 0x0C, 0x07};
20*74a4d8c2SCharles.Forsyth 
21*74a4d8c2SCharles.Forsyth static	void	gtimerinit(int, ushort*, ushort*);
22*74a4d8c2SCharles.Forsyth 
23*74a4d8c2SCharles.Forsyth static void
gtimerreset(void)24*74a4d8c2SCharles.Forsyth gtimerreset(void)
25*74a4d8c2SCharles.Forsyth {
26*74a4d8c2SCharles.Forsyth 	IMM *io;
27*74a4d8c2SCharles.Forsyth 	int i;
28*74a4d8c2SCharles.Forsyth 
29*74a4d8c2SCharles.Forsyth 	ilock(&cpmtimers);
30*74a4d8c2SCharles.Forsyth 	if(!cpmtimers.init){
31*74a4d8c2SCharles.Forsyth 		if(m->cputype == 0x50 && (getimmr() & 0xFFFF) <= 0x2001)
32*74a4d8c2SCharles.Forsyth 			cpmtimers.ntimer = 2;
33*74a4d8c2SCharles.Forsyth 		else
34*74a4d8c2SCharles.Forsyth 			cpmtimers.ntimer = Ntimer;
35*74a4d8c2SCharles.Forsyth 		io = m->iomem;
36*74a4d8c2SCharles.Forsyth 		io->tgcr = 0x2222;	/* reset timers, low-power stop */
37*74a4d8c2SCharles.Forsyth 		for(i=0; i<cpmtimers.ntimer; i++)
38*74a4d8c2SCharles.Forsyth 			gtimerinit(i, &io->tmr1+i, &io->ter1+i);
39*74a4d8c2SCharles.Forsyth 		cpmtimers.init = 1;
40*74a4d8c2SCharles.Forsyth 	}
41*74a4d8c2SCharles.Forsyth 	iunlock(&cpmtimers);
42*74a4d8c2SCharles.Forsyth }
43*74a4d8c2SCharles.Forsyth 
44*74a4d8c2SCharles.Forsyth static void
gtimerintr(Ureg * ur,void * arg)45*74a4d8c2SCharles.Forsyth gtimerintr(Ureg *ur, void *arg)
46*74a4d8c2SCharles.Forsyth {
47*74a4d8c2SCharles.Forsyth 	GTimer *t;
48*74a4d8c2SCharles.Forsyth 
49*74a4d8c2SCharles.Forsyth 	t = arg;
50*74a4d8c2SCharles.Forsyth 	t->event = *t->ter;
51*74a4d8c2SCharles.Forsyth 	*t->ter = t->event;
52*74a4d8c2SCharles.Forsyth 	if(t->inuse && t->interrupt != nil)
53*74a4d8c2SCharles.Forsyth 		t->interrupt(ur, t->arg, t);
54*74a4d8c2SCharles.Forsyth }
55*74a4d8c2SCharles.Forsyth 
56*74a4d8c2SCharles.Forsyth static void
gtimerinit(int i,ushort * tmr,ushort * ter)57*74a4d8c2SCharles.Forsyth gtimerinit(int i, ushort *tmr, ushort *ter)
58*74a4d8c2SCharles.Forsyth {
59*74a4d8c2SCharles.Forsyth 	GTimer *t;
60*74a4d8c2SCharles.Forsyth 	char name[KNAMELEN];
61*74a4d8c2SCharles.Forsyth 
62*74a4d8c2SCharles.Forsyth 	snprint(name, sizeof(name), "timer.%d", i);
63*74a4d8c2SCharles.Forsyth 	t = &cpmtimers.t[i];
64*74a4d8c2SCharles.Forsyth 	t->x = i*4;	/* field in tgcr */
65*74a4d8c2SCharles.Forsyth 	t->inuse = 0;
66*74a4d8c2SCharles.Forsyth 	t->interrupt = nil;
67*74a4d8c2SCharles.Forsyth 	t->tmr = tmr;
68*74a4d8c2SCharles.Forsyth 	t->trr = tmr+2;
69*74a4d8c2SCharles.Forsyth 	t->tcr = tmr+4;
70*74a4d8c2SCharles.Forsyth 	t->tcn = tmr+6;
71*74a4d8c2SCharles.Forsyth 	t->ter = ter;
72*74a4d8c2SCharles.Forsyth 	intrenable(VectorCPIC+timerirq[i], gtimerintr, t, BUSUNKNOWN, name);
73*74a4d8c2SCharles.Forsyth }
74*74a4d8c2SCharles.Forsyth 
75*74a4d8c2SCharles.Forsyth GTimer*
gtimer(ushort mode,ushort ref,void (* intr)(Ureg *,void *,GTimer *),void * arg)76*74a4d8c2SCharles.Forsyth gtimer(ushort mode, ushort ref, void (*intr)(Ureg*,void*,GTimer*), void *arg)
77*74a4d8c2SCharles.Forsyth {
78*74a4d8c2SCharles.Forsyth 	GTimer *t;
79*74a4d8c2SCharles.Forsyth 	int i;
80*74a4d8c2SCharles.Forsyth 
81*74a4d8c2SCharles.Forsyth 	t = cpmtimers.t;
82*74a4d8c2SCharles.Forsyth 	if(!cpmtimers.init)
83*74a4d8c2SCharles.Forsyth 		gtimerreset();
84*74a4d8c2SCharles.Forsyth 	ilock(&cpmtimers);
85*74a4d8c2SCharles.Forsyth 	for(i=0; ; i++){
86*74a4d8c2SCharles.Forsyth 		if(i >= cpmtimers.ntimer){
87*74a4d8c2SCharles.Forsyth 			iunlock(&cpmtimers);
88*74a4d8c2SCharles.Forsyth 			return nil;
89*74a4d8c2SCharles.Forsyth 		}
90*74a4d8c2SCharles.Forsyth 		if(t->inuse == 0)
91*74a4d8c2SCharles.Forsyth 			break;
92*74a4d8c2SCharles.Forsyth 		t++;
93*74a4d8c2SCharles.Forsyth 	}
94*74a4d8c2SCharles.Forsyth 	t->inuse = 1;
95*74a4d8c2SCharles.Forsyth 	t->interrupt = intr;
96*74a4d8c2SCharles.Forsyth 	t->arg = arg;
97*74a4d8c2SCharles.Forsyth 	m->iomem->tgcr &= ~(0xF<<t->x);	/* reset */
98*74a4d8c2SCharles.Forsyth 	*t->tmr = mode;
99*74a4d8c2SCharles.Forsyth 	*t->tcn = 0;
100*74a4d8c2SCharles.Forsyth 	*t->trr = ref;
101*74a4d8c2SCharles.Forsyth 	*t->ter = 0xFFFF;
102*74a4d8c2SCharles.Forsyth 	iunlock(&cpmtimers);
103*74a4d8c2SCharles.Forsyth 	return t;
104*74a4d8c2SCharles.Forsyth }
105*74a4d8c2SCharles.Forsyth 
106*74a4d8c2SCharles.Forsyth void
gtimerset(GTimer * t,ushort mode,int usec)107*74a4d8c2SCharles.Forsyth gtimerset(GTimer *t, ushort mode, int usec)
108*74a4d8c2SCharles.Forsyth {
109*74a4d8c2SCharles.Forsyth 	ulong ref, ps;
110*74a4d8c2SCharles.Forsyth 	int clk;
111*74a4d8c2SCharles.Forsyth 
112*74a4d8c2SCharles.Forsyth 	if(usec <= 0)
113*74a4d8c2SCharles.Forsyth 		return;
114*74a4d8c2SCharles.Forsyth 	ref = usec*m->speed;
115*74a4d8c2SCharles.Forsyth 	clk = mode & (3<<1);
116*74a4d8c2SCharles.Forsyth 	if(ref >= 0x1000000 && clk == TimerSclk){
117*74a4d8c2SCharles.Forsyth 		mode = (mode & ~clk) | TimerSclk16;
118*74a4d8c2SCharles.Forsyth 		ref >>= 4;
119*74a4d8c2SCharles.Forsyth 	} else if(clk == TimerSclk16)
120*74a4d8c2SCharles.Forsyth 		ref >>= 4;
121*74a4d8c2SCharles.Forsyth 	ps = (ref+(1<<16))/(1<<16);	/* round up */
122*74a4d8c2SCharles.Forsyth 	ref /= ps;
123*74a4d8c2SCharles.Forsyth 	*t->tmr = ((ps-1)<<8) | (mode&0xFF);
124*74a4d8c2SCharles.Forsyth 	*t->trr = ref;
125*74a4d8c2SCharles.Forsyth }
126*74a4d8c2SCharles.Forsyth 
127*74a4d8c2SCharles.Forsyth void
gtimerstart(GTimer * t)128*74a4d8c2SCharles.Forsyth gtimerstart(GTimer *t)
129*74a4d8c2SCharles.Forsyth {
130*74a4d8c2SCharles.Forsyth 	if(t){
131*74a4d8c2SCharles.Forsyth 		ilock(&cpmtimers);
132*74a4d8c2SCharles.Forsyth 		m->iomem->tgcr = (m->iomem->tgcr & ~(0xF<<t->x)) | (1<<t->x);	/* enable */
133*74a4d8c2SCharles.Forsyth 		iunlock(&cpmtimers);
134*74a4d8c2SCharles.Forsyth 	}
135*74a4d8c2SCharles.Forsyth }
136*74a4d8c2SCharles.Forsyth 
137*74a4d8c2SCharles.Forsyth void
gtimerstop(GTimer * t)138*74a4d8c2SCharles.Forsyth gtimerstop(GTimer *t)
139*74a4d8c2SCharles.Forsyth {
140*74a4d8c2SCharles.Forsyth 	if(t){
141*74a4d8c2SCharles.Forsyth 		ilock(&cpmtimers);
142*74a4d8c2SCharles.Forsyth 		m->iomem->tgcr |= 2<<t->x;	/* stop */
143*74a4d8c2SCharles.Forsyth 		iunlock(&cpmtimers);
144*74a4d8c2SCharles.Forsyth 	}
145*74a4d8c2SCharles.Forsyth }
146*74a4d8c2SCharles.Forsyth 
147*74a4d8c2SCharles.Forsyth void
gtimerfree(GTimer * t)148*74a4d8c2SCharles.Forsyth gtimerfree(GTimer *t)
149*74a4d8c2SCharles.Forsyth {
150*74a4d8c2SCharles.Forsyth 	if(t){
151*74a4d8c2SCharles.Forsyth 		ilock(&cpmtimers);
152*74a4d8c2SCharles.Forsyth 		t->inuse = 0;
153*74a4d8c2SCharles.Forsyth 		*t->tmr = 0;	/* disable interrupts */
154*74a4d8c2SCharles.Forsyth 		*t->ter = 0xFFFF;
155*74a4d8c2SCharles.Forsyth 		m->iomem->tgcr = (m->iomem->tgcr & ~(0xF<<t->x)) | (2<<t->x);	/* reset and stop */
156*74a4d8c2SCharles.Forsyth 		iunlock(&cpmtimers);
157*74a4d8c2SCharles.Forsyth 	}
158*74a4d8c2SCharles.Forsyth }
159*74a4d8c2SCharles.Forsyth 
160*74a4d8c2SCharles.Forsyth #ifdef GTIMETEST
161*74a4d8c2SCharles.Forsyth static void
gtintr(Ureg *,void *,GTimer *)162*74a4d8c2SCharles.Forsyth gtintr(Ureg*, void*, GTimer*)
163*74a4d8c2SCharles.Forsyth {
164*74a4d8c2SCharles.Forsyth 	m->bcsr[4] ^= DisableVideoLamp;	/* toggle an LED */
165*74a4d8c2SCharles.Forsyth }
166*74a4d8c2SCharles.Forsyth 
167*74a4d8c2SCharles.Forsyth void
gtimetest(void)168*74a4d8c2SCharles.Forsyth gtimetest(void)
169*74a4d8c2SCharles.Forsyth {
170*74a4d8c2SCharles.Forsyth 	GTimer *g;
171*74a4d8c2SCharles.Forsyth 
172*74a4d8c2SCharles.Forsyth 	g = gtimer(0, 0, gtintr, nil);
173*74a4d8c2SCharles.Forsyth 	gtimerset(g, TimerORI|TimerRestart|TimerSclk, 64000);
174*74a4d8c2SCharles.Forsyth 	gtimerstart(g);
175*74a4d8c2SCharles.Forsyth 	delay(1);
176*74a4d8c2SCharles.Forsyth print("started timer: #%4.4ux #%4.4ux %8.8lux #%4.4ux #%4.4ux\n", *g->tmr, *g->trr, m->iomem->tgcr, *g->tcn, *g->ter);
177*74a4d8c2SCharles.Forsyth print("ter=#%8.8lux tmr=#%8.8lux trr=#%8.8lux\n", g->ter, g->tmr, g->trr);
178*74a4d8c2SCharles.Forsyth }
179*74a4d8c2SCharles.Forsyth #endif
180