* bcm283[56] timers
* System timers run at 1MHz (timers 1 and 2 are used by GPU)
* ARM timer usually runs at 250MHz (may be slower in low power modes)
- * Cycle counter runs at 700MHz (unless overclocked)
* All are free-running up-counters
*
* Use system timer 3 (64 bits) for hzclock interrupts and fastticks
* For smp on bcm2836, use local generic timer for interrupts on cpu1-3
* Use ARM timer (32 bits) for perfticks
* Use ARM timer to force immediate interrupt
- * Use cycle counter for cycles()
+ * Use performance cycle counter for lcycles()
+ * Use generic timer virtual counter for cycles()
*/
#include "u.h"
syswr(PMCR_EL0, 1<<6 | 7);
syswr(PMCNTENSET, 1<<31);
syswr(PMUSERENR_EL0, 1<<2);
+ syswr(CNTKCTL_EL1, 1<<1);
syswr(CNTP_TVAL_EL0, ~0UL);
if(m->machno == 0){
t1 -= t0;
m->cpuhz = 100 * t1;
m->cpumhz = (m->cpuhz + Mhz/2 - 1) / Mhz;
- m->cyclefreq = m->cpuhz;
+
+ /*
+ * Cyclefreq used to be the same as cpuhz as
+ * we where using the PMCCNTR_EL0 which counts
+ * per core cpu cycles. But is is kind of useless
+ * in userspace because each core has a differnet
+ * counter and it stops when the core is idle (WFI).
+ * So we change it to use the generic timer
+ * virtual counter register CNTVCT_EL0 instead
+ * running at the same frequency as system timer.
+ * (CNTFRQ_EL0 is WRONG on raspberry pi).
+ */
+ m->cyclefreq = SystimerFreq;
if(m->machno == 0){
tn->cs = 1<<3;
#define PMUSERENR_EL0 SYSREG(3,3,9,14,0)
#define CNTPCT_EL0 SYSREG(3,3,14,0,1)
+#define CNTVCT_EL0 SYSREG(3,3,14,0,2)
+#define CNTKCTL_EL1 SYSREG(3,0,14,1,0)
#define CNTP_TVAL_EL0 SYSREG(3,3,14,2,0)
#define CNTP_CTL_EL0 SYSREG(3,3,14,2,1)
#define CNTP_CVAL_EL0 SYSREG(3,3,14,2,2)
#define SYSREG(op0,op1,Cn,Cm,op2) SPR(((op0)<<19|(op1)<<16|(Cn)<<12|(Cm)<<8|(op2)<<5))
-#define PMCCNTR_EL0 SYSREG(3,3,9,13,0)
+#define CNTVCT_EL0 SYSREG(3,3,14,0,2)
TEXT cycles(SB), 1, $-4
- MRS PMCCNTR_EL0, R1
+ MRS CNTVCT_EL0, R1
MOV R1, (R0)
RETURN