Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * ar7161 clocks and timers
3
 */
4
#include	"u.h"
5
#include	"../port/lib.h"
6
#include	"mem.h"
7
#include	"dat.h"
8
#include	"fns.h"
9
#include	"io.h"
10
 
11
#include	"ureg.h"
12
 
13
enum {
14
	Cyccntres	= 2, /* counter advances at ½ clock rate (mips 24k) */
15
	Basetickfreq	= 680*Mhz / Cyccntres,	/* rb450g */
16
};
17
 
18
void (*kproftimer)(ulong);
19
 
20
void
21
silencewdog(void)
22
{
23
	*Rstwdogtimer = Basetickfreq * 2 * 5;	/* pet the dog */
24
}
25
 
26
void
27
sicwdog(void)
28
{
29
	*Rstwdogtimer = Basetickfreq * 2;
30
	*Rstwdogctl = Wdogreset;		/* wake the dog */
31
}
32
 
33
void
34
wdogreset(void)
35
{
36
	*Rstwdogtimer = Basetickfreq / 100;
37
	*Rstwdogctl = Wdogreset;		/* wake the dog */
38
	coherence();
39
	*Rstwdogtimer = Basetickfreq / 10000;
40
	coherence();
41
}
42
 
43
void
44
stopwdog(void)
45
{
46
	*Rstwdogtimer = ~0;
47
	*Rstwdogctl = Wdognoaction;		/* put the dog to sleep */
48
}
49
 
50
void
51
clockshutdown(void)
52
{
53
	stopwdog();
54
}
55
 
56
/*
57
 *  delay for l milliseconds more or less.
58
 */
59
void
60
delay(int l)
61
{
62
	while(l-- > 0)
63
		microdelay(1000);
64
}
65
 
66
/*
67
 *  microseconds delay
68
 */
69
void
70
microdelay(int l)
71
{
72
	int s;
73
	ulong x, cyc, cnt, speed;
74
 
75
	speed = m->speed;
76
	if (speed == 0)
77
		speed = Basetickfreq / Mhz * Cyccntres;
78
	cyc = (ulong)l * (speed / Cyccntres);
79
	s = splhi();
80
	cnt = rdcount();
81
	x = cnt + cyc;
82
	if (x < cnt || x >= ~0ul - Basetickfreq) {
83
		/* counter will wrap between now and x, or x is too near ~0 */
84
		wrcount(0);			/* somewhat drastic */
85
		wrcompare(rdcompare() - cnt);	/* match new count */
86
		x = cyc;
87
	}
88
	while(rdcount() < x)
89
		;
90
	splx(s);
91
	silencewdog();
92
}
93
 
94
void
95
clock(Ureg *ureg)
96
{
97
	wrcompare(rdcount()+m->maxperiod);	/* side-effect: dismiss intr */
98
	silencewdog();
99
	timerintr(ureg, 0);
100
}
101
 
102
enum {
103
	Instrs		= 10*Mhz,
104
};
105
 
106
static long
107
issue1loop(void)
108
{
109
	register int i;
110
	long st;
111
 
112
	i = Instrs;
113
	st = perfticks();
114
	do {
115
		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
116
		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
117
		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
118
		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
119
		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
120
		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
121
		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
122
		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
123
		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
124
		--i; --i; --i; --i; --i;
125
		/* omit 3 (--i) to account for conditional branch, nop & jump */
126
		i -= 1+3;	 /* --i plus 3 omitted (--i) instructions */
127
	} while(--i >= 0);
128
	return perfticks() - st;
129
}
130
 
131
/* estimate instructions/s. */
132
static int
133
guessmips(long (*loop)(void), char *)
134
{
135
	int s;
136
	long cyc;
137
 
138
	do {
139
		s = splhi();
140
		cyc = loop();
141
		splx(s);
142
		if (cyc < 0)
143
			iprint("again...");
144
	} while (cyc < 0);
145
	/*
146
	 * Instrs instructions took cyc cycles @ Basetickfreq Hz.
147
	 * round the result.
148
	 */
149
	return (((vlong)Basetickfreq * Instrs) / cyc + Mhz/2) / Mhz;
150
}
151
 
