205 lines
3.5 KiB
C
205 lines
3.5 KiB
C
/*
|
|
* kirkwood clocks
|
|
*
|
|
* timers count down to zero.
|
|
*/
|
|
#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 */
|
|
Dogperiod = 15 * CLOCKFREQ, /* at most 21 s.; must fit in ulong */
|
|
MaxPeriod = Tcycles,
|
|
MinPeriod = MaxPeriod / 100,
|
|
|
|
/* timer ctl bits */
|
|
Tmr0enable = 1<<0,
|
|
Tmr0reload = 1<<1, /* at 0 count, load timer0 from reload0 */
|
|
Tmr1enable = 1<<2,
|
|
Tmr1reload = 1<<3, /* at 0 count, load timer1 from reload1 */
|
|
TmrWDenable = 1<<4,
|
|
TmrWDreload = 1<<5,
|
|
};
|
|
|
|
typedef struct TimerReg TimerReg;
|
|
struct TimerReg
|
|
{
|
|
ulong ctl;
|
|
ulong pad[3];
|
|
ulong reload0;
|
|
ulong timer0; /* cycles until zero */
|
|
ulong reload1;
|
|
ulong timer1; /* cycles until zero */
|
|
ulong reloadwd;
|
|
ulong timerwd;
|
|
};
|
|
|
|
static int ticks; /* for sanity checking; m->ticks doesn't always get updated */
|
|
|
|
static void
|
|
clockintr(Ureg *ureg, void *arg)
|
|
{
|
|
TimerReg *tmr = arg;
|
|
static int nesting;
|
|
|
|
tmr->timerwd = Dogperiod; /* reassure the watchdog */
|
|
ticks++;
|
|
coherence();
|
|
|
|
if (nesting == 0) { /* if the clock interrupted itself, bail out */
|
|
++nesting;
|
|
timerintr(ureg, 0);
|
|
--nesting;
|
|
}
|
|
|
|
intrclear(Irqbridge, IRQcputimer0);
|
|
}
|
|
|
|
/* stop clock interrupts and disable the watchdog timer */
|
|
void
|
|
clockshutdown(void)
|
|
{
|
|
TimerReg *tmr = (TimerReg *)soc.clock;
|
|
|
|
tmr->ctl = 0;
|
|
coherence();
|
|
}
|
|
|
|
void
|
|
clockinit(void)
|
|
{
|
|
int i, s;
|
|
CpucsReg *cpu = (CpucsReg *)soc.cpu;
|
|
TimerReg *tmr = (TimerReg *)soc.clock;
|
|
|
|
clockshutdown();
|
|
|
|
/*
|
|
* verify sanity of timer0
|
|
*/
|
|
|
|
intrenable(Irqbridge, IRQcputimer0, clockintr, tmr, "clock0");
|
|
s = spllo(); /* risky */
|
|
/* take any deferred clock (& other) interrupts here */
|
|
splx(s);
|
|
|
|
/* adjust m->bootdelay, used by delay()? */
|
|
m->ticks = ticks = 0;
|
|
m->fastclock = 0;
|
|
|
|
tmr->timer0 = 1;
|
|
tmr->ctl = Tmr0enable; /* just once */
|
|
coherence();
|
|
|
|
s = spllo(); /* risky */
|
|
for (i = 0; i < 10 && ticks == 0; i++) {
|
|
delay(1);
|
|
coherence();
|
|
}
|
|
splx(s);
|
|
if (ticks == 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");
|
|
}
|
|
|
|
/*
|
|
* configure all timers
|
|
*/
|
|
clockshutdown();
|
|
tmr->reload0 = tmr->timer0 = Tcycles; /* tick clock */
|
|
tmr->reload1 = tmr->timer1 = ~0; /* cycle clock */
|
|
tmr->timerwd = Dogperiod; /* watch dog timer */
|
|
coherence();
|
|
tmr->ctl = Tmr0enable | Tmr0reload | Tmr1enable | Tmr1reload |
|
|
TmrWDenable;
|
|
cpu->rstout |= RstoutWatchdog;
|
|
coherence();
|
|
}
|
|
|
|
void
|
|
timerset(Tval next)
|
|
{
|
|
int offset;
|
|
TimerReg *tmr = (TimerReg *)soc.clock;
|
|
|
|
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();
|
|
/* zero low ulong of fastclock */
|
|
now = (m->fastclock & ~(uvlong)~0ul) | perfticks();
|
|
if(now < m->fastclock) /* low bits must have wrapped */
|
|
now += 1ll << 32;
|
|
m->fastclock = now;
|
|
splx(s);
|
|
return now;
|
|
}
|
|
|
|
ulong
|
|
perfticks(void)
|
|
{
|
|
TimerReg *tmr = (TimerReg *)soc.clock;
|
|
|
|
return ~tmr->timer1;
|
|
}
|
|
|
|
long
|
|
lcycles(void)
|
|
{
|
|
return perfticks();
|
|
}
|
|
|
|
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++)
|
|
;
|
|
}
|