Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
66
clockshutdown(void)
67
{
68
	TimerReg *tmr = (TimerReg *)soc.clock;
69
 
70
	tmr->ctl = 0;
71
	coherence();
72
}
73
 
74
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
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
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
164
perfticks(void)
165
{
166
	TimerReg *tmr = (TimerReg *)soc.clock;
167
 
168
	return ~tmr->timer1;
169
}
170
 
171
long
172
lcycles(void)
173
{
174
	return perfticks();
175
}
176
 
177
ulong
178
µs(void)
179
{
180
	return fastticks2us(fastticks(nil));
181
}
182
 
183
void
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
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
}