152
void
153
clockinit(void)
154
{
155
	int mips;
156
 
157
	silencewdog();
158
 
159
	/*
160
	 * calibrate fastclock
161
	 */
162
	mips = guessmips(issue1loop, "single");
163
 
164
	/*
165
	 * m->delayloop should be the number of delay loop iterations
166
	 * needed to consume 1 ms, assuming 2 instr'ns in the delay loop.
167
	 */
168
	m->delayloop = mips*Mhz / (1000 * 2);
169
	if(m->delayloop == 0)
170
		m->delayloop = 1;
171
 
172
	m->speed = mips;
173
	m->hz = m->speed*Mhz;
174
 
175
	m->maxperiod = Basetickfreq / HZ;
176
	m->minperiod = Basetickfreq / (100*HZ);
177
	wrcompare(rdcount()+m->maxperiod);
178
 
179
	/*
180
	 *  desynchronize the processor clocks so that they all don't
181
	 *  try to resched at the same time.
182
	 */
183
	delay(m->machno*2);
184
 
185
	syncclock();
186
	intron(INTR7);
187
}
188
 
189
/*
190
 * Tval is supposed to be in fastticks units.
191
 * One fasttick unit is 1/Basetickfreq seconds.
192
 */
193
void
194
timerset(Tval next)
195
{
196
	int x;
197
	long period;
198
 
199
	if(next == 0)
200
		return;
201
	x = splhi();			/* don't let us get scheduled */
202
	period = next - fastticks(nil);
203
	if(period > m->maxperiod - m->minperiod)
204
		period = m->maxperiod;
205
	else if(period < m->minperiod)
206
		period = m->minperiod;
207
	wrcompare(rdcount()+period);
208
	silencewdog();
209
	splx(x);
210
}
211
 
212
/*
213
 *  The rewriting of compare in this routine shouldn't be necessary.
214
 *  However, we lose clock interrupts if I don't, either a chip bug
215
 *  or one of ours -- presotto
216
 */
217
uvlong
218
fastticks(uvlong *hz)
219
{
220
	int x;
221
	ulong delta, count;
222
 
223
	if(hz)
224
		*hz = Basetickfreq;
225
 
226
	/* avoid reentry on interrupt or trap, to prevent recursion */
227
	x = splhi();
228
	count = rdcount();
229
	if(rdcompare() - count > m->maxperiod)
230
		wrcompare(count+m->maxperiod);
231
	silencewdog();
232
 
233
	if (count < m->lastcount)		/* wrapped around? */
234
		delta = count + ((1ull<<32) - m->lastcount);
235
	else
236
		delta = count - m->lastcount;
237
	m->lastcount = count;
238
	m->fastticks += delta;
239
	splx(x);
240
	return m->fastticks;
241
}
242
 
243
ulong
244
µs(void)
245
{
246
	return fastticks2us(fastticks(nil));
247
}
248
 
249
/*
250
 *  performance measurement ticks.  must be low overhead.
251
 *  doesn't have to count over a second.
252
 */
253
ulong
254
perfticks(void)
255
{
256
	return rdcount();
257
}
258
 
259
long
260
lcycles(void)
261
{
262
	return perfticks();
263
}
264
 
265
/* should use vlong hw counters ideally; lcycles is inadequate */
266
void
267
cycles(uvlong *cycp)
268
{
269
	*cycp = fastticks(nil);
270
}
271
 
272
Lock mpsynclock;
273
 
274
/*
275
 *  synchronize all clocks with processor 0
276
 */
277
void
278
syncclock(void)
279
{
280
	uvlong x;
281
 
282
	if(m->machno == 0){
283
		m->lastcount = rdcount();
284
		m->fastticks = 0;
285
		m->ticks = 0;
286
		wrcompare(rdcount()+m->maxperiod);
287
	} else {
288
		/* wait for processor 0's soft clock to change and then sync ours */
289
		lock(&mpsynclock);
290
		x = MACHP(0)->fastticks;
291
		while(MACHP(0)->fastticks == x)
292
			;
293
		m->lastcount = rdcount();
294
		m->fastticks = MACHP(0)->fastticks;
295
		m->ticks = MACHP(0)->ticks;
296
		wrcompare(rdcount()+m->maxperiod);
297
		unlock(&mpsynclock);
298
	}
299
}