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