1 /*
2 * kirkwood clocks
3 *
4 * timers count down to zero.
5 */
6 #include "u.h"
7 #include "../port/lib.h"
8 #include "mem.h"
9 #include "dat.h"
10 #include "fns.h"
11 #include "io.h"
12
13 #include "ureg.h"
14
15 enum {
16 Tcycles = CLOCKFREQ / HZ, /* cycles per clock tick */
17 Dogperiod = 15 * CLOCKFREQ, /* at most 21 s.; must fit in ulong */
18 MaxPeriod = Tcycles,
19 MinPeriod = MaxPeriod / 100,
20
21 /* timer ctl bits */
22 Tmr0enable = 1<<0,
23 Tmr0reload = 1<<1, /* at 0 count, load timer0 from reload0 */
24 Tmr1enable = 1<<2,
25 Tmr1reload = 1<<3, /* at 0 count, load timer1 from reload1 */
26 TmrWDenable = 1<<4,
27 TmrWDreload = 1<<5,
28 };
29
30 typedef struct TimerReg TimerReg;
31 struct TimerReg
32 {
33 ulong ctl;
34 ulong pad[3];
35 ulong reload0;
36 ulong timer0; /* cycles until zero */
37 ulong reload1;
38 ulong timer1; /* cycles until zero */
39 ulong reloadwd;
40 ulong timerwd;
41 };
42
43 static int ticks; /* for sanity checking; m->ticks doesn't always get updated */
44
45 static void
clockintr(Ureg * ureg,void * arg)46 clockintr(Ureg *ureg, void *arg)
47 {
48 TimerReg *tmr = arg;
49 static int nesting;
50
51 tmr->timerwd = Dogperiod; /* reassure the watchdog */
52 ticks++;
53 coherence();
54
55 if (nesting == 0) { /* if the clock interrupted itself, bail out */
56 ++nesting;
57 timerintr(ureg, 0);
58 --nesting;
59 }
60
61 intrclear(Irqbridge, IRQcputimer0);
62 }
63
64 /* stop clock interrupts and disable the watchdog timer */
65 void
clockshutdown(void)66 clockshutdown(void)
67 {
68 TimerReg *tmr = (TimerReg *)soc.clock;
69
70 tmr->ctl = 0;
71 coherence();
72 }
73
74 void
clockinit(void)75 clockinit(void)
76 {
77 int i, s;
78 CpucsReg *cpu = (CpucsReg *)soc.cpu;
79 TimerReg *tmr = (TimerReg *)soc.clock;
80
81 clockshutdown();
82
83 /*
84 * verify sanity of timer0
85 */
86
87 intrenable(Irqbridge, IRQcputimer0, clockintr, tmr, "clock0");
88 s = spllo(); /* risky */
89 /* take any deferred clock (& other) interrupts here */
90 splx(s);
91
92 /* adjust m->bootdelay, used by delay()? */
93 m->ticks = ticks = 0;
94 m->fastclock = 0;
95
96 tmr->timer0 = 1;
97 tmr->ctl = Tmr0enable; /* just once */
98 coherence();
99
100 s = spllo(); /* risky */
101 for (i = 0; i < 10 && ticks == 0; i++) {
102 delay(1);
103 coherence();
104 }
105 splx(s);
106 if (ticks == 0) {
107 serialputc('?');
108 if (tmr->timer0 == 0)
109 panic("clock not interrupting");
110 else if (tmr->timer0 == tmr->reload0)
111 panic("clock not ticking");
112 else
113 panic("clock running very slowly");
114 }
115
116 /*
117 * configure all timers
118 */
119 clockshutdown();
120 tmr->reload0 = tmr->timer0 = Tcycles; /* tick clock */
121 tmr->reload1 = tmr->timer1 = ~0; /* cycle clock */
122 tmr->timerwd = Dogperiod; /* watch dog timer */
123 coherence();
124 tmr->ctl = Tmr0enable | Tmr0reload | Tmr1enable | Tmr1reload |
125 TmrWDenable;
126 cpu->rstout |= RstoutWatchdog;
127 coherence();
128 }
129
130 void
timerset(Tval next)131 timerset(Tval next)
132 {
133 int offset;
134 TimerReg *tmr = (TimerReg *)soc.clock;
135
136 offset = next - fastticks(nil);
137 if(offset < MinPeriod)
138 offset = MinPeriod;
139 else if(offset > MaxPeriod)
140 offset = MaxPeriod;
141 tmr->timer0 = offset;
142 coherence();
143 }
144
145 uvlong
fastticks(uvlong * hz)146 fastticks(uvlong *hz)
147 {
148 uvlong now;
149 int s;
150
151 if(hz)
152 *hz = CLOCKFREQ;
153 s = splhi();
154 /* zero low ulong of fastclock */
155 now = (m->fastclock & ~(uvlong)~0ul) | perfticks();
156 if(now < m->fastclock) /* low bits must have wrapped */
157 now += 1ll << 32;
158 m->fastclock = now;
159 splx(s);
160 return now;
161 }
162
163 ulong
perfticks(void)164 perfticks(void)
165 {
166 TimerReg *tmr = (TimerReg *)soc.clock;
167
168 return ~tmr->timer1;
169 }
170
171 long
lcycles(void)172 lcycles(void)
173 {
174 return perfticks();
175 }
176
177 ulong
s(void)178 µs(void)
179 {
180 return fastticks2us(fastticks(nil));
181 }
182
183 void
microdelay(int l)184 microdelay(int l)
185 {
186 int i;
187
188 l *= m->delayloop;
189 l /= 1000;
190 if(l <= 0)
191 l = 1;
192 for(i = 0; i < l; i++)
193 ;
194 }
195
196 void
delay(int l)197 delay(int l)
198 {
199 ulong i, j;
200
201 j = m->delayloop;
202 while(l-- > 0)
203 for(i=0; i < j; i++)
204 ;
205 }
206