clock.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "io.h"
  7. #include "ureg.h"
  8. #include "../port/error.h"
  9. enum {
  10. RTCREGS = 0x90010000, /* real time clock registers */
  11. RTSR_al = 0x01, /* alarm detected */
  12. RTSR_hz = 0x02, /* 1Hz tick */
  13. RTSR_ale= 0x04, /* alarm interrupt enable */
  14. RTSR_hze= 0x08, /* 1Hz tick enable */
  15. Never = 0xffffffff,
  16. };
  17. typedef struct OSTimer
  18. {
  19. ulong osmr[4]; /* match registers */
  20. volatile ulong oscr; /* counter register */
  21. ulong ossr; /* status register */
  22. ulong ower; /* watchdog enable register */
  23. ulong oier; /* timer interrupt enable register */
  24. } OSTimer;
  25. typedef struct RTCregs
  26. {
  27. ulong rtar; /* alarm */
  28. ulong rcnr; /* count */
  29. ulong rttr; /* trim */
  30. ulong dummy; /* hole */
  31. ulong rtsr; /* status */
  32. } RTCregs;
  33. OSTimer *timerregs = (OSTimer*)OSTIMERREGS;
  34. RTCregs *rtcregs = (RTCregs*)RTCREGS;
  35. static int clockinited;
  36. static void clockintr(Ureg*, void*);
  37. static void rtcintr(Ureg*, void*);
  38. static Tval when; /* scheduled time of next interrupt */
  39. long timeradjust;
  40. enum
  41. {
  42. Minfreq = ClockFreq/HZ, /* At least one interrupt per HZ (50 ms) */
  43. Maxfreq = ClockFreq/10000, /* At most one interrupt every 100 µs */
  44. };
  45. ulong
  46. clockpower(int on)
  47. {
  48. static ulong savedtime;
  49. if (on){
  50. timerregs->ossr |= 1<<0;
  51. timerregs->oier = 1<<0;
  52. timerregs->osmr[0] = timerregs->oscr + Minfreq;
  53. if (rtcregs->rttr == 0){
  54. rtcregs->rttr = 0x8000; // nominal frequency.
  55. rtcregs->rcnr = 0;
  56. rtcregs->rtar = 0xffffffff;
  57. rtcregs->rtsr |= RTSR_ale;
  58. rtcregs->rtsr |= RTSR_hze;
  59. }
  60. if (rtcregs->rcnr > savedtime)
  61. return rtcregs->rcnr - savedtime;
  62. } else
  63. savedtime = rtcregs->rcnr;
  64. clockinited = on;
  65. return 0L;
  66. }
  67. void
  68. clockinit(void)
  69. {
  70. ulong x;
  71. ulong id;
  72. /* map the clock registers */
  73. timerregs = mapspecial(OSTIMERREGS, sizeof(OSTimer));
  74. rtcregs = mapspecial(RTCREGS, sizeof(RTCregs));
  75. /* enable interrupts on match register 0, turn off all others */
  76. timerregs->ossr |= 1<<0;
  77. intrenable(IRQ, IRQtimer0, clockintr, nil, "clock");
  78. timerregs->oier = 1<<0;
  79. /* figure out processor frequency */
  80. x = powerregs->ppcr & 0x1f;
  81. conf.hz = ClockFreq*(x*4+16);
  82. conf.mhz = (conf.hz+499999)/1000000;
  83. /* get processor type */
  84. id = getcpuid();
  85. print("%lud MHZ ARM, ver %lux/part %lux/step %lud\n", conf.mhz,
  86. (id>>16)&0xff, (id>>4)&0xfff, id&0xf);
  87. /* post interrupt 1/HZ secs from now */
  88. when = timerregs->oscr + Minfreq;
  89. timerregs->osmr[0] = when;
  90. /* enable RTC interrupts and alarms */
  91. intrenable(IRQ, IRQrtc, rtcintr, nil, "rtc");
  92. rtcregs->rttr = 0x8000; // make rcnr 1Hz
  93. rtcregs->rcnr = 0; // reset counter
  94. rtcregs->rtsr |= RTSR_al;
  95. rtcregs->rtsr |= RTSR_ale;
  96. timersinit();
  97. clockinited = 1;
  98. }
  99. /* turn 32 bit counter into a 64 bit one. since todfix calls
  100. * us at least once a second and we overflow once every 1165
  101. * seconds, we won't miss an overflow.
  102. */
  103. uvlong
  104. fastticks(uvlong *hz)
  105. {
  106. static uvlong high;
  107. static ulong last;
  108. ulong x;
  109. if(hz != nil)
  110. *hz = ClockFreq;
  111. x = timerregs->oscr;
  112. if(x < last)
  113. high += 1LL<<32;
  114. last = x;
  115. return high+x;
  116. }
  117. ulong
  118. µs(void)
  119. {
  120. return fastticks2us(fastticks(nil));
  121. }
  122. void
  123. timerset(Tval v)
  124. {
  125. ulong next, tics; /* Must be unsigned! */
  126. static int count;
  127. next = v;
  128. /* post next interrupt: calculate # of tics from now */
  129. tics = next - timerregs->oscr - Maxfreq;
  130. if (tics > Minfreq){
  131. timeradjust++;
  132. next = timerregs->oscr + Maxfreq;
  133. }
  134. timerregs->osmr[0] = next;
  135. }
  136. static void
  137. clockintr(Ureg *ureg, void*)
  138. {
  139. /* reset previous interrupt */
  140. timerregs->ossr |= 1<<0;
  141. when += Minfreq;
  142. timerregs->osmr[0] = when; /* insurance */
  143. timerintr(ureg, when);
  144. }
  145. void
  146. rtcalarm(ulong secs)
  147. {
  148. vlong t;
  149. if (t == 0){
  150. iprint("RTC alarm cancelled\n");
  151. rtcregs->rtsr &= ~RTSR_ale;
  152. rtcregs->rtar = 0xffffffff;
  153. } else {
  154. t = todget(nil);
  155. t = t / 1000000000ULL; // nsec to secs
  156. if (secs < t)
  157. return;
  158. secs -= t;
  159. iprint("RTC alarm set to %uld seconds from now\n", secs);
  160. rtcregs->rtar = rtcregs->rcnr + secs;
  161. rtcregs->rtsr|= RTSR_ale;
  162. }
  163. }
  164. static void
  165. rtcintr(Ureg*, void*)
  166. {
  167. /* reset interrupt */
  168. rtcregs->rtsr&= ~RTSR_ale;
  169. rtcregs->rtsr&= ~RTSR_al;
  170. rtcregs->rtar = 0;
  171. iprint("RTC alarm: %lud\n", rtcregs->rcnr);
  172. }
  173. void
  174. delay(int ms)
  175. {
  176. ulong start;
  177. int i;
  178. if(clockinited){
  179. while(ms-- > 0){
  180. start = timerregs->oscr;
  181. while(timerregs->oscr-start < ClockFreq/1000)
  182. ;
  183. }
  184. } else {
  185. while(ms-- > 0){
  186. for(i = 0; i < 1000; i++)
  187. ;
  188. }
  189. }
  190. }
  191. void
  192. microdelay(int µs)
  193. {
  194. ulong start;
  195. int i;
  196. µs++;
  197. if(clockinited){
  198. start = timerregs->oscr;
  199. while(timerregs->oscr - start < 1UL+(µs*ClockFreq)/1000000UL)
  200. ;
  201. } else {
  202. while(µs-- > 0){
  203. for(i = 0; i < 10; i++)
  204. ;
  205. }
  206. }
  207. }
  208. /*
  209. * performance measurement ticks. must be low overhead.
  210. * doesn't have to count over a second.
  211. */
  212. ulong
  213. perfticks(void)
  214. {
  215. return timerregs->oscr;
  216. }