initial commit, pull in sys/arch/armv7/omap
[bbb-pru.git] / dmtimer.c
1 /* $OpenBSD: dmtimer.c,v 1.6 2015/01/22 14:33:01 krw Exp $ */
2 /*
3 * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
4 * Copyright (c) 2013 Raphael Graf <r@undefined.ch>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 /*
20 * WARNING - this timer initializion has not been checked
21 * to see if it will do _ANYTHING_ sane if the omap enters
22 * low power mode.
23 */
24
25 #include <sys/types.h>
26 #include <sys/param.h>
27 #include <sys/systm.h>
28 #include <sys/kernel.h>
29 #include <sys/time.h>
30 #include <sys/evcount.h>
31 #include <sys/device.h>
32 #include <sys/timetc.h>
33 #include <dev/clock_subr.h>
34 #include <machine/bus.h>
35 #include <armv7/armv7/armv7var.h>
36 #include <armv7/omap/prcmvar.h>
37
38 #include <machine/intr.h>
39 #include <arm/cpufunc.h>
40
41 /* registers */
42 #define DM_TIDR 0x000
43 #define DM_TIDR_MAJOR 0x00000700
44 #define DM_TIDR_MINOR 0x0000003f
45 #define DM_TIOCP_CFG 0x010
46 #define DM_TIOCP_CFG_IDLEMODE (3<<2)
47 #define DM_TIOCP_CFG_EMUFREE (1<<1)
48 #define DM_TIOCP_CFG_SOFTRESET (1<<0)
49 #define DM_TISR 0x028
50 #define DM_TISR_TCAR (1<<2)
51 #define DM_TISR_OVF (1<<1)
52 #define DM_TISR_MAT (1<<0)
53 #define DM_TIER 0x2c
54 #define DM_TIER_TCAR_EN (1<<2)
55 #define DM_TIER_OVF_EN (1<<1)
56 #define DM_TIER_MAT_EN (1<<0)
57 #define DM_TIECR 0x30
58 #define DM_TIECR_TCAR_EN (1<<2)
59 #define DM_TIECR_OVF_EN (1<<1)
60 #define DM_TIECR_MAT_EN (1<<0)
61 #define DM_TWER 0x034
62 #define DM_TWER_TCAR_EN (1<<2)
63 #define DM_TWER_OVF_EN (1<<1)
64 #define DM_TWER_MAT_EN (1<<0)
65 #define DM_TCLR 0x038
66 #define DM_TCLR_GPO (1<<14)
67 #define DM_TCLR_CAPT (1<<13)
68 #define DM_TCLR_PT (1<<12)
69 #define DM_TCLR_TRG (3<<10)
70 #define DM_TCLR_TRG_O (1<<10)
71 #define DM_TCLR_TRG_OM (2<<10)
72 #define DM_TCLR_TCM (3<<8)
73 #define DM_TCLR_TCM_RISE (1<<8)
74 #define DM_TCLR_TCM_FALL (2<<8)
75 #define DM_TCLR_TCM_BOTH (3<<8)
76 #define DM_TCLR_SCPWM (1<<7)
77 #define DM_TCLR_CE (1<<6)
78 #define DM_TCLR_PRE (1<<5)
79 #define DM_TCLR_PTV (7<<2)
80 #define DM_TCLR_AR (1<<1)
81 #define DM_TCLR_ST (1<<0)
82 #define DM_TCRR 0x03c
83 #define DM_TLDR 0x040
84 #define DM_TTGR 0x044
85 #define DM_TWPS 0x048
86 #define DM_TWPS_TMAR (1<<4)
87 #define DM_TWPS_TTGR (1<<3)
88 #define DM_TWPS_TLDR (1<<2)
89 #define DM_TWPS_TCLR (1<<0)
90 #define DM_TWPS_TCRR (1<<1)
91 #define DM_TWPS_ALL 0x1f
92 #define DM_TMAR 0x04c
93 #define DM_TCAR 0x050
94 #define DM_TSICR 0x054
95 #define DM_TSICR_POSTED (1<<2)
96 #define DM_TSICR_SFT (1<<1)
97 #define DM_TCAR2 0x058
98
99 #define TIMER_FREQUENCY 32768 /* 32kHz is used, selectable */
100 #define MAX_TIMERS 2
101
102 static struct evcount clk_count;
103 static struct evcount stat_count;
104
105 void dmtimer_attach(struct device *parent, struct device *self, void *args);
106 int dmtimer_intr(void *frame);
107 void dmtimer_wait(int reg);
108 void dmtimer_cpu_initclocks(void);
109 void dmtimer_delay(u_int);
110 void dmtimer_setstatclockrate(int newhz);
111
112 u_int dmtimer_get_timecount(struct timecounter *);
113
114 static struct timecounter dmtimer_timecounter = {
115 dmtimer_get_timecount, NULL, 0xffffffff, 0, "dmtimer", 0, NULL
116 };
117
118 bus_space_handle_t dmtimer_ioh0;
119 int dmtimer_irq = 0;
120
121 struct dmtimer_softc {
122 struct device sc_dev;
123 bus_space_tag_t sc_iot;
124 bus_space_handle_t sc_ioh[MAX_TIMERS];
125 u_int32_t sc_irq;
126 u_int32_t sc_ticks_per_second;
127 u_int32_t sc_ticks_per_intr;
128 u_int32_t sc_ticks_err_cnt;
129 u_int32_t sc_ticks_err_sum;
130 u_int32_t sc_statvar;
131 u_int32_t sc_statmin;
132 u_int32_t sc_nexttickevent;
133 u_int32_t sc_nextstatevent;
134 };
135
136 struct cfattach dmtimer_ca = {
137 sizeof (struct dmtimer_softc), NULL, dmtimer_attach
138 };
139
140 struct cfdriver dmtimer_cd = {
141 NULL, "dmtimer", DV_DULL
142 };
143
144 void
145 dmtimer_attach(struct device *parent, struct device *self, void *args)
146 {
147 struct dmtimer_softc *sc = (struct dmtimer_softc *)self;
148 struct armv7_attach_args *aa = args;
149 bus_space_handle_t ioh;
150 u_int32_t rev, cfg;
151
152 sc->sc_iot = aa->aa_iot;
153
154 if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr,
155 aa->aa_dev->mem[0].size, 0, &ioh))
156 panic("%s: bus_space_map failed!\n", __func__);
157
158
159 prcm_setclock(1, PRCM_CLK_SPEED_32);
160 prcm_setclock(2, PRCM_CLK_SPEED_32);
161 prcm_enablemodule(PRCM_TIMER2);
162 prcm_enablemodule(PRCM_TIMER3);
163
164 /* reset */
165 bus_space_write_4(sc->sc_iot, ioh, DM_TIOCP_CFG,
166 DM_TIOCP_CFG_SOFTRESET);
167 while (bus_space_read_4(sc->sc_iot, ioh, DM_TIOCP_CFG)
168 & DM_TIOCP_CFG_SOFTRESET)
169 ;
170
171 if (self->dv_unit == 0) {
172 dmtimer_ioh0 = ioh;
173 dmtimer_irq = aa->aa_dev->irq[0];
174 /* enable write posted mode */
175 bus_space_write_4(sc->sc_iot, ioh, DM_TSICR, DM_TSICR_POSTED);
176 /* stop timer */
177 bus_space_write_4(sc->sc_iot, ioh, DM_TCLR, 0);
178 } else if (self->dv_unit == 1) {
179 /* start timer because it is used in delay */
180 /* interrupts and posted mode are disabled */
181 sc->sc_irq = dmtimer_irq;
182 sc->sc_ioh[0] = dmtimer_ioh0;
183 sc->sc_ioh[1] = ioh;
184
185 bus_space_write_4(sc->sc_iot, ioh, DM_TCRR, 0);
186 bus_space_write_4(sc->sc_iot, ioh, DM_TLDR, 0);
187 bus_space_write_4(sc->sc_iot, ioh, DM_TCLR,
188 DM_TCLR_AR | DM_TCLR_ST);
189
190 dmtimer_timecounter.tc_frequency = TIMER_FREQUENCY;
191 dmtimer_timecounter.tc_priv = sc;
192 tc_init(&dmtimer_timecounter);
193 arm_clock_register(dmtimer_cpu_initclocks, dmtimer_delay,
194 dmtimer_setstatclockrate, NULL);
195 }
196 else
197 panic("attaching too many dmtimers at 0x%lx",
198 aa->aa_dev->mem[0].addr);
199
200 /* set IDLEMODE to smart-idle */
201 cfg = bus_space_read_4(sc->sc_iot, ioh, DM_TIOCP_CFG);
202 bus_space_write_4(sc->sc_iot, ioh, DM_TIOCP_CFG,
203 (cfg & ~DM_TIOCP_CFG_IDLEMODE) | 0x02);
204
205 rev = bus_space_read_4(sc->sc_iot, ioh, DM_TIDR);
206 printf(" rev %d.%d\n", (rev & DM_TIDR_MAJOR) >> 8, rev & DM_TIDR_MINOR);
207 }
208
209 /*
210 * See comment in arm/xscale/i80321_clock.c
211 *
212 * Counter is count up, but with autoreload timers it is not possible
213 * to detect how many interrupts passed while interrupts were blocked.
214 * Also it is not possible to atomically add to the register.
215 *
216 * To work around this two timers are used, one is used as a reference
217 * clock without reload, however we just disable the interrupt it
218 * could generate.
219 *
220 * Internally this keeps track of when the next timer should fire
221 * and based on that time and the current value of the reference
222 * clock a number is written into the timer count register to schedule
223 * the next event.
224 */
225
226 int
227 dmtimer_intr(void *frame)
228 {
229 struct dmtimer_softc *sc = dmtimer_cd.cd_devs[1];
230 u_int32_t now, r, nextevent;
231 int32_t duration;
232
233 now = bus_space_read_4(sc->sc_iot, sc->sc_ioh[1], DM_TCRR);
234
235 while ((int32_t) (sc->sc_nexttickevent - now) <= 0) {
236 sc->sc_nexttickevent += sc->sc_ticks_per_intr;
237 sc->sc_ticks_err_sum += sc->sc_ticks_err_cnt;
238
239 while (sc->sc_ticks_err_sum > hz) {
240 sc->sc_nexttickevent += 1;
241 sc->sc_ticks_err_sum -= hz;
242 }
243
244 clk_count.ec_count++;
245 hardclock(frame);
246 }
247
248 while ((int32_t) (sc->sc_nextstatevent - now) <= 0) {
249 do {
250 r = random() & (sc->sc_statvar - 1);
251 } while (r == 0); /* random == 0 not allowed */
252 sc->sc_nextstatevent += sc->sc_statmin + r;
253 stat_count.ec_count++;
254 statclock(frame);
255 }
256 if ((sc->sc_nexttickevent - now) < (sc->sc_nextstatevent - now))
257 nextevent = sc->sc_nexttickevent;
258 else
259 nextevent = sc->sc_nextstatevent;
260
261 duration = nextevent -
262 bus_space_read_4(sc->sc_iot, sc->sc_ioh[1], DM_TCRR);
263
264 if (duration <= 0)
265 duration = 1; /* trigger immediately. */
266
267 if (duration > sc->sc_ticks_per_intr + 1) {
268 printf("%s: time lost!\n", __func__);
269 /*
270 * If interrupts are blocked too long, like during
271 * the root prompt or ddb, the timer can roll over,
272 * this will allow the system to continue to run
273 * even if time is lost.
274 */
275 duration = sc->sc_ticks_per_intr;
276 sc->sc_nexttickevent = now;
277 sc->sc_nextstatevent = now;
278 }
279
280 bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TISR,
281 bus_space_read_4(sc->sc_iot, sc->sc_ioh[0], DM_TISR));
282 bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TCRR, -duration);
283 dmtimer_wait(DM_TWPS_ALL);
284
285 return 1;
286 }
287
288 /*
289 * would be interesting to play with trigger mode while having one timer
290 * in 32KHz mode, and the other timer running in sysclk mode and use
291 * the high resolution speeds (matters more for delay than tick timer
292 */
293
294 void
295 dmtimer_cpu_initclocks()
296 {
297 struct dmtimer_softc *sc = dmtimer_cd.cd_devs[1];
298
299 stathz = 128;
300 profhz = 1024;
301
302 sc->sc_ticks_per_second = TIMER_FREQUENCY; /* 32768 */
303
304 setstatclockrate(stathz);
305
306 sc->sc_ticks_per_intr = sc->sc_ticks_per_second / hz;
307 sc->sc_ticks_err_cnt = sc->sc_ticks_per_second % hz;
308 sc->sc_ticks_err_sum = 0;
309
310 /* establish interrupts */
311 arm_intr_establish(sc->sc_irq, IPL_CLOCK, dmtimer_intr,
312 NULL, "tick");
313
314 /* setup timer 0 */
315
316 bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TLDR, 0);
317
318 sc->sc_nexttickevent = sc->sc_nextstatevent = bus_space_read_4(sc->sc_iot,
319 sc->sc_ioh[1], DM_TCRR) + sc->sc_ticks_per_intr;
320
321 bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TIER, DM_TIER_OVF_EN);
322 bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TWER, DM_TWER_OVF_EN);
323 bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TISR, /*clear interrupt flags */
324 bus_space_read_4(sc->sc_iot, sc->sc_ioh[0], DM_TISR));
325 bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TCRR, -sc->sc_ticks_per_intr);
326 dmtimer_wait(DM_TWPS_ALL);
327 bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TCLR, /* autoreload and start */
328 DM_TCLR_AR | DM_TCLR_ST);
329 dmtimer_wait(DM_TWPS_ALL);
330 }
331
332 void
333 dmtimer_wait(int reg)
334 {
335 struct dmtimer_softc *sc = dmtimer_cd.cd_devs[1];
336 while (bus_space_read_4(sc->sc_iot, sc->sc_ioh[0], DM_TWPS) & reg)
337 ;
338 }
339
340 void
341 dmtimer_delay(u_int usecs)
342 {
343 struct dmtimer_softc *sc = dmtimer_cd.cd_devs[1];
344 u_int32_t clock, oclock, delta, delaycnt;
345 volatile int j;
346 int csec, usec;
347
348 if (usecs > (0x80000000 / (TIMER_FREQUENCY))) {
349 csec = usecs / 10000;
350 usec = usecs % 10000;
351
352 delaycnt = (TIMER_FREQUENCY / 100) * csec +
353 (TIMER_FREQUENCY / 100) * usec / 10000;
354 } else {
355 delaycnt = TIMER_FREQUENCY * usecs / 1000000;
356 }
357 if (delaycnt <= 1)
358 for (j = 100; j > 0; j--)
359 ;
360
361 if (sc->sc_ioh[1] == 0) {
362 /* BAH */
363 for (; usecs > 0; usecs--)
364 for (j = 100; j > 0; j--)
365 ;
366 return;
367 }
368 oclock = bus_space_read_4(sc->sc_iot, sc->sc_ioh[1], DM_TCRR);
369 while (1) {
370 for (j = 100; j > 0; j--)
371 ;
372 clock = bus_space_read_4(sc->sc_iot, sc->sc_ioh[1], DM_TCRR);
373 delta = clock - oclock;
374 if (delta > delaycnt)
375 break;
376 }
377
378 }
379
380 void
381 dmtimer_setstatclockrate(int newhz)
382 {
383 struct dmtimer_softc *sc = dmtimer_cd.cd_devs[1];
384 int minint, statint;
385 int s;
386
387 s = splclock();
388
389 statint = sc->sc_ticks_per_second / newhz;
390 /* calculate largest 2^n which is smaller than just over half statint */
391 sc->sc_statvar = 0x40000000; /* really big power of two */
392 minint = statint / 2 + 100;
393 while (sc->sc_statvar > minint)
394 sc->sc_statvar >>= 1;
395
396 sc->sc_statmin = statint - (sc->sc_statvar >> 1);
397
398 splx(s);
399
400 /*
401 * XXX this allows the next stat timer to occur then it switches
402 * to the new frequency. Rather than switching instantly.
403 */
404 }
405
406
407 u_int
408 dmtimer_get_timecount(struct timecounter *tc)
409 {
410 struct dmtimer_softc *sc = dmtimer_timecounter.tc_priv;
411
412 return bus_space_read_4(sc->sc_iot, sc->sc_ioh[1], DM_TCRR);
413 }