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,
33 MaxPeriod = SystimerFreq / HZ,
38 typedef struct Systimers Systimers;
39 typedef struct Armtimer Armtimer;
64 CntPrescaleShift= 16, /* freq is sys_clk/(prescale+1) */
65 CntPrescaleMask = 0xFF,
70 TmrPrescale1 = 0x00<<2,
71 TmrPrescale16 = 0x01<<2,
72 TmrPrescale256 = 0x02<<2,
76 /* generic timer (cortex-a7) */
83 clockintr(Ureg *ureg, void *)
88 panic("cpu%d: unexpected system timer interrupt", m->machno);
89 tn = (Systimers*)SYSTIMERS;
90 /* dismiss interrupt */
96 localclockintr(Ureg *ureg, void *)
99 panic("cpu0: Unexpected local generic timer interrupt");
108 tm = (Armtimer*)ARMTIMER;
117 ulong t0, t1, tstart, tend;
119 if(((cprdsc(0, CpID, CpIDfeat, 1) >> 16) & 0xF) != 0) {
120 /* generic timer supported */
121 cpwrsc(0, CpTIMER, CpTIMERphys, CpTIMERphysval, ~0);
123 cpwrsc(0, CpTIMER, CpTIMERphys, CpTIMERphysctl, Imask);
125 /* input clock is 19.2Mhz crystal */
126 *(ulong*)(ARMLOCAL + Localctl) = 0;
127 /* divide by (2^31/Prescaler) */
128 *(ulong*)(ARMLOCAL + Prescaler) = (((uvlong)SystimerFreq<<31)/19200000)&~1UL;
130 cpwrsc(0, CpTIMER, CpTIMERphys, CpTIMERphysctl, Enable);
131 intrenable(IRQcntpns, localclockintr, nil, 0, "clock");
135 tn = (Systimers*)SYSTIMERS;
139 }while(tn->clo == tstart);
140 tend = tstart + (SystimerFreq/100);
143 }while(tn->clo != tend);
146 m->cpumhz = (m->cpuhz + Mhz/2 - 1) / Mhz;
147 m->cyclefreq = m->cpuhz;
150 tn->c3 = tn->clo - 1;
151 intrenable(IRQtimer3, clockintr, nil, 0, "clock");
153 tm = (Armtimer*)ARMTIMER;
155 tm->ctl = TmrPrescale1|CntEnable|CntWidth32;
160 timerset(uvlong next)
166 now = fastticks(nil);
168 if(period < MinPeriod)
170 else if(period > MaxPeriod)
173 cpwrsc(0, CpTIMER, CpTIMERphys, CpTIMERphysval, period);
175 tn = (Systimers*)SYSTIMERS;
176 tn->c3 = tn->clo + period;
181 fastticks(uvlong *hz)
189 tn = (Systimers*)SYSTIMERS;
193 }while(tn->chi != hi);
194 now = (uvlong)hi<<32 | lo;
203 tm = (Armtimer*)ARMTIMER;
212 tm = (Armtimer*)ARMTIMER;
214 tm->ctl |= TmrEnable|TmrIntEnable;
218 tm->ctl &= ~(TmrEnable|TmrIntEnable);
226 if(SystimerFreq != 1*Mhz)
227 return fastticks2us(fastticks(nil));
228 return ((Systimers*)SYSTIMERS)->clo;
237 while(µs() - now < n);