clock-tegra.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /*
  2. * tegra 2 SoC clocks; excludes cortex-a timers.
  3. *
  4. * SoC provides these shared clocks:
  5. * 4 29-bit count-down `timers' @ 1MHz,
  6. * 1 32-bit count-up time-stamp counter @ 1MHz,
  7. * and a real-time clock @ 32KHz.
  8. * the tegra watchdog (tegra 2 ref man §5.4.1) is tied to timers, not rtc.
  9. */
  10. #include "u.h"
  11. #include "../port/lib.h"
  12. #include "mem.h"
  13. #include "dat.h"
  14. #include "fns.h"
  15. #include "arm.h"
  16. typedef struct Shrdtmr Shrdtmr;
  17. typedef struct µscnt µscnt;
  18. /* tegra2 shared-intr timer registers */
  19. struct Shrdtmr { /* 29-bit count-down timer (4); unused */
  20. ulong trigger;
  21. ulong prescnt;
  22. };
  23. enum {
  24. /* trigger bits */
  25. Enable = 1u<<31,
  26. Periodintr = 1<<30,
  27. Countmask = MASK(29),
  28. /* prescnt bits */
  29. Intrclr = 1<<30,
  30. /* Countmask is ro */
  31. };
  32. struct µscnt { /* tegra2 shared 32-bit count-up µs counter (1) */
  33. ulong cntr;
  34. /*
  35. * oscillator clock fraction - 1; initially 0xb (11) from u-boot
  36. * for 12MHz periphclk.
  37. */
  38. ulong cfg;
  39. uchar _pad0[0x3c - 0x8];
  40. ulong freeze;
  41. };
  42. enum {
  43. /* cfg bits */
  44. Dividendshift = 8,
  45. Dividendmask = MASK(8),
  46. Divisorshift = 0,
  47. Divisormask = MASK(8),
  48. };
  49. void
  50. tegclockintr(void)
  51. {
  52. int junk;
  53. Shrdtmr *tmr;
  54. /* appease the tegra dog */
  55. tmr = (Shrdtmr *)soc.tmr[0];
  56. junk = tmr->trigger;
  57. USED(junk);
  58. }
  59. /*
  60. * if on cpu0, shutdown the shared tegra2 watchdog timer.
  61. */
  62. void
  63. tegclockshutdown(void)
  64. {
  65. Shrdtmr *tmr;
  66. if (m->machno == 0) {
  67. tmr = (Shrdtmr *)soc.tmr[0];
  68. tmr->prescnt = tmr->trigger = 0;
  69. coherence();
  70. }
  71. }
  72. void
  73. tegwdogintr(Ureg *, void *v)
  74. {
  75. int junk;
  76. Shrdtmr *tmr;
  77. tmr = (Shrdtmr *)v;
  78. tmr->prescnt |= Intrclr;
  79. coherence();
  80. /* the lousy documentation says we also have to read trigger */
  81. junk = tmr->trigger;
  82. USED(junk);
  83. }
  84. /* start tegra2 shared watch dog */
  85. void
  86. tegclock0init(void)
  87. {
  88. Shrdtmr *tmr;
  89. tmr = (Shrdtmr *)soc.tmr[0];
  90. irqenable(Tn0irq, tegwdogintr, tmr, "tegra watchdog");
  91. /*
  92. * tegra watchdog only fires on the second missed interrupt, thus /2.
  93. */
  94. tmr->trigger = (Dogsectimeout * Mhz / 2 - 1) | Periodintr | Enable;
  95. coherence();
  96. }
  97. /*
  98. * µscnt is a freerunning timer (cycle counter); it needs no
  99. * initialisation, wraps and does not dispatch interrupts.
  100. */
  101. void
  102. tegclockinit(void)
  103. {
  104. ulong old;
  105. µscnt *µs = (µscnt *)soc.µs;
  106. /* verify µs counter sanity */
  107. assert(µs->cfg == 0xb); /* set by u-boot */
  108. old = µs->cntr;
  109. delay(1);
  110. assert(old != µs->cntr);
  111. }
  112. ulong
  113. perfticks(void) /* MHz rate, assumed by timing loops */
  114. {
  115. ulong v;
  116. /* keep it non-zero to prevent m->fastclock ever going to zero. */
  117. v = ((µscnt *)soc.µs)->cntr;
  118. return v == 0? 1: v;
  119. }