18e32b400SDavid du Colombier /*
28e32b400SDavid du Colombier * omap3530 clocks
38e32b400SDavid du Colombier *
48e32b400SDavid du Colombier * timers count up to zero.
58e32b400SDavid du Colombier *
68e32b400SDavid du Colombier * the source clock signals for the timers are sometimes selectable. for
78e32b400SDavid du Colombier * WDTIMER[23] and GPTIMER12, it's always the 32kHz clock. for the
88e32b400SDavid du Colombier * others, it can be the 32kHz clock or the system clock. we use only
98e32b400SDavid du Colombier * WDTIMER2 and GPTIMER[12], and configure GPTIMER[12] in archomap.c to
108e32b400SDavid du Colombier * use the 32kHZ clock. WDTIMER1 is not accessible to us on GP
118e32b400SDavid du Colombier * (general-purpose) omaps.
128e32b400SDavid du Colombier */
138e32b400SDavid du Colombier #include "u.h"
148e32b400SDavid du Colombier #include "../port/lib.h"
158e32b400SDavid du Colombier #include "mem.h"
168e32b400SDavid du Colombier #include "dat.h"
178e32b400SDavid du Colombier #include "fns.h"
188e32b400SDavid du Colombier #include "arm.h"
198e32b400SDavid du Colombier
208e32b400SDavid du Colombier enum {
218e32b400SDavid du Colombier Debug = 0,
228e32b400SDavid du Colombier
238e32b400SDavid du Colombier Tn0 = PHYSTIMER1,
248e32b400SDavid du Colombier Tn1 = PHYSTIMER2,
258e32b400SDavid du Colombier
26436938c0SDavid du Colombier /* irq 36 is watchdog timer module 3 overflow */
278e32b400SDavid du Colombier Tn0irq = 37, /* base IRQ for all timers */
288e32b400SDavid du Colombier
298e32b400SDavid du Colombier Freebase = 1, /* base of free-running timer */
308e32b400SDavid du Colombier
318e32b400SDavid du Colombier /*
328e32b400SDavid du Colombier * clock is 32K (32,768) Hz, so one tick is 30.517µs,
33436938c0SDavid du Colombier * so 327.68 ticks is 10ms, 32.768 ticks is 1ms.
348e32b400SDavid du Colombier */
358e32b400SDavid du Colombier Clockfreqbase = 32 * 1024, /* base rate in Hz */
368e32b400SDavid du Colombier Tcycles = Clockfreqbase / HZ, /* cycles per clock tick */
378e32b400SDavid du Colombier
388e32b400SDavid du Colombier MinPeriod = (Tcycles / 100 < 2? 2: Tcycles / 100),
398e32b400SDavid du Colombier MaxPeriod = Tcycles,
408e32b400SDavid du Colombier
41047f1f95SDavid du Colombier Dogtimeout = 20 * Clockfreqbase, /* was 4 s.; must be ≤ 21 s. */
428e32b400SDavid du Colombier };
438e32b400SDavid du Colombier
448e32b400SDavid du Colombier enum {
458e32b400SDavid du Colombier /* ticpcfg bits */
468e32b400SDavid du Colombier Noidle = 1<<3,
478e32b400SDavid du Colombier Softreset = 1<<1,
488e32b400SDavid du Colombier
498e32b400SDavid du Colombier /* tistat bits */
508e32b400SDavid du Colombier Resetdone = 1<<0,
518e32b400SDavid du Colombier
528e32b400SDavid du Colombier /* tisr/tier bits */
538e32b400SDavid du Colombier Ovf_it = 1<<1, /* gp: overflow intr */
548e32b400SDavid du Colombier Mat_it = 1<<0, /* gp: match intr */
558e32b400SDavid du Colombier Wdovf_it = 1<<0, /* wdog: overflow intr */
568e32b400SDavid du Colombier
578e32b400SDavid du Colombier /* tclr bits */
588e32b400SDavid du Colombier Ar = 1<<1, /* gp only: autoreload mode overflow */
598e32b400SDavid du Colombier St = 1<<0, /* gp only: start the timer */
608e32b400SDavid du Colombier };
618e32b400SDavid du Colombier
628e32b400SDavid du Colombier /* omap35x timer registers */
638e32b400SDavid du Colombier typedef struct Timerregs Timerregs;
648e32b400SDavid du Colombier struct Timerregs {
658e32b400SDavid du Colombier /* common to all timers, gp and watchdog */
668e32b400SDavid du Colombier uchar pad0[0x10];
678e32b400SDavid du Colombier ulong ticpcfg;
688e32b400SDavid du Colombier ulong tistat; /* ro: low bit: reset done */
698e32b400SDavid du Colombier ulong tisr;
708e32b400SDavid du Colombier ulong tier;
718e32b400SDavid du Colombier ulong twer;
728e32b400SDavid du Colombier ulong tclr;
738e32b400SDavid du Colombier ulong tcrr; /* counter: cycles to zero */
748e32b400SDavid du Colombier ulong tldr;
758e32b400SDavid du Colombier ulong ttgr; /* trigger */
768e32b400SDavid du Colombier ulong twps; /* ro: write posted pending */
778e32b400SDavid du Colombier
788e32b400SDavid du Colombier /* gp timers only, unused by us */
798e32b400SDavid du Colombier ulong tmar; /* value to compare with counter */
808e32b400SDavid du Colombier ulong tcar1; /* ro */
818e32b400SDavid du Colombier ulong tsicr;
828e32b400SDavid du Colombier ulong tcar2; /* ro */
838e32b400SDavid du Colombier union {
848e32b400SDavid du Colombier ulong tpir; /* gp: 1 ms tick generation: +ve */
858e32b400SDavid du Colombier ulong wspr; /* wdog: start/stop control */
868e32b400SDavid du Colombier };
878e32b400SDavid du Colombier ulong tnir; /* 1 ms tick generation: -ve */
888e32b400SDavid du Colombier ulong tcvr; /* 1 ms tick generation: next counter value */
898e32b400SDavid du Colombier ulong tocr; /* intr mask for n ticks */
908e32b400SDavid du Colombier ulong towr;
918e32b400SDavid du Colombier };
928e32b400SDavid du Colombier
938e32b400SDavid du Colombier static int ticks; /* for sanity checking; m->ticks doesn't always get called */
948e32b400SDavid du Colombier static Lock clklck;
958e32b400SDavid du Colombier
968e32b400SDavid du Colombier static ulong rdcycles(void), rdbaseticks(void);
978e32b400SDavid du Colombier
988e32b400SDavid du Colombier /* write a watchdog timer's start/stop register */
998e32b400SDavid du Colombier static void
wdogwrss(Timerregs * tn,ulong val)1008e32b400SDavid du Colombier wdogwrss(Timerregs *tn, ulong val)
1018e32b400SDavid du Colombier {
1028e32b400SDavid du Colombier while (tn->twps & (1 << 4)) /* pending write to start/stop reg? */
1038e32b400SDavid du Colombier ;
1048e32b400SDavid du Colombier tn->wspr = val;
1058e32b400SDavid du Colombier coherence();
1068e32b400SDavid du Colombier while (tn->twps & (1 << 4)) /* pending write to start/stop reg? */
1078e32b400SDavid du Colombier ;
1088e32b400SDavid du Colombier }
1098e32b400SDavid du Colombier
1108e32b400SDavid du Colombier static void
resetwait(Timerregs * tn)1118e32b400SDavid du Colombier resetwait(Timerregs *tn)
1128e32b400SDavid du Colombier {
1138e32b400SDavid du Colombier long bound;
1148e32b400SDavid du Colombier
115*df2dbabfSDavid du Colombier for (bound = 400*Mhz; !(tn->tistat & Resetdone) && bound > 0; bound--)
1168e32b400SDavid du Colombier ;
1178e32b400SDavid du Colombier if (bound <= 0)
1188e32b400SDavid du Colombier iprint("clock reset didn't complete\n");
1198e32b400SDavid du Colombier }
1208e32b400SDavid du Colombier
1218e32b400SDavid du Colombier
1228e32b400SDavid du Colombier static void
wdogoff(Timerregs * tn)1238e32b400SDavid du Colombier wdogoff(Timerregs *tn)
1248e32b400SDavid du Colombier {
1258e32b400SDavid du Colombier resetwait(tn);
1268e32b400SDavid du Colombier
1278e32b400SDavid du Colombier wdogwrss(tn, 0xaaaa); /* magic off sequence */
1288e32b400SDavid du Colombier wdogwrss(tn, 0x5555);
1298e32b400SDavid du Colombier
1308e32b400SDavid du Colombier tn->tldr = 1;
1318e32b400SDavid du Colombier coherence();
1328e32b400SDavid du Colombier tn->tcrr = 1; /* paranoia */
1338e32b400SDavid du Colombier coherence();
1348e32b400SDavid du Colombier }
1358e32b400SDavid du Colombier
1368e32b400SDavid du Colombier static void wdogassure(void);
1378e32b400SDavid du Colombier
1388e32b400SDavid du Colombier static void
wdogon(Timerregs * tn)1398e32b400SDavid du Colombier wdogon(Timerregs *tn)
1408e32b400SDavid du Colombier {
1418e32b400SDavid du Colombier static int beenhere;
1428e32b400SDavid du Colombier
1438e32b400SDavid du Colombier resetwait(tn);
1448e32b400SDavid du Colombier tn->tldr = -Dogtimeout;
1458e32b400SDavid du Colombier tn->tcrr = -Dogtimeout;
1468e32b400SDavid du Colombier coherence();
1478e32b400SDavid du Colombier wdogwrss(tn, 0xbbbb); /* magic on sequence */
1488e32b400SDavid du Colombier wdogwrss(tn, 0x4444); /* magic on sequence */
1498e32b400SDavid du Colombier
1508e32b400SDavid du Colombier if (!beenhere) {
1518e32b400SDavid du Colombier beenhere = 1;
1528e32b400SDavid du Colombier /* touching the dog is not quick, so do it infrequently */
1538e32b400SDavid du Colombier addclock0link(wdogassure, HZ);
1548e32b400SDavid du Colombier }
1558e32b400SDavid du Colombier }
1568e32b400SDavid du Colombier
1578e32b400SDavid du Colombier static void
wdogassure(void)1588e32b400SDavid du Colombier wdogassure(void) /* reset the watch dog's counter */
1598e32b400SDavid du Colombier {
1608e32b400SDavid du Colombier Timerregs *tn;
1618e32b400SDavid du Colombier
1628e32b400SDavid du Colombier tn = (Timerregs *)PHYSWDOG;
1638e32b400SDavid du Colombier wdogoff(tn);
1648e32b400SDavid du Colombier
1658e32b400SDavid du Colombier tn->tcrr = -Dogtimeout;
1668e32b400SDavid du Colombier coherence();
1678e32b400SDavid du Colombier
1688e32b400SDavid du Colombier wdogon(tn);
1698e32b400SDavid du Colombier }
1708e32b400SDavid du Colombier
1718e32b400SDavid du Colombier static void
clockintr(Ureg * ureg,void * arg)1728e32b400SDavid du Colombier clockintr(Ureg* ureg, void *arg)
1738e32b400SDavid du Colombier {
1748e32b400SDavid du Colombier Timerregs *tn;
1758e32b400SDavid du Colombier static int nesting;
1768e32b400SDavid du Colombier
1778e32b400SDavid du Colombier ticks++;
1788e32b400SDavid du Colombier coherence();
1798e32b400SDavid du Colombier
1808e32b400SDavid du Colombier if (nesting == 0) { /* if the clock interrupted itself, bail out */
1818e32b400SDavid du Colombier ++nesting;
1828e32b400SDavid du Colombier timerintr(ureg, 0);
1838e32b400SDavid du Colombier --nesting;
1848e32b400SDavid du Colombier }
1858e32b400SDavid du Colombier
1868e32b400SDavid du Colombier tn = arg;
1878e32b400SDavid du Colombier tn->tisr = Ovf_it; /* dismiss the interrupt */
1888e32b400SDavid du Colombier coherence();
1898e32b400SDavid du Colombier }
1908e32b400SDavid du Colombier
1918e32b400SDavid du Colombier static void
clockreset(Timerregs * tn)1928e32b400SDavid du Colombier clockreset(Timerregs *tn)
1938e32b400SDavid du Colombier {
1948e32b400SDavid du Colombier if (probeaddr((uintptr)&tn->ticpcfg) < 0)
1958e32b400SDavid du Colombier panic("no clock at %#p", tn);
1968e32b400SDavid du Colombier tn->ticpcfg = Softreset | Noidle;
1978e32b400SDavid du Colombier coherence();
1988e32b400SDavid du Colombier resetwait(tn);
1998e32b400SDavid du Colombier tn->tier = tn->tclr = 0;
2008e32b400SDavid du Colombier coherence();
2018e32b400SDavid du Colombier }
2028e32b400SDavid du Colombier
2038e32b400SDavid du Colombier /* stop clock interrupts and disable the watchdog timer */
2048e32b400SDavid du Colombier void
clockshutdown(void)2058e32b400SDavid du Colombier clockshutdown(void)
2068e32b400SDavid du Colombier {
2078e32b400SDavid du Colombier clockreset((Timerregs *)PHYSWDT2);
2088e32b400SDavid du Colombier wdogoff((Timerregs *)PHYSWDT2);
2098e32b400SDavid du Colombier clockreset((Timerregs *)PHYSWDT3);
2108e32b400SDavid du Colombier wdogoff((Timerregs *)PHYSWDT3);
2118e32b400SDavid du Colombier
2128e32b400SDavid du Colombier clockreset((Timerregs *)Tn0);
2138e32b400SDavid du Colombier clockreset((Timerregs *)Tn1);
2148e32b400SDavid du Colombier }
2158e32b400SDavid du Colombier
2168e32b400SDavid du Colombier enum {
217*df2dbabfSDavid du Colombier Instrs = 10*Mhz,
2188e32b400SDavid du Colombier };
2198e32b400SDavid du Colombier
2208e32b400SDavid du Colombier static long
issue1loop(void)2218e32b400SDavid du Colombier issue1loop(void)
2228e32b400SDavid du Colombier {
2238e32b400SDavid du Colombier register int i;
2248e32b400SDavid du Colombier long st;
2258e32b400SDavid du Colombier
2268e32b400SDavid du Colombier st = rdbaseticks();
2278e32b400SDavid du Colombier i = Instrs;
2288e32b400SDavid du Colombier do {
2298e32b400SDavid du Colombier --i; --i; --i; --i; --i;
2308e32b400SDavid du Colombier --i; --i; --i; --i;
2318e32b400SDavid du Colombier } while(--i >= 0);
2328e32b400SDavid du Colombier return rdbaseticks() - st;
2338e32b400SDavid du Colombier }
2348e32b400SDavid du Colombier
2358e32b400SDavid du Colombier static long
issue2loop(void)2368e32b400SDavid du Colombier issue2loop(void)
2378e32b400SDavid du Colombier {
2388e32b400SDavid du Colombier register int i, j;
2398e32b400SDavid du Colombier long st;
2408e32b400SDavid du Colombier
2418e32b400SDavid du Colombier st = rdbaseticks();
2428e32b400SDavid du Colombier i = Instrs / 2;
2438e32b400SDavid du Colombier j = 0;
2448e32b400SDavid du Colombier do {
2458e32b400SDavid du Colombier --i; --j; --i; --j;
2468e32b400SDavid du Colombier --i; --j; --i; --j;
2478e32b400SDavid du Colombier --j;
2488e32b400SDavid du Colombier } while(--i >= 0);
2498e32b400SDavid du Colombier return rdbaseticks() - st;
2508e32b400SDavid du Colombier }
2518e32b400SDavid du Colombier
2528e32b400SDavid du Colombier /* estimate instructions/s. using 32kHz clock */
2538e32b400SDavid du Colombier static void
guessmips(long (* loop)(void),char * lab)2548e32b400SDavid du Colombier guessmips(long (*loop)(void), char *lab)
2558e32b400SDavid du Colombier {
2568e32b400SDavid du Colombier int s;
2578e32b400SDavid du Colombier long tcks;
2588e32b400SDavid du Colombier
2598e32b400SDavid du Colombier do {
2608e32b400SDavid du Colombier s = splhi();
2618e32b400SDavid du Colombier tcks = loop();
2628e32b400SDavid du Colombier splx(s);
2638e32b400SDavid du Colombier if (tcks < 0)
2648e32b400SDavid du Colombier iprint("again...");
2658e32b400SDavid du Colombier } while (tcks < 0);
2668e32b400SDavid du Colombier /*
2678e32b400SDavid du Colombier * Instrs instructions took tcks ticks @ Clockfreqbase Hz.
2688e32b400SDavid du Colombier */
2698e32b400SDavid du Colombier s = ((vlong)Clockfreqbase * Instrs) / tcks / 1000000;
2708e32b400SDavid du Colombier if (Debug)
2718e32b400SDavid du Colombier iprint("%ud mips (%s-issue)", s, lab);
2728e32b400SDavid du Colombier USED(s);
2738e32b400SDavid du Colombier }
2748e32b400SDavid du Colombier
2758e32b400SDavid du Colombier void
clockinit(void)2768e32b400SDavid du Colombier clockinit(void)
2778e32b400SDavid du Colombier {
2788e32b400SDavid du Colombier int i, s;
2798e32b400SDavid du Colombier Timerregs *tn;
2808e32b400SDavid du Colombier
2818e32b400SDavid du Colombier clockshutdown();
2828e32b400SDavid du Colombier
2838e32b400SDavid du Colombier /* turn cycle counter on */
2848e32b400SDavid du Colombier cpwrsc(0, CpCLD, CpCLDena, CpCLDenacyc, 1<<31);
2858e32b400SDavid du Colombier
2868e32b400SDavid du Colombier /* turn all counters on and clear the cycle counter */
2878e32b400SDavid du Colombier cpwrsc(0, CpCLD, CpCLDena, CpCLDenapmnc, 1<<2 | 1);
2888e32b400SDavid du Colombier
2898e32b400SDavid du Colombier /* let users read the cycle counter directly */
2908e32b400SDavid du Colombier cpwrsc(0, CpCLD, CpCLDena, CpCLDenapmnc, 1);
2918e32b400SDavid du Colombier
2928e32b400SDavid du Colombier ilock(&clklck);
2938e32b400SDavid du Colombier m->fastclock = 1;
2948e32b400SDavid du Colombier m->ticks = ticks = 0;
2958e32b400SDavid du Colombier
2968e32b400SDavid du Colombier /*
2978e32b400SDavid du Colombier * T0 is a freerunning timer (cycle counter); it wraps,
2988e32b400SDavid du Colombier * automatically reloads, and does not dispatch interrupts.
2998e32b400SDavid du Colombier */
3008e32b400SDavid du Colombier tn = (Timerregs *)Tn0;
3018e32b400SDavid du Colombier tn->tcrr = Freebase; /* count up to 0 */
3028e32b400SDavid du Colombier tn->tldr = Freebase;
3038e32b400SDavid du Colombier coherence();
3048e32b400SDavid du Colombier tn->tclr = Ar | St;
3058e32b400SDavid du Colombier iunlock(&clklck);
3068e32b400SDavid du Colombier
3078e32b400SDavid du Colombier /*
3088e32b400SDavid du Colombier * T1 is the interrupting timer and does not participate
3098e32b400SDavid du Colombier * in measuring time. It is initially set to HZ.
3108e32b400SDavid du Colombier */
3118e32b400SDavid du Colombier tn = (Timerregs *)Tn1;
3128e32b400SDavid du Colombier irqenable(Tn0irq+1, clockintr, tn, "clock");
3138e32b400SDavid du Colombier ilock(&clklck);
3148e32b400SDavid du Colombier tn->tcrr = -Tcycles; /* approx.; count up to 0 */
3158e32b400SDavid du Colombier tn->tldr = -Tcycles;
3168e32b400SDavid du Colombier coherence();
3178e32b400SDavid du Colombier tn->tclr = Ar | St;
3188e32b400SDavid du Colombier coherence();
3198e32b400SDavid du Colombier tn->tier = Ovf_it;
3208e32b400SDavid du Colombier coherence();
3218e32b400SDavid du Colombier iunlock(&clklck);
3228e32b400SDavid du Colombier
3238e32b400SDavid du Colombier /*
3248e32b400SDavid du Colombier * verify sanity of timer1
3258e32b400SDavid du Colombier */
3268e32b400SDavid du Colombier s = spllo(); /* risky */
3278e32b400SDavid du Colombier for (i = 0; i < 5 && ticks == 0; i++) {
3288e32b400SDavid du Colombier delay(10);
3298e32b400SDavid du Colombier cachedwbinvse(&ticks, sizeof ticks);
3308e32b400SDavid du Colombier }
3318e32b400SDavid du Colombier splx(s);
3328e32b400SDavid du Colombier if (ticks == 0) {
3338e32b400SDavid du Colombier if (tn->tcrr == 0)
3348e32b400SDavid du Colombier panic("clock not interrupting");
3358e32b400SDavid du Colombier else if (tn->tcrr == tn->tldr)
3368e32b400SDavid du Colombier panic("clock not ticking at all");
3378e32b400SDavid du Colombier #ifdef PARANOID
3388e32b400SDavid du Colombier else
3398e32b400SDavid du Colombier panic("clock running very slowly");
3408e32b400SDavid du Colombier #endif
3418e32b400SDavid du Colombier }
3428e32b400SDavid du Colombier
3438e32b400SDavid du Colombier guessmips(issue1loop, "single");
3448e32b400SDavid du Colombier if (Debug)
3458e32b400SDavid du Colombier iprint(", ");
3468e32b400SDavid du Colombier guessmips(issue2loop, "dual");
3478e32b400SDavid du Colombier if (Debug)
3488e32b400SDavid du Colombier iprint("\n");
3498e32b400SDavid du Colombier
3508e32b400SDavid du Colombier /*
3518e32b400SDavid du Colombier * m->delayloop should be the number of delay loop iterations
3528e32b400SDavid du Colombier * needed to consume 1 ms. 2 is min. instructions in the delay loop.
3538e32b400SDavid du Colombier */
3548e32b400SDavid du Colombier m->delayloop = m->cpuhz / (1000 * 2);
3558e32b400SDavid du Colombier // iprint("m->delayloop = %lud\n", m->delayloop);
3568e32b400SDavid du Colombier
3578e32b400SDavid du Colombier /*
3588e32b400SDavid du Colombier * desynchronize the processor clocks so that they all don't
3598e32b400SDavid du Colombier * try to resched at the same time.
3608e32b400SDavid du Colombier */
3618e32b400SDavid du Colombier delay(m->machno*2);
3628e32b400SDavid du Colombier }
3638e32b400SDavid du Colombier
3648e32b400SDavid du Colombier void
watchdoginit(void)3658e32b400SDavid du Colombier watchdoginit(void)
3668e32b400SDavid du Colombier {
3678e32b400SDavid du Colombier wdogassure();
3688e32b400SDavid du Colombier }
3698e32b400SDavid du Colombier
3708e32b400SDavid du Colombier ulong
s(void)3718e32b400SDavid du Colombier µs(void)
3728e32b400SDavid du Colombier {
3738e32b400SDavid du Colombier return fastticks2us(fastticks(nil));
3748e32b400SDavid du Colombier }
3758e32b400SDavid du Colombier
3768e32b400SDavid du Colombier void
timerset(Tval next)3778e32b400SDavid du Colombier timerset(Tval next)
3788e32b400SDavid du Colombier {
3798e32b400SDavid du Colombier long offset;
3808e32b400SDavid du Colombier Timerregs *tn = (Timerregs *)Tn1;
3818e32b400SDavid du Colombier static Lock setlck;
3828e32b400SDavid du Colombier
3838e32b400SDavid du Colombier ilock(&setlck);
3848e32b400SDavid du Colombier offset = next - fastticks(nil);
3858e32b400SDavid du Colombier if(offset < MinPeriod)
3868e32b400SDavid du Colombier offset = MinPeriod;
3878e32b400SDavid du Colombier else if(offset > MaxPeriod)
3888e32b400SDavid du Colombier offset = MaxPeriod;
3898e32b400SDavid du Colombier tn->tcrr = -offset;
3908e32b400SDavid du Colombier coherence();
3918e32b400SDavid du Colombier iunlock(&setlck);
3928e32b400SDavid du Colombier }
3938e32b400SDavid du Colombier
3948e32b400SDavid du Colombier static ulong
rdcycles(void)3958e32b400SDavid du Colombier rdcycles(void)
3968e32b400SDavid du Colombier {
3978e32b400SDavid du Colombier ulong v;
3988e32b400SDavid du Colombier
3998e32b400SDavid du Colombier /* reads 32-bit cycle counter (counting up) */
4008e32b400SDavid du Colombier v = cprdsc(0, CpCLD, CpCLDcyc, 0);
4018e32b400SDavid du Colombier /* keep it positive; prevent m->fastclock ever going to 0 */
4028e32b400SDavid du Colombier return v == 0? 1: v;
4038e32b400SDavid du Colombier }
4048e32b400SDavid du Colombier
4058e32b400SDavid du Colombier static ulong
rdbaseticks(void)4068e32b400SDavid du Colombier rdbaseticks(void)
4078e32b400SDavid du Colombier {
4088e32b400SDavid du Colombier ulong v;
4098e32b400SDavid du Colombier
4108e32b400SDavid du Colombier v = ((Timerregs *)Tn0)->tcrr; /* tcrr should be counting up */
4118e32b400SDavid du Colombier /* keep it positive; prevent m->fastclock ever going to 0 */
4128e32b400SDavid du Colombier return v == 0? 1: v;
4138e32b400SDavid du Colombier }
4148e32b400SDavid du Colombier
4158e32b400SDavid du Colombier ulong
perfticks(void)4168e32b400SDavid du Colombier perfticks(void)
4178e32b400SDavid du Colombier {
4188e32b400SDavid du Colombier return rdcycles();
4198e32b400SDavid du Colombier }
4208e32b400SDavid du Colombier
4218e32b400SDavid du Colombier long
lcycles(void)4228e32b400SDavid du Colombier lcycles(void)
4238e32b400SDavid du Colombier {
4248e32b400SDavid du Colombier return perfticks();
4258e32b400SDavid du Colombier }
4268e32b400SDavid du Colombier
4278e32b400SDavid du Colombier /*
4288e32b400SDavid du Colombier * until 5[cal] inline vlong ops, avoid them where possible,
4298e32b400SDavid du Colombier * they are currently slow function calls.
4308e32b400SDavid du Colombier */
4318e32b400SDavid du Colombier typedef union Counter Counter;
4328e32b400SDavid du Colombier union Counter {
4338e32b400SDavid du Colombier uvlong uvl;
4348e32b400SDavid du Colombier struct { /* little-endian */
4358e32b400SDavid du Colombier ulong low;
4368e32b400SDavid du Colombier ulong high;
4378e32b400SDavid du Colombier };
4388e32b400SDavid du Colombier };
4398e32b400SDavid du Colombier
4408e32b400SDavid du Colombier enum {
4418e32b400SDavid du Colombier Fastvlongops = 0,
4428e32b400SDavid du Colombier };
4438e32b400SDavid du Colombier
4448e32b400SDavid du Colombier uvlong
fastticks(uvlong * hz)4458e32b400SDavid du Colombier fastticks(uvlong *hz)
4468e32b400SDavid du Colombier {
4478e32b400SDavid du Colombier Counter now, sclnow;
4488e32b400SDavid du Colombier
4498e32b400SDavid du Colombier if(hz)
4508e32b400SDavid du Colombier *hz = m->cpuhz;
4518e32b400SDavid du Colombier ilock(&clklck);
4528e32b400SDavid du Colombier if (m->ticks > HZ/10 && m->fastclock == 0)
4538e32b400SDavid du Colombier panic("fastticks: zero m->fastclock; ticks %lud fastclock %#llux",
4548e32b400SDavid du Colombier m->ticks, m->fastclock);
4558e32b400SDavid du Colombier
4568e32b400SDavid du Colombier now.uvl = m->fastclock;
4578e32b400SDavid du Colombier now.low = rdcycles();
4588e32b400SDavid du Colombier if(now.uvl < m->fastclock) /* low bits must have wrapped */
4598e32b400SDavid du Colombier now.high++;
4608e32b400SDavid du Colombier m->fastclock = now.uvl;
4618e32b400SDavid du Colombier coherence();
4628e32b400SDavid du Colombier
4638e32b400SDavid du Colombier sclnow.uvl = now.uvl;
4648e32b400SDavid du Colombier iunlock(&clklck);
4658e32b400SDavid du Colombier return sclnow.uvl;
4668e32b400SDavid du Colombier }
4678e32b400SDavid du Colombier
4688e32b400SDavid du Colombier void
microdelay(int l)4698e32b400SDavid du Colombier microdelay(int l)
4708e32b400SDavid du Colombier {
4718e32b400SDavid du Colombier int i;
4728e32b400SDavid du Colombier
4738e32b400SDavid du Colombier l = l * (vlong)m->delayloop / 1000;
4748e32b400SDavid du Colombier if(l <= 0)
4758e32b400SDavid du Colombier l = 1;
4768e32b400SDavid du Colombier for(i = 0; i < l; i++)
4778e32b400SDavid du Colombier ;
4788e32b400SDavid du Colombier }
4798e32b400SDavid du Colombier
4808e32b400SDavid du Colombier void
delay(int l)4818e32b400SDavid du Colombier delay(int l)
4828e32b400SDavid du Colombier {
4838e32b400SDavid du Colombier ulong i, j;
4848e32b400SDavid du Colombier
4858e32b400SDavid du Colombier j = m->delayloop;
4868e32b400SDavid du Colombier while(l-- > 0)
4878e32b400SDavid du Colombier for(i=0; i < j; i++)
4888e32b400SDavid du Colombier ;
4898e32b400SDavid du Colombier }
490