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