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