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);
126 syswr(CNTP_CTL_EL0, Imask);
128 *(u32int*)(ARMLOCAL + GPUirqroute) = 0;
130 /* bit 1 from OTP bootmode register determines OSC frequency */
131 if(*((u32int*)(VIRTIO+0x20f000)) & (1<<1))
136 /* input clock to OSC */
137 *(u32int*)(ARMLOCAL + Localctl) = 0;
139 /* divide by (2^31/Prescaler) */
140 *(u32int*)(ARMLOCAL + Prescaler) = (((uvlong)SystimerFreq<<31)/oscfreq)&~1UL;
142 syswr(CNTP_CTL_EL0, Enable);
143 intrenable(IRQcntpns, localclockintr, nil, BUSUNKNOWN, "clock");
146 tn = (Systimers*)SYSTIMERS;
150 }while(tn->clo == tstart);
151 tend = tstart + (SystimerFreq/100);
154 }while(tn->clo < tend);
157 m->cpumhz = (m->cpuhz + Mhz/2 - 1) / Mhz;
158 m->cyclefreq = m->cpuhz;
162 tn->c3 = tn->clo - 1;
163 intrenable(IRQtimer3, clockintr, nil, BUSUNKNOWN, "clock");
165 tm = (Armtimer*)ARMTIMER;
167 tm->ctl = TmrPrescale1|CntEnable|CntWidth32;
172 timerset(uvlong next)
178 now = fastticks(nil);
180 if(period < MinPeriod)
182 else if(period > MaxPeriod)
185 syswr(CNTP_TVAL_EL0, period);
187 tn = (Systimers*)SYSTIMERS;
188 tn->c3 = tn->clo + period;
193 fastticks(uvlong *hz)
201 tn = (Systimers*)SYSTIMERS;
205 }while(tn->chi != hi);
206 now = (uvlong)hi<<32 | lo;
215 tm = (Armtimer*)ARMTIMER;
224 tm = (Armtimer*)ARMTIMER;
226 tm->ctl |= TmrEnable|TmrIntEnable;
230 tm->ctl &= ~(TmrEnable|TmrIntEnable);
238 if(SystimerFreq != 1*Mhz)
239 return fastticks2us(fastticks(nil));
240 return ((Systimers*)SYSTIMERS)->clo;
249 while(µs() - now < n);
268 while(r1.ref != conf.nmach)
270 // syswr(PMCR_EL0, 1<<6 | 7);
272 while(r2.ref != conf.nmach)