/*
* kirkwood clock
*/
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "ureg.h"
enum {
Tcycles = CLOCKFREQ / HZ, /* cycles per clock tick */
MaxPeriod = Tcycles,
MinPeriod = MaxPeriod / 100,
};
static void
clockintr(Ureg *ureg, void*)
{
TIMERREG->timerwd = CLOCKFREQ; /* reassure the watchdog */
coherence();
timerintr(ureg, 0);
intrclear(Irqbridge, IRQcputimer0);
}
void
clockinit(void)
{
int s;
long cyc;
TimerReg *tmr = TIMERREG;
tmr->ctl = 0;
coherence();
intrenable(Irqbridge, IRQcputimer0, clockintr, nil, "clock");
s = spllo(); /* risky */
/* take any deferred clock (& other) interrupts here */
splx(s);
/* adjust m->bootdelay, used by delay()? */
m->ticks = 0;
m->fastclock = 0;
tmr->timer0 = Tcycles;
tmr->ctl = Tmr0enable; /* just once */
coherence();
s = spllo(); /* risky */
/* one iteration seems to take about 40 ns. */
for (cyc = Tcycles; cyc > 0 && m->fastclock == 0; cyc--)
;
splx(s);
if (m->fastclock == 0) {
serialputc('?');
if (tmr->timer0 == 0)
panic("clock not interrupting");
else if (tmr->timer0 == tmr->reload0)
panic("clock not ticking");
else
panic("clock running very slowly");
}
tmr->ctl = 0;
coherence();
tmr->timer0 = Tcycles;
tmr->timer1 = ~0;
tmr->reload1 = ~0;
tmr->timerwd = CLOCKFREQ;
coherence();
tmr->ctl = Tmr0enable | Tmr1enable | Tmr1periodic | TmrWDenable;
CPUCSREG->rstout |= RstoutWatchdog;
coherence();
}
void
timerset(Tval next)
{
TimerReg *tmr = TIMERREG;
int offset;
offset = next - fastticks(nil);
if(offset < MinPeriod)
offset = MinPeriod;
else if(offset > MaxPeriod)
offset = MaxPeriod;
tmr->timer0 = offset;
coherence();
}
uvlong
fastticks(uvlong *hz)
{
uvlong now;
int s;
if(hz)
*hz = CLOCKFREQ;
s = splhi();
now = (m->fastclock&0xFFFFFFFF00000000LL) | ~TIMERREG->timer1;
if(now < m->fastclock)
now += 0x100000000LL;
m->fastclock = now;
splx(s);
return now;
}
ulong
µs(void)
{
return fastticks2us(fastticks(nil));
}
void
microdelay(int l)
{
int i;
l *= m->delayloop;
l /= 1000;
if(l <= 0)
l = 1;
for(i = 0; i < l; i++)
;
}
void
delay(int l)
{
ulong i, j;
j = m->delayloop;
while(l-- > 0)
for(i=0; i < j; i++)
;
}
ulong
perfticks(void)
{
return ~TIMERREG->timer1;
}
|