/*
* omap3530 clocks
*
* timers count up to zero.
*
* the source clock signals for the timers are sometimes selectable. for
* WDTIMER[23] and GPTIMER12, it's always the 32kHz clock. for the
* others, it can be the 32kHz clock or the system clock. we use only
* WDTIMER2 and GPTIMER[12], and configure GPTIMER[12] in archomap.c to
* use the 32kHZ clock. WDTIMER1 is not accessible to us on GP
* (general-purpose) omaps.
*/
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "arm.h"
enum {
Debug = 0,
Tn0 = PHYSTIMER1,
Tn1 = PHYSTIMER2,
/* irq 36 is watchdog timer module 3 overflow */
Tn0irq = 37, /* base IRQ for all timers */
Freebase = 1, /* base of free-running timer */
/*
* clock is 32K (32,768) Hz, so one tick is 30.517µs,
* so 327.68 ticks is 10ms, 32.768 ticks is 1ms.
*/
Clockfreqbase = 32 * 1024, /* base rate in Hz */
Tcycles = Clockfreqbase / HZ, /* cycles per clock tick */
/*
* T0 is a freerunning timer (cycle counter); it wraps,
* automatically reloads, and does not dispatch interrupts.
*/
tn = (Timerregs *)Tn0;
tn->tcrr = Freebase; /* count up to 0 */
tn->tldr = Freebase;
coherence();
tn->tclr = Ar | St;
iunlock(&clklck);
/*
* T1 is the interrupting timer and does not participate
* in measuring time. It is initially set to HZ.
*/
tn = (Timerregs *)Tn1;
irqenable(Tn0irq+1, clockintr, tn, "clock");
ilock(&clklck);
tn->tcrr = -Tcycles; /* approx.; count up to 0 */
tn->tldr = -Tcycles;
coherence();
tn->tclr = Ar | St;
coherence();
tn->tier = Ovf_it;
coherence();
iunlock(&clklck);
/*
* verify sanity of timer1
*/
s = spllo(); /* risky */
for (i = 0; i < 5 && ticks == 0; i++) {
delay(10);
cachedwbinvse(&ticks, sizeof ticks);
}
splx(s);
if (ticks == 0) {
if (tn->tcrr == 0)
panic("clock not interrupting");
else if (tn->tcrr == tn->tldr)
panic("clock not ticking at all");
#ifdef PARANOID
else
panic("clock running very slowly");
#endif
}
guessmips(issue1loop, "single");
if (Debug)
iprint(", ");
guessmips(issue2loop, "dual");
if (Debug)
iprint("\n");
/*
* m->delayloop should be the number of delay loop iterations
* needed to consume 1 ms. 2 is min. instructions in the delay loop.
*/
m->delayloop = m->cpuhz / (1000 * 2);
// iprint("m->delayloop = %lud\n", m->delayloop);
/*
* desynchronize the processor clocks so that they all don't
* try to resched at the same time.
*/
delay(m->machno*2);
}
/* reads 32-bit cycle counter (counting up) */
v = cprdsc(0, CpCLD, CpCLDcyc, 0);
/* keep it positive; prevent m->fastclock ever going to 0 */
return v == 0? 1: v;
}
static ulong
rdbaseticks(void)
{
ulong v;
v = ((Timerregs *)Tn0)->tcrr; /* tcrr should be counting up */
/* keep it positive; prevent m->fastclock ever going to 0 */
return v == 0? 1: v;
}
ulong
perfticks(void)
{
return rdcycles();
}
long
lcycles(void)
{
return perfticks();
}
/*
* until 5[cal] inline vlong ops, avoid them where possible,
* they are currently slow function calls.
*/
typedef union Counter Counter;
union Counter {
uvlong uvl;
struct { /* little-endian */
ulong low;
ulong high;
};
};