]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/teg2/clock-tegra.c
usbehci: catch interrupt in tsleep
[plan9front.git] / sys / src / 9 / teg2 / clock-tegra.c
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
17 typedef struct Shrdtmr Shrdtmr;
18 typedef struct µscnt µscnt;
19
20 /* tegra2 shared-intr timer registers */
21 struct Shrdtmr {                /* 29-bit count-down timer (4); unused */
22         ulong   trigger;
23         ulong   prescnt;
24 };
25
26 enum {
27         /* trigger bits */
28         Enable =        1u<<31,
29         Periodintr =    1<<30,
30         Countmask =     MASK(29),
31
32         /* prescnt bits */
33         Intrclr =       1<<30,
34         /* Countmask is ro */
35 };
36
37 struct µscnt {         /* tegra2 shared 32-bit count-up µs counter (1) */
38         ulong   cntr;
39         /*
40          * oscillator clock fraction - 1; initially 0xb (11) from u-boot
41          * for 12MHz periphclk.
42          */
43         ulong   cfg;
44         uchar   _pad0[0x3c - 0x8];
45         ulong   freeze;
46 };
47
48 enum {
49         /* cfg bits */
50         Dividendshift = 8,
51         Dividendmask =  MASK(8),
52         Divisorshift =  0,
53         Divisormask =   MASK(8),
54 };
55
56 void
57 tegclockintr(void)
58 {
59         int junk;
60         Shrdtmr *tmr;
61
62         /* appease the tegra dog */
63         tmr = (Shrdtmr *)soc.tmr[0];
64         junk = tmr->trigger;
65         USED(junk);
66 }
67
68 /*
69  * if on cpu0, shutdown the shared tegra2 watchdog timer.
70  */
71 void
72 tegclockshutdown(void)
73 {
74         Shrdtmr *tmr;
75
76         if (m->machno == 0) {
77                 tmr = (Shrdtmr *)soc.tmr[0];
78                 tmr->prescnt = tmr->trigger = 0;
79                 coherence();
80         }
81 }
82
83 void
84 tegwdogintr(Ureg *, void *v)
85 {
86         int junk;
87         Shrdtmr *tmr;
88
89         tmr = (Shrdtmr *)v;
90         tmr->prescnt |= Intrclr;
91         coherence();
92         /* the lousy documentation says we also have to read trigger */
93         junk = tmr->trigger;
94         USED(junk);
95 }
96
97 /* start tegra2 shared watch dog */
98 void
99 tegclock0init(void)
100 {
101         Shrdtmr *tmr;
102
103         tmr = (Shrdtmr *)soc.tmr[0];
104         irqenable(Tn0irq, tegwdogintr, tmr, "tegra watchdog");
105
106         /*
107          * tegra watchdog only fires on the second missed interrupt, thus /2.
108          */
109         tmr->trigger = (Dogsectimeout * Mhz / 2 - 1) | Periodintr | Enable;
110         coherence();
111 }
112
113 /*
114  * µscnt is a freerunning timer (cycle counter); it needs no
115  * initialisation, wraps and does not dispatch interrupts.
116  */
117 void
118 tegclockinit(void)
119 {
120         ulong old;
121         µscnt *µs = (µscnt *)soc.µs;
122
123         /* verify µs counter sanity */
124         assert(µs->cfg == 0xb);                        /* set by u-boot */
125         old = µs->cntr;
126         delay(1);
127         assert(old != µs->cntr);
128 }
129
130 ulong
131 perfticks(void)                 /* MHz rate, assumed by timing loops */
132 {
133         ulong v;
134
135         /* keep it non-zero to prevent m->fastclock ever going to zero. */
136         v = ((µscnt *)soc.µs)->cntr;
137         return v == 0? 1: v;
138 }