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 * All are free-running up-counters
7 * Use system timer 3 (64 bits) for hzclock interrupts and fastticks
8 * For smp on bcm2836, use local generic timer for interrupts on cpu1-3
9 * Use ARM timer (32 bits) for perfticks
10 * Use ARM timer to force immediate interrupt
11 * Use performance cycle counter for lcycles()
12 * Use generic timer virtual 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);
121 syswr(CNTKCTL_EL1, 1<<1);
123 syswr(CNTP_TVAL_EL0, ~0UL);
125 syswr(CNTP_CTL_EL0, Imask);
127 *(u32int*)(ARMLOCAL + GPUirqroute) = 0;
129 /* input clock to OSC */
130 *(u32int*)(ARMLOCAL + Localctl) = 0;
132 /* divide by (2^31/Prescaler) */
133 *(u32int*)(ARMLOCAL + Prescaler) = (((uvlong)SystimerFreq<<31)/soc.oscfreq)&~1UL;
135 syswr(CNTP_CTL_EL0, Enable);
136 intrenable(IRQcntpns, localclockintr, nil, BUSUNKNOWN, "clock");
139 tn = (Systimers*)SYSTIMERS;
143 }while(tn->clo == tstart);
144 tend = tstart + (SystimerFreq/100);
147 }while(tn->clo < tend);
150 m->cpumhz = (m->cpuhz + Mhz/2 - 1) / Mhz;
153 * Cyclefreq used to be the same as cpuhz as
154 * we where using the PMCCNTR_EL0 which counts
155 * per core cpu cycles. But is is kind of useless
156 * in userspace because each core has a differnet
157 * counter and it stops when the core is idle (WFI).
158 * So we change it to use the generic timer
159 * virtual counter register CNTVCT_EL0 instead
160 * running at the same frequency as system timer.
161 * (CNTFRQ_EL0 is WRONG on raspberry pi).
163 m->cyclefreq = SystimerFreq;
167 tn->c3 = tn->clo - 1;
168 intrenable(IRQtimer3, clockintr, nil, BUSUNKNOWN, "clock");
170 tm = (Armtimer*)ARMTIMER;
172 tm->ctl = TmrPrescale1|CntEnable|CntWidth32;
177 timerset(uvlong next)
183 now = fastticks(nil);
185 if(period < MinPeriod)
187 else if(period > MaxPeriod)
190 syswr(CNTP_TVAL_EL0, period);
192 tn = (Systimers*)SYSTIMERS;
193 tn->c3 = tn->clo + period;
198 fastticks(uvlong *hz)
206 tn = (Systimers*)SYSTIMERS;
210 }while(tn->chi != hi);
211 now = (uvlong)hi<<32 | lo;
220 tm = (Armtimer*)ARMTIMER;
229 tm = (Armtimer*)ARMTIMER;
231 tm->ctl |= TmrEnable|TmrIntEnable;
235 tm->ctl &= ~(TmrEnable|TmrIntEnable);
243 if(SystimerFreq != 1*Mhz)
244 return fastticks2us(fastticks(nil));
245 return ((Systimers*)SYSTIMERS)->clo;
254 while(µs() - now < n);
273 while(r1.ref != conf.nmach)
275 // syswr(PMCR_EL0, 1<<6 | 7);
277 while(r2.ref != conf.nmach)