Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * bcm2835 timers
3
 *	System timers run at 1MHz (timers 1 and 2 are used by GPU)
4
 *	ARM timer usually runs at 250MHz (may be slower in low power modes)
5
 *	Cycle counter runs at 700MHz (unless overclocked)
6
 *    All are free-running up-counters
7
 *
8
 * Use system timer 3 (64 bits) for hzclock interrupts and fastticks
9
 * Use ARM timer (32 bits) for perfticks
10
 * Use ARM timer to force immediate interrupt
11
 * Use cycle counter for cycles()
12
 */
13
 
14
#include "u.h"
15
#include "../port/lib.h"
16
#include "mem.h"
17
#include "dat.h"
18
#include "fns.h"
19
#include "io.h"
20
 
21
enum {
22
	SYSTIMERS	= VIRTIO+0x3000,
23
	ARMTIMER	= VIRTIO+0xB400,
24
 
25
	SystimerFreq	= 1*Mhz,
26
	MaxPeriod	= SystimerFreq / HZ,
27
	MinPeriod	= SystimerFreq / (100*HZ),
28
};
29
 
30
typedef struct Systimers Systimers;
31
typedef struct Armtimer Armtimer;
32
 
33
struct Systimers {
34
	u32int	cs;
35
	u32int	clo;
36
	u32int	chi;
37
	u32int	c0;
38
	u32int	c1;
39
	u32int	c2;
40
	u32int	c3;
41
};
42
 
43
struct Armtimer {
44
	u32int	load;
45
	u32int	val;
46
	u32int	ctl;
47
	u32int	irqack;
48
	u32int	irq;
49
	u32int	maskedirq;
50
	u32int	reload;
51
	u32int	predivider;
52
	u32int	count;
53
};
54
 
55
enum {
56
	CntPrescaleShift= 16,	/* freq is sys_clk/(prescale+1) */
57
	CntPrescaleMask	= 0xFF,
58
	CntEnable	= 1<<9,
59
	TmrDbgHalt	= 1<<8,
60
	TmrEnable	= 1<<7,
61
	TmrIntEnable	= 1<<5,
62
	TmrPrescale1	= 0x00<<2,
63
	TmrPrescale16	= 0x01<<2,
64
	TmrPrescale256	= 0x02<<2,
65
	CntWidth16	= 0<<1,
66
	CntWidth32	= 1<<1,
67
};
68
 
69
static void
70
clockintr(Ureg *ureg, void *)
71
{
72
	Systimers *tn;
73
 
74
	tn = (Systimers*)SYSTIMERS;
75
	/* dismiss interrupt */
76
	tn->cs = 1<<3;
77
	timerintr(ureg, 0);
78
}
79
 
80
void
81
clockshutdown(void)
82
{
83
	Armtimer *tm;
84
 
85
	tm = (Armtimer*)ARMTIMER;
86
	tm->ctl = 0;
87
	wdogoff();
88
}
89
 
90
void
91
clockinit(void)
92
{
93
	Systimers *tn;
94
	Armtimer *tm;
95
	u32int t0, t1, tstart, tend;
96
 
97
	tn = (Systimers*)SYSTIMERS;
98
	tm = (Armtimer*)ARMTIMER;
99
	tm->load = 0;
100
	tm->ctl = TmrPrescale1|CntEnable|CntWidth32;
101
 
102
	tstart = tn->clo;
103
	do{
104
		t0 = lcycles();
105
	}while(tn->clo == tstart);
106
	tend = tstart + 10000;
107
	do{
108
		t1 = lcycles();
109
	}while(tn->clo != tend);
110
	t1 -= t0;
111
	m->cpuhz = 100 * t1;
112
	m->cpumhz = (m->cpuhz + Mhz/2 - 1) / Mhz;
113
	m->cyclefreq = m->cpuhz;
114
 
115
	tn->c3 = tn->clo - 1;
116
	intrenable(IRQtimer3, clockintr, nil, 0, "clock");
117
}
118
 
119
void
120
timerset(uvlong next)
121
{
122
	Systimers *tn;
123
	vlong now, period;
124
 
125
	tn = (Systimers*)SYSTIMERS;
126
	now = fastticks(nil);
127
	period = next - fastticks(nil);
128
	if(period < MinPeriod)
129
		next = now + MinPeriod;
130
	else if(period > MaxPeriod)
131
		next = now + MaxPeriod;
132
	tn->c3 = (ulong)next;
133
}
134
 
135
uvlong
136
fastticks(uvlong *hz)
137
{
138
	Systimers *tn;
139
	ulong lo, hi;
140
 
141
	tn = (Systimers*)SYSTIMERS;
142
	if(hz)
143
		*hz = SystimerFreq;
144
	do{
145
		hi = tn->chi;
146
		lo = tn->clo;
147
	}while(tn->chi != hi);
148
	m->fastclock = (uvlong)hi<<32 | lo;
149
	return m->fastclock;
150
}
151
 
152
ulong
153
perfticks(void)
154
{
155
	Armtimer *tm;
156
 
157
	tm = (Armtimer*)ARMTIMER;
158
	return tm->count;
159
}
160
 
161
void
162
armtimerset(int n)
163
{
164
	Armtimer *tm;
165
 
166
	tm = (Armtimer*)ARMTIMER;
167
	if(n > 0){
168
		tm->ctl |= TmrEnable|TmrIntEnable;
169
		tm->load = n;
170
	}else{
171
		tm->load = 0;
172
		tm->ctl &= ~(TmrEnable|TmrIntEnable);
173
		tm->irq = 1;
174
	}
175
}
176
 
177
ulong
178
µs(void)
179
{
180
	if(SystimerFreq != 1*Mhz)
181
		return fastticks2us(fastticks(nil));
182
	return fastticks(nil);
183
}
184
 
185
void
186
microdelay(int n)
187
{
188
	Systimers *tn;
189
	u32int now, diff;
190
 
191
	tn = (Systimers*)SYSTIMERS;
192
	diff = n + 1;
193
	now = tn->clo;
194
	while(tn->clo - now < diff)
195
		;
196
}
197
 
198
void
199
delay(int n)
200
{
201
	while(--n >= 0)
202
		microdelay(1000);
203
}