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
clockintr(Ureg * ureg,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
clockshutdown(void)81 clockshutdown(void)
82 {
83 Armtimer *tm;
84
85 tm = (Armtimer*)ARMTIMER;
86 tm->ctl = 0;
87 wdogoff();
88 }
89
90 void
clockinit(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
timerset(uvlong next)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
fastticks(uvlong * hz)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
perfticks(void)153 perfticks(void)
154 {
155 Armtimer *tm;
156
157 tm = (Armtimer*)ARMTIMER;
158 return tm->count;
159 }
160
161 void
armtimerset(int n)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
s(void)178 µs(void)
179 {
180 if(SystimerFreq != 1*Mhz)
181 return fastticks2us(fastticks(nil));
182 return fastticks(nil);
183 }
184
185 void
microdelay(int n)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
delay(int n)199 delay(int n)
200 {
201 while(--n >= 0)
202 microdelay(1000);
203 }
204