diff options
author | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-01-26 17:33:21 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-01-26 17:33:21 +0100 |
commit | ea108c8ca6e726ac008f75775ab83775ec233171 (patch) | |
tree | 982816b58d50e1b12b7eeb2c29fe22ca8d9c195b /sys/src/9/teg2/clock-tegra.c | |
parent | 43e09c468b4c6562c93c9375a316012e238d21b2 (diff) |
add tegra2 soc kernel (from sources)
Diffstat (limited to 'sys/src/9/teg2/clock-tegra.c')
-rw-r--r-- | sys/src/9/teg2/clock-tegra.c | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/sys/src/9/teg2/clock-tegra.c b/sys/src/9/teg2/clock-tegra.c new file mode 100644 index 000000000..a90e9b973 --- /dev/null +++ b/sys/src/9/teg2/clock-tegra.c @@ -0,0 +1,138 @@ +/* + * tegra 2 SoC clocks; excludes cortex-a timers. + * + * SoC provides these shared clocks: + * 4 29-bit count-down `timers' @ 1MHz, + * 1 32-bit count-up time-stamp counter @ 1MHz, + * and a real-time clock @ 32KHz. + * the tegra watchdog (tegra 2 ref man §5.4.1) is tied to timers, not rtc. + */ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "arm.h" + +typedef struct Shrdtmr Shrdtmr; +typedef struct µscnt µscnt; + +/* tegra2 shared-intr timer registers */ +struct Shrdtmr { /* 29-bit count-down timer (4); unused */ + ulong trigger; + ulong prescnt; +}; + +enum { + /* trigger bits */ + Enable = 1u<<31, + Periodintr = 1<<30, + Countmask = MASK(29), + + /* prescnt bits */ + Intrclr = 1<<30, + /* Countmask is ro */ +}; + +struct µscnt { /* tegra2 shared 32-bit count-up µs counter (1) */ + ulong cntr; + /* + * oscillator clock fraction - 1; initially 0xb (11) from u-boot + * for 12MHz periphclk. + */ + ulong cfg; + uchar _pad0[0x3c - 0x8]; + ulong freeze; +}; + +enum { + /* cfg bits */ + Dividendshift = 8, + Dividendmask = MASK(8), + Divisorshift = 0, + Divisormask = MASK(8), +}; + +void +tegclockintr(void) +{ + int junk; + Shrdtmr *tmr; + + /* appease the tegra dog */ + tmr = (Shrdtmr *)soc.tmr[0]; + junk = tmr->trigger; + USED(junk); +} + +/* + * if on cpu0, shutdown the shared tegra2 watchdog timer. + */ +void +tegclockshutdown(void) +{ + Shrdtmr *tmr; + + if (m->machno == 0) { + tmr = (Shrdtmr *)soc.tmr[0]; + tmr->prescnt = tmr->trigger = 0; + coherence(); + } +} + +void +tegwdogintr(Ureg *, void *v) +{ + int junk; + Shrdtmr *tmr; + + tmr = (Shrdtmr *)v; + tmr->prescnt |= Intrclr; + coherence(); + /* the lousy documentation says we also have to read trigger */ + junk = tmr->trigger; + USED(junk); +} + +/* start tegra2 shared watch dog */ +void +tegclock0init(void) +{ + Shrdtmr *tmr; + + tmr = (Shrdtmr *)soc.tmr[0]; + irqenable(Tn0irq, tegwdogintr, tmr, "tegra watchdog"); + + /* + * tegra watchdog only fires on the second missed interrupt, thus /2. + */ + tmr->trigger = (Dogsectimeout * Mhz / 2 - 1) | Periodintr | Enable; + coherence(); +} + +/* + * µscnt is a freerunning timer (cycle counter); it needs no + * initialisation, wraps and does not dispatch interrupts. + */ +void +tegclockinit(void) +{ + ulong old; + µscnt *µs = (µscnt *)soc.µs; + + /* verify µs counter sanity */ + assert(µs->cfg == 0xb); /* set by u-boot */ + old = µs->cntr; + delay(1); + assert(old != µs->cntr); +} + +ulong +perfticks(void) /* MHz rate, assumed by timing loops */ +{ + ulong v; + + /* keep it non-zero to prevent m->fastclock ever going to zero. */ + v = ((µscnt *)soc.µs)->cntr; + return v == 0? 1: v; +} |