123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- /*
- * bcm2835 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
- * Use ARM timer (32 bits) for perfticks
- * Use ARM timer to force immediate interrupt
- * Use cycle counter for cycles()
- */
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "io.h"
- enum {
- SYSTIMERS = VIRTIO+0x3000,
- ARMTIMER = VIRTIO+0xB400,
- SystimerFreq = 1*Mhz,
- MaxPeriod = SystimerFreq / HZ,
- MinPeriod = SystimerFreq / (100*HZ),
- };
- typedef struct Systimers Systimers;
- typedef struct Armtimer Armtimer;
- struct Systimers {
- u32int cs;
- u32int clo;
- u32int chi;
- u32int c0;
- u32int c1;
- u32int c2;
- u32int c3;
- };
- struct Armtimer {
- u32int load;
- u32int val;
- u32int ctl;
- u32int irqack;
- u32int irq;
- u32int maskedirq;
- u32int reload;
- u32int predivider;
- u32int count;
- };
- enum {
- CntPrescaleShift= 16, /* freq is sys_clk/(prescale+1) */
- CntPrescaleMask = 0xFF,
- CntEnable = 1<<9,
- TmrDbgHalt = 1<<8,
- TmrEnable = 1<<7,
- TmrIntEnable = 1<<5,
- TmrPrescale1 = 0x00<<2,
- TmrPrescale16 = 0x01<<2,
- TmrPrescale256 = 0x02<<2,
- CntWidth16 = 0<<1,
- CntWidth32 = 1<<1,
- };
- static void
- clockintr(Ureg *ureg, void *)
- {
- Systimers *tn;
- tn = (Systimers*)SYSTIMERS;
- /* dismiss interrupt */
- tn->cs = 1<<3;
- timerintr(ureg, 0);
- }
- void
- clockshutdown(void)
- {
- Armtimer *tm;
- tm = (Armtimer*)ARMTIMER;
- tm->ctl = 0;
- wdogoff();
- }
- void
- clockinit(void)
- {
- Systimers *tn;
- Armtimer *tm;
- u32int t0, t1, tstart, tend;
- tn = (Systimers*)SYSTIMERS;
- tm = (Armtimer*)ARMTIMER;
- tm->load = 0;
- tm->ctl = TmrPrescale1|CntEnable|CntWidth32;
- tstart = tn->clo;
- do{
- t0 = lcycles();
- }while(tn->clo == tstart);
- tend = tstart + 10000;
- do{
- t1 = lcycles();
- }while(tn->clo != tend);
- t1 -= t0;
- m->cpuhz = 100 * t1;
- m->cpumhz = (m->cpuhz + Mhz/2 - 1) / Mhz;
- m->cyclefreq = m->cpuhz;
- tn->c3 = tn->clo - 1;
- intrenable(IRQtimer3, clockintr, nil, 0, "clock");
- }
- void
- timerset(uvlong next)
- {
- Systimers *tn;
- vlong now, period;
- tn = (Systimers*)SYSTIMERS;
- now = fastticks(nil);
- period = next - fastticks(nil);
- if(period < MinPeriod)
- next = now + MinPeriod;
- else if(period > MaxPeriod)
- next = now + MaxPeriod;
- tn->c3 = (ulong)next;
- }
- uvlong
- fastticks(uvlong *hz)
- {
- Systimers *tn;
- ulong lo, hi;
- tn = (Systimers*)SYSTIMERS;
- if(hz)
- *hz = SystimerFreq;
- do{
- hi = tn->chi;
- lo = tn->clo;
- }while(tn->chi != hi);
- m->fastclock = (uvlong)hi<<32 | lo;
- return m->fastclock;
- }
- ulong
- perfticks(void)
- {
- Armtimer *tm;
- tm = (Armtimer*)ARMTIMER;
- return tm->count;
- }
- void
- armtimerset(int n)
- {
- Armtimer *tm;
- tm = (Armtimer*)ARMTIMER;
- if(n > 0){
- tm->ctl |= TmrEnable|TmrIntEnable;
- tm->load = n;
- }else{
- tm->load = 0;
- tm->ctl &= ~(TmrEnable|TmrIntEnable);
- tm->irq = 1;
- }
- }
- ulong
- µs(void)
- {
- if(SystimerFreq != 1*Mhz)
- return fastticks2us(fastticks(nil));
- return fastticks(nil);
- }
- void
- microdelay(int n)
- {
- Systimers *tn;
- u32int now, diff;
- tn = (Systimers*)SYSTIMERS;
- diff = n + 1;
- now = tn->clo;
- while(tn->clo - now < diff)
- ;
- }
- void
- delay(int n)
- {
- while(--n >= 0)
- microdelay(1000);
- }
|