clock.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  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 uvlong 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. void
  118. timerset(uvlong v)
  119. {
  120. ulong next, tics; /* Must be unsigned! */
  121. static int count;
  122. next = v;
  123. /* post next interrupt: calculate # of tics from now */
  124. tics = next - timerregs->oscr - Maxfreq;
  125. if (tics > Minfreq){
  126. timeradjust++;
  127. next = timerregs->oscr + Maxfreq;
  128. }
  129. timerregs->osmr[0] = next;
  130. }
  131. static void
  132. clockintr(Ureg *ureg, void*)
  133. {
  134. /* reset previous interrupt */
  135. timerregs->ossr |= 1<<0;
  136. when += Minfreq;
  137. timerregs->osmr[0] = when; /* insurance */
  138. timerintr(ureg, when);
  139. }
  140. void
  141. rtcalarm(ulong secs)
  142. {
  143. vlong t;
  144. if (t == 0){
  145. iprint("RTC alarm cancelled\n");
  146. rtcregs->rtsr &= ~RTSR_ale;
  147. rtcregs->rtar = 0xffffffff;
  148. } else {
  149. t = todget(nil);
  150. t = t / 1000000000ULL; // nsec to secs
  151. if (secs < t)
  152. return;
  153. secs -= t;
  154. iprint("RTC alarm set to %uld seconds from now\n", secs);
  155. rtcregs->rtar = rtcregs->rcnr + secs;
  156. rtcregs->rtsr|= RTSR_ale;
  157. }
  158. }
  159. static void
  160. rtcintr(Ureg*, void*)
  161. {
  162. /* reset interrupt */
  163. rtcregs->rtsr&= ~RTSR_ale;
  164. rtcregs->rtsr&= ~RTSR_al;
  165. rtcregs->rtar = 0;
  166. iprint("RTC alarm: %lud\n", rtcregs->rcnr);
  167. }
  168. void
  169. delay(int ms)
  170. {
  171. ulong start;
  172. int i;
  173. if(clockinited){
  174. while(ms-- > 0){
  175. start = timerregs->oscr;
  176. while(timerregs->oscr-start < ClockFreq/1000)
  177. ;
  178. }
  179. } else {
  180. while(ms-- > 0){
  181. for(i = 0; i < 1000; i++)
  182. ;
  183. }
  184. }
  185. }
  186. void
  187. microdelay(int µs)
  188. {
  189. ulong start;
  190. int i;
  191. µs++;
  192. if(clockinited){
  193. start = timerregs->oscr;
  194. while(timerregs->oscr - start < 1UL+(µs*ClockFreq)/1000000UL)
  195. ;
  196. } else {
  197. while(µs-- > 0){
  198. for(i = 0; i < 10; i++)
  199. ;
  200. }
  201. }
  202. }
  203. /*
  204. * performance measurement ticks. must be low overhead.
  205. * doesn't have to count over a second.
  206. */
  207. ulong
  208. perfticks(void)
  209. {
  210. return timerregs->oscr;
  211. }