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 * Cortex-a7 has local generic timers per cpu (which we run at 1MHz)
9 * Use system timer 3 (64 bits) for hzclock interrupts and fastticks
10 * For smp on bcm2836, use local generic timer for interrupts on cpu1-3
11 * Use ARM timer (32 bits) for perfticks
12 * Use ARM timer to force immediate interrupt
13 * Use cycle counter for cycles()
17 #include "../port/lib.h"
26 SYSTIMERS = VIRTIO+0x3000,
27 ARMTIMER = VIRTIO+0xB400,
31 Localintpending = 0x60,
34 MaxPeriod = SystimerFreq / HZ,
39 typedef struct Systimers Systimers;
40 typedef struct Armtimer Armtimer;
65 CntPrescaleShift= 16, /* freq is sys_clk/(prescale+1) */
66 CntPrescaleMask = 0xFF,
71 TmrPrescale1 = 0x00<<2,
72 TmrPrescale16 = 0x01<<2,
73 TmrPrescale256 = 0x02<<2,
77 /* generic timer (cortex-a7) */
84 clockintr(Ureg *ureg, void *)
89 panic("cpu%d: unexpected system timer interrupt", m->machno);
90 tn = (Systimers*)SYSTIMERS;
91 /* dismiss interrupt */
97 localclockintr(Ureg *ureg, void *)
100 panic("cpu0: Unexpected local generic timer interrupt");
101 cpwrsc(0, CpTIMER, CpTIMERphys, CpTIMERphysctl, Imask);
110 tm = (Armtimer*)ARMTIMER;
119 u32int t0, t1, tstart, tend;
121 if(((cprdsc(0, CpID, CpIDfeat, 1) >> 16) & 0xF) != 0) {
122 /* generic timer supported */
124 *(ulong*)(ARMLOCAL + Localctl) = 0; /* input clock is 19.2Mhz crystal */
125 *(ulong*)(ARMLOCAL + Prescaler) = 0x06aaaaab; /* divide by (2^31/Prescaler) for 1Mhz */
127 cpwrsc(0, CpTIMER, CpTIMERphys, CpTIMERphysctl, Imask);
128 intrenable(IRQcntpns, localclockintr, nil, 0, "clock");
131 tn = (Systimers*)SYSTIMERS;
135 }while(tn->clo == tstart);
136 tend = tstart + 10000;
139 }while(tn->clo != tend);
142 m->cpumhz = (m->cpuhz + Mhz/2 - 1) / Mhz;
143 m->cyclefreq = m->cpuhz;
145 tn->c3 = tn->clo - 1;
146 tm = (Armtimer*)ARMTIMER;
148 tm->ctl = TmrPrescale1|CntEnable|CntWidth32;
149 intrenable(IRQtimer3, clockintr, nil, 0, "clock");
154 timerset(uvlong next)
160 now = fastticks(nil);
162 if(period < MinPeriod)
164 else if(period > MaxPeriod)
167 cpwrsc(0, CpTIMER, CpTIMERphys, CpTIMERphysval, period);
168 cpwrsc(0, CpTIMER, CpTIMERphys, CpTIMERphysctl, Enable);
170 tn = (Systimers*)SYSTIMERS;
171 tn->c3 = tn->clo + period;
176 fastticks(uvlong *hz)
184 tn = (Systimers*)SYSTIMERS;
188 }while(tn->chi != hi);
189 now = (uvlong)hi<<32 | lo;
198 tm = (Armtimer*)ARMTIMER;
207 tm = (Armtimer*)ARMTIMER;
209 tm->ctl |= TmrEnable|TmrIntEnable;
213 tm->ctl &= ~(TmrEnable|TmrIntEnable);
221 if(SystimerFreq != 1*Mhz)
222 return fastticks2us(fastticks(nil));
223 return ((Systimers*)SYSTIMERS)->clo;
232 while(µs() - now < n);