1 /* 2 * bcm2835 timers 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 * 8 * Use system timer 3 (64 bits) for hzclock interrupts and fastticks 9 * Use ARM timer (32 bits) for perfticks 10 * Use ARM timer to force immediate interrupt 11 * Use cycle counter for cycles() 12 */ 13 14 #include "u.h" 15 #include "../port/lib.h" 16 #include "mem.h" 17 #include "dat.h" 18 #include "fns.h" 19 #include "io.h" 20 21 enum { 22 SYSTIMERS = VIRTIO+0x3000, 23 ARMTIMER = VIRTIO+0xB400, 24 25 SystimerFreq = 1*Mhz, 26 MaxPeriod = SystimerFreq / HZ, 27 MinPeriod = SystimerFreq / (100*HZ), 28 }; 29 30 typedef struct Systimers Systimers; 31 typedef struct Armtimer Armtimer; 32 33 struct Systimers { 34 u32int cs; 35 u32int clo; 36 u32int chi; 37 u32int c0; 38 u32int c1; 39 u32int c2; 40 u32int c3; 41 }; 42 43 struct Armtimer { 44 u32int load; 45 u32int val; 46 u32int ctl; 47 u32int irqack; 48 u32int irq; 49 u32int maskedirq; 50 u32int reload; 51 u32int predivider; 52 u32int count; 53 }; 54 55 enum { 56 CntPrescaleShift= 16, /* freq is sys_clk/(prescale+1) */ 57 CntPrescaleMask = 0xFF, 58 CntEnable = 1<<9, 59 TmrDbgHalt = 1<<8, 60 TmrEnable = 1<<7, 61 TmrIntEnable = 1<<5, 62 TmrPrescale1 = 0x00<<2, 63 TmrPrescale16 = 0x01<<2, 64 TmrPrescale256 = 0x02<<2, 65 CntWidth16 = 0<<1, 66 CntWidth32 = 1<<1, 67 }; 68 69 static void 70 clockintr(Ureg *ureg, void *) 71 { 72 Systimers *tn; 73 74 tn = (Systimers*)SYSTIMERS; 75 /* dismiss interrupt */ 76 tn->cs = 1<<3; 77 timerintr(ureg, 0); 78 } 79 80 void 81 clockshutdown(void) 82 { 83 Armtimer *tm; 84 85 tm = (Armtimer*)ARMTIMER; 86 tm->ctl = 0; 87 wdogoff(); 88 } 89 90 void 91 clockinit(void) 92 { 93 Systimers *tn; 94 Armtimer *tm; 95 u32int t0, t1, tstart, tend; 96 97 tn = (Systimers*)SYSTIMERS; 98 tm = (Armtimer*)ARMTIMER; 99 tm->load = 0; 100 tm->ctl = TmrPrescale1|CntEnable|CntWidth32; 101 102 tstart = tn->clo; 103 do{ 104 t0 = lcycles(); 105 }while(tn->clo == tstart); 106 tend = tstart + 10000; 107 do{ 108 t1 = lcycles(); 109 }while(tn->clo != tend); 110 t1 -= t0; 111 m->cpuhz = 100 * t1; 112 m->cpumhz = (m->cpuhz + Mhz/2 - 1) / Mhz; 113 m->cyclefreq = m->cpuhz; 114 115 tn->c3 = tn->clo - 1; 116 intrenable(IRQtimer3, clockintr, nil, 0, "clock"); 117 } 118 119 void 120 timerset(uvlong next) 121 { 122 Systimers *tn; 123 vlong now, period; 124 125 tn = (Systimers*)SYSTIMERS; 126 now = fastticks(nil); 127 period = next - fastticks(nil); 128 if(period < MinPeriod) 129 next = now + MinPeriod; 130 else if(period > MaxPeriod) 131 next = now + MaxPeriod; 132 tn->c3 = (ulong)next; 133 } 134 135 uvlong 136 fastticks(uvlong *hz) 137 { 138 Systimers *tn; 139 ulong lo, hi; 140 141 tn = (Systimers*)SYSTIMERS; 142 if(hz) 143 *hz = SystimerFreq; 144 do{ 145 hi = tn->chi; 146 lo = tn->clo; 147 }while(tn->chi != hi); 148 m->fastclock = (uvlong)hi<<32 | lo; 149 return m->fastclock; 150 } 151 152 ulong 153 perfticks(void) 154 { 155 Armtimer *tm; 156 157 tm = (Armtimer*)ARMTIMER; 158 return tm->count; 159 } 160 161 void 162 armtimerset(int n) 163 { 164 Armtimer *tm; 165 166 tm = (Armtimer*)ARMTIMER; 167 if(n > 0){ 168 tm->ctl |= TmrEnable|TmrIntEnable; 169 tm->load = n; 170 }else{ 171 tm->load = 0; 172 tm->ctl &= ~(TmrEnable|TmrIntEnable); 173 tm->irq = 1; 174 } 175 } 176 177 ulong 178 µs(void) 179 { 180 if(SystimerFreq != 1*Mhz) 181 return fastticks2us(fastticks(nil)); 182 return fastticks(nil); 183 } 184 185 void 186 microdelay(int n) 187 { 188 Systimers *tn; 189 u32int now, diff; 190 191 tn = (Systimers*)SYSTIMERS; 192 diff = n + 1; 193 now = tn->clo; 194 while(tn->clo - now < diff) 195 ; 196 } 197 198 void 199 delay(int n) 200 { 201 while(--n >= 0) 202 microdelay(1000); 203 } 204