clock.c 3.6 KB

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