clock.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. * kirkwood clocks
  3. *
  4. * timers count down to zero.
  5. */
  6. #include "u.h"
  7. #include "../port/lib.h"
  8. #include "mem.h"
  9. #include "dat.h"
  10. #include "fns.h"
  11. #include "io.h"
  12. #include "ureg.h"
  13. #define TIMERREG ((TimerReg *)AddrTimer)
  14. enum {
  15. Tcycles = CLOCKFREQ / HZ, /* cycles per clock tick */
  16. Dogperiod = 15 * CLOCKFREQ, /* at most 21 s.; must fit in ulong */
  17. MaxPeriod = Tcycles,
  18. MinPeriod = MaxPeriod / 100,
  19. /* timer ctl bits */
  20. Tmr0enable = 1<<0,
  21. Tmr0reload = 1<<1, /* at 0 count, load timer0 from reload0 */
  22. Tmr1enable = 1<<2,
  23. Tmr1reload = 1<<3, /* at 0 count, load timer1 from reload1 */
  24. TmrWDenable = 1<<4,
  25. TmrWDreload = 1<<5,
  26. };
  27. typedef struct TimerReg TimerReg;
  28. struct TimerReg
  29. {
  30. ulong ctl;
  31. ulong pad[3];
  32. ulong reload0;
  33. ulong timer0; /* cycles until zero */
  34. ulong reload1;
  35. ulong timer1; /* cycles until zero */
  36. ulong reloadwd;
  37. ulong timerwd;
  38. };
  39. static int ticks; /* for sanity checking; m->ticks doesn't always get updated */
  40. static void
  41. clockintr(Ureg *ureg, void *arg)
  42. {
  43. TimerReg *tmr = arg;
  44. static int nesting;
  45. tmr->timerwd = Dogperiod; /* reassure the watchdog */
  46. ticks++;
  47. coherence();
  48. if (nesting == 0) { /* if the clock interrupted itself, bail out */
  49. ++nesting;
  50. timerintr(ureg, 0);
  51. --nesting;
  52. }
  53. intrclear(Irqbridge, IRQcputimer0);
  54. }
  55. /* stop clock interrupts and disable the watchdog timer */
  56. void
  57. clockshutdown(void)
  58. {
  59. TIMERREG->ctl = 0;
  60. coherence();
  61. }
  62. void
  63. clockinit(void)
  64. {
  65. int i, s;
  66. CpucsReg *cpu = CPUCSREG;
  67. TimerReg *tmr = TIMERREG;
  68. clockshutdown();
  69. /*
  70. * verify sanity of timer0
  71. */
  72. intrenable(Irqbridge, IRQcputimer0, clockintr, tmr, "clock0");
  73. s = spllo(); /* risky */
  74. /* take any deferred clock (& other) interrupts here */
  75. splx(s);
  76. /* adjust m->bootdelay, used by delay()? */
  77. m->ticks = ticks = 0;
  78. m->fastclock = 0;
  79. tmr->timer0 = 1;
  80. tmr->ctl = Tmr0enable; /* just once */
  81. coherence();
  82. s = spllo(); /* risky */
  83. for (i = 0; i < 10 && ticks == 0; i++) {
  84. delay(1);
  85. coherence();
  86. }
  87. splx(s);
  88. if (ticks == 0) {
  89. serialputc('?');
  90. if (tmr->timer0 == 0)
  91. panic("clock not interrupting");
  92. else if (tmr->timer0 == tmr->reload0)
  93. panic("clock not ticking");
  94. else
  95. panic("clock running very slowly");
  96. }
  97. /*
  98. * configure all timers
  99. */
  100. clockshutdown();
  101. tmr->reload0 = tmr->timer0 = Tcycles; /* tick clock */
  102. tmr->reload1 = tmr->timer1 = ~0; /* cycle clock */
  103. tmr->timerwd = Dogperiod; /* watch dog timer */
  104. coherence();
  105. tmr->ctl = Tmr0enable | Tmr0reload | Tmr1enable | Tmr1reload |
  106. TmrWDenable;
  107. cpu->rstout |= RstoutWatchdog;
  108. coherence();
  109. }
  110. void
  111. timerset(Tval next)
  112. {
  113. int offset;
  114. TimerReg *tmr = TIMERREG;
  115. offset = next - fastticks(nil);
  116. if(offset < MinPeriod)
  117. offset = MinPeriod;
  118. else if(offset > MaxPeriod)
  119. offset = MaxPeriod;
  120. tmr->timer0 = offset;
  121. coherence();
  122. }
  123. uvlong
  124. fastticks(uvlong *hz)
  125. {
  126. uvlong now;
  127. int s;
  128. if(hz)
  129. *hz = CLOCKFREQ;
  130. s = splhi();
  131. /* zero low ulong of fastclock */
  132. now = (m->fastclock & ~(uvlong)~0ul) | perfticks();
  133. if(now < m->fastclock) /* low bits must have wrapped */
  134. now += 1ll << 32;
  135. m->fastclock = now;
  136. splx(s);
  137. return now;
  138. }
  139. ulong
  140. perfticks(void)
  141. {
  142. return ~TIMERREG->timer1;
  143. }
  144. long
  145. lcycles(void)
  146. {
  147. return perfticks();
  148. }
  149. ulong
  150. µs(void)
  151. {
  152. return fastticks2us(fastticks(nil));
  153. }
  154. void
  155. microdelay(int l)
  156. {
  157. int i;
  158. l *= m->delayloop;
  159. l /= 1000;
  160. if(l <= 0)
  161. l = 1;
  162. for(i = 0; i < l; i++)
  163. ;
  164. }
  165. void
  166. delay(int l)
  167. {
  168. ulong i, j;
  169. j = m->delayloop;
  170. while(l-- > 0)
  171. for(i=0; i < j; i++)
  172. ;
  173. }