2 #include "../port/lib.h"
8 #include "../port/error.h"
12 RTCREGS = 0x90010000, /* real time clock registers */
13 RTSR_al = 0x01, /* alarm detected */
14 RTSR_hz = 0x02, /* 1Hz tick */
15 RTSR_ale= 0x04, /* alarm interrupt enable */
16 RTSR_hze= 0x08, /* 1Hz tick enable */
21 typedef struct OSTimer
23 ulong osmr[4]; /* match registers */
24 volatile ulong oscr; /* counter register */
25 ulong ossr; /* status register */
26 ulong ower; /* watchdog enable register */
27 ulong oier; /* timer interrupt enable register */
30 typedef struct RTCregs
32 ulong rtar; /* alarm */
33 ulong rcnr; /* count */
34 ulong rttr; /* trim */
35 ulong dummy; /* hole */
36 ulong rtsr; /* status */
39 OSTimer *timerregs = (OSTimer*)OSTIMERREGS;
40 RTCregs *rtcregs = (RTCregs*)RTCREGS;
41 static int clockinited;
43 static void clockintr(Ureg*, void*);
44 static void rtcintr(Ureg*, void*);
45 static Tval when; /* scheduled time of next interrupt */
51 Minfreq = ClockFreq/HZ, /* At least one interrupt per HZ (50 ms) */
52 Maxfreq = ClockFreq/10000, /* At most one interrupt every 100 µs */
58 static ulong savedtime;
61 timerregs->ossr |= 1<<0;
62 timerregs->oier = 1<<0;
63 timerregs->osmr[0] = timerregs->oscr + Minfreq;
64 if (rtcregs->rttr == 0){
65 rtcregs->rttr = 0x8000; // nominal frequency.
67 rtcregs->rtar = 0xffffffff;
68 rtcregs->rtsr |= RTSR_ale;
69 rtcregs->rtsr |= RTSR_hze;
71 if (rtcregs->rcnr > savedtime)
72 return rtcregs->rcnr - savedtime;
74 savedtime = rtcregs->rcnr;
85 /* map the clock registers */
86 timerregs = mapspecial(OSTIMERREGS, sizeof(OSTimer));
87 rtcregs = mapspecial(RTCREGS, sizeof(RTCregs));
89 /* enable interrupts on match register 0, turn off all others */
90 timerregs->ossr |= 1<<0;
91 intrenable(IRQ, IRQtimer0, clockintr, nil, "clock");
92 timerregs->oier = 1<<0;
94 /* figure out processor frequency */
95 x = powerregs->ppcr & 0x1f;
96 conf.hz = ClockFreq*(x*4+16);
97 conf.mhz = (conf.hz+499999)/1000000;
99 /* get processor type */
102 print("%lud MHZ ARM, ver %lux/part %lux/step %lud\n", conf.mhz,
103 (id>>16)&0xff, (id>>4)&0xfff, id&0xf);
105 /* post interrupt 1/HZ secs from now */
106 when = timerregs->oscr + Minfreq;
107 timerregs->osmr[0] = when;
109 /* enable RTC interrupts and alarms */
110 intrenable(IRQ, IRQrtc, rtcintr, nil, "rtc");
111 rtcregs->rttr = 0x8000; // make rcnr 1Hz
112 rtcregs->rcnr = 0; // reset counter
113 rtcregs->rtsr |= RTSR_al;
114 rtcregs->rtsr |= RTSR_ale;
121 /* turn 32 bit counter into a 64 bit one. since todfix calls
122 * us at least once a second and we overflow once every 1165
123 * seconds, we won't miss an overflow.
126 fastticks(uvlong *hz)
144 return fastticks2us(fastticks(nil));
150 ulong next, tics; /* Must be unsigned! */
155 /* post next interrupt: calculate # of tics from now */
156 tics = next - timerregs->oscr - Maxfreq;
159 next = timerregs->oscr + Maxfreq;
161 timerregs->osmr[0] = next;
165 clockintr(Ureg *ureg, void*)
167 /* reset previous interrupt */
168 timerregs->ossr |= 1<<0;
170 timerregs->osmr[0] = when; /* insurance */
172 timerintr(ureg, when);
181 iprint("RTC alarm cancelled\n");
182 rtcregs->rtsr &= ~RTSR_ale;
183 rtcregs->rtar = 0xffffffff;
186 t = t / 1000000000ULL; // nsec to secs
190 iprint("RTC alarm set to %uld seconds from now\n", secs);
191 rtcregs->rtar = rtcregs->rcnr + secs;
192 rtcregs->rtsr|= RTSR_ale;
197 rtcintr(Ureg*, void*)
199 /* reset interrupt */
200 rtcregs->rtsr&= ~RTSR_ale;
201 rtcregs->rtsr&= ~RTSR_al;
204 iprint("RTC alarm: %lud\n", rtcregs->rcnr);
215 start = timerregs->oscr;
216 while(timerregs->oscr-start < ClockFreq/1000)
221 for(i = 0; i < 1000; i++)
235 start = timerregs->oscr;
236 while(timerregs->oscr - start < 1UL+(µs*ClockFreq)/1000000UL)
240 for(i = 0; i < 10; i++)
247 * performance measurement ticks. must be low overhead.
248 * doesn't have to count over a second.
253 return timerregs->oscr;