clock.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. * bcm2835 timers
  3. * System timers run at 1MHz (timers 1 and 2 are used by GPU)
  4. * ARM timer usually runs at 250MHz (may be slower in low power modes)
  5. * Cycle counter runs at 700MHz (unless overclocked)
  6. * All are free-running up-counters
  7. *
  8. * Use system timer 3 (64 bits) for hzclock interrupts and fastticks
  9. * Use ARM timer (32 bits) for perfticks
  10. * Use ARM timer to force immediate interrupt
  11. * Use cycle counter for cycles()
  12. */
  13. #include "u.h"
  14. #include "../port/lib.h"
  15. #include "mem.h"
  16. #include "dat.h"
  17. #include "fns.h"
  18. #include "io.h"
  19. enum {
  20. SYSTIMERS = VIRTIO+0x3000,
  21. ARMTIMER = VIRTIO+0xB400,
  22. SystimerFreq = 1*Mhz,
  23. MaxPeriod = SystimerFreq / HZ,
  24. MinPeriod = SystimerFreq / (100*HZ),
  25. };
  26. typedef struct Systimers Systimers;
  27. typedef struct Armtimer Armtimer;
  28. struct Systimers {
  29. u32int cs;
  30. u32int clo;
  31. u32int chi;
  32. u32int c0;
  33. u32int c1;
  34. u32int c2;
  35. u32int c3;
  36. };
  37. struct Armtimer {
  38. u32int load;
  39. u32int val;
  40. u32int ctl;
  41. u32int irqack;
  42. u32int irq;
  43. u32int maskedirq;
  44. u32int reload;
  45. u32int predivider;
  46. u32int count;
  47. };
  48. enum {
  49. CntPrescaleShift= 16, /* freq is sys_clk/(prescale+1) */
  50. CntPrescaleMask = 0xFF,
  51. CntEnable = 1<<9,
  52. TmrDbgHalt = 1<<8,
  53. TmrEnable = 1<<7,
  54. TmrIntEnable = 1<<5,
  55. TmrPrescale1 = 0x00<<2,
  56. TmrPrescale16 = 0x01<<2,
  57. TmrPrescale256 = 0x02<<2,
  58. CntWidth16 = 0<<1,
  59. CntWidth32 = 1<<1,
  60. };
  61. static void
  62. clockintr(Ureg *ureg, void *)
  63. {
  64. Systimers *tn;
  65. tn = (Systimers*)SYSTIMERS;
  66. /* dismiss interrupt */
  67. tn->cs = 1<<3;
  68. timerintr(ureg, 0);
  69. }
  70. void
  71. clockshutdown(void)
  72. {
  73. Armtimer *tm;
  74. tm = (Armtimer*)ARMTIMER;
  75. tm->ctl = 0;
  76. wdogoff();
  77. }
  78. void
  79. clockinit(void)
  80. {
  81. Systimers *tn;
  82. Armtimer *tm;
  83. u32int t0, t1, tstart, tend;
  84. tn = (Systimers*)SYSTIMERS;
  85. tm = (Armtimer*)ARMTIMER;
  86. tm->load = 0;
  87. tm->ctl = TmrPrescale1|CntEnable|CntWidth32;
  88. tstart = tn->clo;
  89. do{
  90. t0 = lcycles();
  91. }while(tn->clo == tstart);
  92. tend = tstart + 10000;
  93. do{
  94. t1 = lcycles();
  95. }while(tn->clo != tend);
  96. t1 -= t0;
  97. m->cpuhz = 100 * t1;
  98. m->cpumhz = (m->cpuhz + Mhz/2 - 1) / Mhz;
  99. m->cyclefreq = m->cpuhz;
  100. tn->c3 = tn->clo - 1;
  101. intrenable(IRQtimer3, clockintr, nil, 0, "clock");
  102. }
  103. void
  104. timerset(uvlong next)
  105. {
  106. Systimers *tn;
  107. vlong now, period;
  108. tn = (Systimers*)SYSTIMERS;
  109. now = fastticks(nil);
  110. period = next - fastticks(nil);
  111. if(period < MinPeriod)
  112. next = now + MinPeriod;
  113. else if(period > MaxPeriod)
  114. next = now + MaxPeriod;
  115. tn->c3 = (ulong)next;
  116. }
  117. uvlong
  118. fastticks(uvlong *hz)
  119. {
  120. Systimers *tn;
  121. ulong lo, hi;
  122. tn = (Systimers*)SYSTIMERS;
  123. if(hz)
  124. *hz = SystimerFreq;
  125. do{
  126. hi = tn->chi;
  127. lo = tn->clo;
  128. }while(tn->chi != hi);
  129. m->fastclock = (uvlong)hi<<32 | lo;
  130. return m->fastclock;
  131. }
  132. ulong
  133. perfticks(void)
  134. {
  135. Armtimer *tm;
  136. tm = (Armtimer*)ARMTIMER;
  137. return tm->count;
  138. }
  139. void
  140. armtimerset(int n)
  141. {
  142. Armtimer *tm;
  143. tm = (Armtimer*)ARMTIMER;
  144. if(n > 0){
  145. tm->ctl |= TmrEnable|TmrIntEnable;
  146. tm->load = n;
  147. }else{
  148. tm->load = 0;
  149. tm->ctl &= ~(TmrEnable|TmrIntEnable);
  150. tm->irq = 1;
  151. }
  152. }
  153. ulong
  154. µs(void)
  155. {
  156. if(SystimerFreq != 1*Mhz)
  157. return fastticks2us(fastticks(nil));
  158. return fastticks(nil);
  159. }
  160. void
  161. microdelay(int n)
  162. {
  163. Systimers *tn;
  164. u32int now, diff;
  165. tn = (Systimers*)SYSTIMERS;
  166. diff = n + 1;
  167. now = tn->clo;
  168. while(tn->clo - now < diff)
  169. ;
  170. }
  171. void
  172. delay(int n)
  173. {
  174. while(--n >= 0)
  175. microdelay(1000);
  176. }