ref: e1dcd2beb412a3e77b5c6df23571135137b486ed
dir: /sys/src/9/teg2/clock-tegra.c/
/* * 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; }