clock.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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. enum {
  14. Tcycles = CLOCKFREQ / HZ, /* cycles per clock tick */
  15. Dogperiod = 15 * CLOCKFREQ, /* at most 21 s.; must fit in ulong */
  16. MaxPeriod = Tcycles,
  17. MinPeriod = MaxPeriod / 100,
  18. /* timer ctl bits */
  19. Tmr0enable = 1<<0,
  20. Tmr0reload = 1<<1, /* at 0 count, load timer0 from reload0 */
  21. Tmr1enable = 1<<2,
  22. Tmr1reload = 1<<3, /* at 0 count, load timer1 from reload1 */
  23. TmrWDenable = 1<<4,
  24. TmrWDreload = 1<<5,
  25. };
  26. typedef struct TimerReg TimerReg;
  27. struct TimerReg
  28. {
  29. ulong ctl;
  30. ulong pad[3];
  31. ulong reload0;
  32. ulong timer0; /* cycles until zero */
  33. ulong reload1;
  34. ulong timer1; /* cycles until zero */
  35. ulong reloadwd;
  36. ulong timerwd;
  37. };
  38. static int ticks; /* for sanity checking; m->ticks doesn't always get updated */
  39. static void
  40. clockintr(Ureg *ureg, void *arg)
  41. {
  42. TimerReg *tmr = arg;
  43. static int nesting;
  44. tmr->timerwd = Dogperiod; /* reassure the watchdog */
  45. ticks++;
  46. coherence();
  47. if (nesting == 0) { /* if the clock interrupted itself, bail out */
  48. ++nesting;
  49. timerintr(ureg, 0);
  50. --nesting;
  51. }
  52. intrclear(Irqbridge, IRQcputimer0);
  53. }
  54. /* stop clock interrupts and disable the watchdog timer */
  55. void
  56. clockshutdown(void)
  57. {
  58. TimerReg *tmr = (TimerReg *)soc.clock;
  59. tmr->ctl = 0;
  60. coherence();
  61. }
  62. void
  63. clockinit(void)
  64. {
  65. int i, s;
  66. CpucsReg *cpu = (CpucsReg *)soc.cpu;
  67. TimerReg *tmr = (TimerReg *)soc.clock;
  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 *)soc.clock;
  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. TimerReg *tmr = (TimerReg *)soc.clock;
  143. return ~tmr->timer1;
  144. }
  145. long
  146. lcycles(void)
  147. {
  148. return perfticks();
  149. }
  150. ulong
  151. µs(void)
  152. {
  153. return fastticks2us(fastticks(nil));
  154. }
  155. void
  156. microdelay(int l)
  157. {
  158. int i;
  159. l *= m->delayloop;
  160. l /= 1000;
  161. if(l <= 0)
  162. l = 1;
  163. for(i = 0; i < l; i++)
  164. ;
  165. }
  166. void
  167. delay(int l)
  168. {
  169. ulong i, j;
  170. j = m->delayloop;
  171. while(l-- > 0)
  172. for(i=0; i < j; i++)
  173. ;
  174. }