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
8 * Use system timer 3 (64 bits) for hzclock interrupts and fastticks
9 * For smp on bcm2836, use local generic timer for interrupts on cpu1-3
10 * Use ARM timer (32 bits) for perfticks
11 * Use ARM timer to force immediate interrupt
12 * Use cycle counter for cycles()
16 #include "../port/lib.h"
25 SYSTIMERS = VIRTIO+0x3000,
26 ARMTIMER = VIRTIO+0xB400,
33 MaxPeriod = SystimerFreq / HZ,
37 typedef struct Systimers Systimers;
38 typedef struct Armtimer Armtimer;
63 CntPrescaleShift= 16, /* freq is sys_clk/(prescale+1) */
64 CntPrescaleMask = 0xFF,
69 TmrPrescale1 = 0x00<<2,
70 TmrPrescale16 = 0x01<<2,
71 TmrPrescale256 = 0x02<<2,
75 /* generic timer (cortex-a7) */
82 clockintr(Ureg *ureg, void *)
87 panic("cpu%d: unexpected system timer interrupt", m->machno);
88 tn = (Systimers*)SYSTIMERS;
89 /* dismiss interrupt */
95 localclockintr(Ureg *ureg, void *)
98 panic("cpu0: Unexpected local generic timer interrupt");
107 tm = (Armtimer*)ARMTIMER;
116 ulong t0, t1, tstart, tend;
118 syswr(PMCR_EL0, 1<<6 | 7);
119 syswr(PMCNTENSET, 1<<31);
120 syswr(PMUSERENR_EL0, 1<<2);
122 syswr(CNTP_TVAL_EL0, ~0UL);
124 syswr(CNTP_CTL_EL0, Imask);
126 *(u32int*)(ARMLOCAL + GPUirqroute) = 0;
128 /* input clock to OSC */
129 *(u32int*)(ARMLOCAL + Localctl) = 0;
131 /* divide by (2^31/Prescaler) */
132 *(u32int*)(ARMLOCAL + Prescaler) = (((uvlong)SystimerFreq<<31)/soc.oscfreq)&~1UL;
134 syswr(CNTP_CTL_EL0, Enable);
135 intrenable(IRQcntpns, localclockintr, nil, BUSUNKNOWN, "clock");
138 tn = (Systimers*)SYSTIMERS;
142 }while(tn->clo == tstart);
143 tend = tstart + (SystimerFreq/100);
146 }while(tn->clo < tend);
149 m->cpumhz = (m->cpuhz + Mhz/2 - 1) / Mhz;
150 m->cyclefreq = m->cpuhz;
154 tn->c3 = tn->clo - 1;
155 intrenable(IRQtimer3, clockintr, nil, BUSUNKNOWN, "clock");
157 tm = (Armtimer*)ARMTIMER;
159 tm->ctl = TmrPrescale1|CntEnable|CntWidth32;
164 timerset(uvlong next)
170 now = fastticks(nil);
172 if(period < MinPeriod)
174 else if(period > MaxPeriod)
177 syswr(CNTP_TVAL_EL0, period);
179 tn = (Systimers*)SYSTIMERS;
180 tn->c3 = tn->clo + period;
185 fastticks(uvlong *hz)
193 tn = (Systimers*)SYSTIMERS;
197 }while(tn->chi != hi);
198 now = (uvlong)hi<<32 | lo;
207 tm = (Armtimer*)ARMTIMER;
216 tm = (Armtimer*)ARMTIMER;
218 tm->ctl |= TmrEnable|TmrIntEnable;
222 tm->ctl &= ~(TmrEnable|TmrIntEnable);
230 if(SystimerFreq != 1*Mhz)
231 return fastticks2us(fastticks(nil));
232 return ((Systimers*)SYSTIMERS)->clo;
241 while(µs() - now < n);
260 while(r1.ref != conf.nmach)
262 // syswr(PMCR_EL0, 1<<6 | 7);
264 while(r2.ref != conf.nmach)