xref: /openbsd/sys/arch/armv7/omap/gptimer.c (revision 24ee467d)
1 /* $OpenBSD: gptimer.c,v 1.19 2023/02/04 19:19:36 cheloha Exp $ */
2 /*
3  * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /*
19  *	WARNING - this timer initialization has not been checked
20  *	to see if it will do _ANYTHING_ sane if the omap enters
21  *	low power mode.
22  */
23 
24 #include <sys/param.h>
25 #include <sys/systm.h>
26 #include <sys/clockintr.h>
27 #include <sys/kernel.h>
28 #include <sys/evcount.h>
29 #include <sys/device.h>
30 #include <sys/stdint.h>
31 #include <sys/timetc.h>
32 #include <machine/bus.h>
33 #include <armv7/armv7/armv7var.h>
34 #include <armv7/omap/prcmvar.h>
35 
36 #include <machine/intr.h>
37 
38 /* registers */
39 #define	GP_TIDR		0x000
40 #define		GP_TIDR_REV	0xff
41 #define GP_TIOCP_CFG	0x010
42 #define 	GP_TIOCP_CFG_CLKA	0x000000300
43 #define 	GP_TIOCP_CFG_EMUFREE	0x000000020
44 #define 	GP_TIOCP_CFG_IDLEMODE	0x000000018
45 #define 	GP_TIOCP_CFG_ENAPWAKEUP	0x000000004
46 #define 	GP_TIOCP_CFG_SOFTRESET	0x000000002
47 #define 	GP_TIOCP_CFG_AUTOIDLE	0x000000001
48 #define	GP_TISTAT	0x014
49 #define 	GP_TISTAT_RESETDONE	0x000000001
50 #define	GP_TISR		0x018
51 #define		GP_TISTAT_TCAR		0x00000004
52 #define		GP_TISTAT_OVF		0x00000002
53 #define		GP_TISTAT_MATCH		0x00000001
54 #define GP_TIER		0x1c
55 #define		GP_TIER_TCAR_EN		0x4
56 #define		GP_TIER_OVF_EN		0x2
57 #define		GP_TIER_MAT_EN		0x1
58 #define	GP_TWER		0x020
59 #define		GP_TWER_TCAR_EN		0x00000004
60 #define		GP_TWER_OVF_EN		0x00000002
61 #define		GP_TWER_MAT_EN		0x00000001
62 #define	GP_TCLR		0x024
63 #define		GP_TCLR_GPO		(1<<14)
64 #define		GP_TCLR_CAPT		(1<<13)
65 #define		GP_TCLR_PT		(1<<12)
66 #define		GP_TCLR_TRG		(3<<10)
67 #define		GP_TCLR_TRG_O		(1<<10)
68 #define		GP_TCLR_TRG_OM		(2<<10)
69 #define		GP_TCLR_TCM		(3<<8)
70 #define		GP_TCLR_TCM_RISE	(1<<8)
71 #define		GP_TCLR_TCM_FALL	(2<<8)
72 #define		GP_TCLR_TCM_BOTH	(3<<8)
73 #define		GP_TCLR_SCPWM		(1<<7)
74 #define		GP_TCLR_CE		(1<<6)
75 #define		GP_TCLR_PRE		(1<<5)
76 #define		GP_TCLR_PTV		(7<<2)
77 #define		GP_TCLR_AR		(1<<1)
78 #define		GP_TCLR_ST		(1<<0)
79 #define	GP_TCRR		0x028				/* counter */
80 #define	GP_TLDR		0x02c				/* reload */
81 #define	GP_TTGR		0x030
82 #define	GP_TWPS		0x034
83 #define		GP_TWPS_TCLR	0x01
84 #define		GP_TWPS_TCRR	0x02
85 #define		GP_TWPS_TLDR	0x04
86 #define		GP_TWPS_TTGR	0x08
87 #define		GP_TWPS_TMAR	0x10
88 #define		GP_TWPS_ALL	0x1f
89 #define	GP_TMAR		0x038
90 #define	GP_TCAR		0x03C
91 #define	GP_TSICR	0x040
92 #define		GP_TSICR_POSTED		0x00000002
93 #define		GP_TSICR_SFT		0x00000001
94 #define	GP_TCAR2	0x044
95 
96 #define TIMER_FREQUENCY			32768	/* 32kHz is used, selectable */
97 
98 void gptimer_attach(struct device *parent, struct device *self, void *args);
99 int gptimer_intr(void *frame);
100 void gptimer_wait(int reg);
101 void gptimer_cpu_initclocks(void);
102 void gptimer_delay(u_int);
103 void gptimer_reset_tisr(void);
104 void gptimer_setstatclockrate(int newhz);
105 
106 bus_space_tag_t gptimer_iot;
107 bus_space_handle_t gptimer_ioh0, gptimer_ioh1;
108 int gptimer_irq = 0;
109 
110 u_int gptimer_get_timecount(struct timecounter *);
111 
112 static struct timecounter gptimer_timecounter = {
113 	.tc_get_timecount = gptimer_get_timecount,
114 	.tc_counter_mask = 0xffffffff,
115 	.tc_frequency = 0,
116 	.tc_name = "gptimer",
117 	.tc_quality = 0,
118 	.tc_priv = NULL,
119 	.tc_user = 0,
120 };
121 
122 uint64_t gptimer_nsec_cycle_ratio;
123 uint64_t gptimer_nsec_max;
124 
125 void gptimer_rearm(void *, uint64_t);
126 void gptimer_trigger(void *);
127 
128 const struct intrclock gptimer_intrclock = {
129 	.ic_rearm = gptimer_rearm,
130 	.ic_trigger = gptimer_trigger
131 };
132 
133 const struct cfattach	gptimer_ca = {
134 	sizeof (struct device), NULL, gptimer_attach
135 };
136 
137 struct cfdriver gptimer_cd = {
138 	NULL, "gptimer", DV_DULL
139 };
140 
141 void
142 gptimer_attach(struct device *parent, struct device *self, void *args)
143 {
144 	struct armv7_attach_args *aa = args;
145 	bus_space_handle_t ioh;
146 	u_int32_t rev;
147 
148 	gptimer_iot = aa->aa_iot;
149 	if (bus_space_map(gptimer_iot, aa->aa_dev->mem[0].addr,
150 	    aa->aa_dev->mem[0].size, 0, &ioh))
151 		panic("gptimer_attach: bus_space_map failed!");
152 
153 	rev = bus_space_read_4(gptimer_iot, ioh, GP_TIDR);
154 
155 	printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf);
156 	if (self->dv_unit == 0) {
157 		gptimer_ioh0 = ioh;
158 		gptimer_irq = aa->aa_dev->irq[0];
159 		bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR, 0);
160 	} else if (self->dv_unit == 1) {
161 		/* start timer because it is used in delay */
162 		gptimer_ioh1 = ioh;
163 		bus_space_write_4(gptimer_iot, gptimer_ioh1, GP_TCRR, 0);
164 		gptimer_wait(GP_TWPS_ALL);
165 		bus_space_write_4(gptimer_iot, gptimer_ioh1, GP_TLDR, 0);
166 		gptimer_wait(GP_TWPS_ALL);
167 		bus_space_write_4(gptimer_iot, gptimer_ioh1, GP_TCLR,
168 		    GP_TCLR_AR | GP_TCLR_ST);
169 		gptimer_wait(GP_TWPS_ALL);
170 
171 		gptimer_timecounter.tc_frequency = TIMER_FREQUENCY;
172 		tc_init(&gptimer_timecounter);
173 	}
174 	else
175 		panic("attaching too many gptimers at 0x%lx",
176 		    aa->aa_dev->mem[0].addr);
177 
178 	arm_clock_register(gptimer_cpu_initclocks, gptimer_delay,
179 	    gptimer_setstatclockrate, NULL);
180 }
181 
182 int
183 gptimer_intr(void *frame)
184 {
185 	clockintr_dispatch(frame);
186 	return 1;
187 }
188 
189 /*
190  * would be interesting to play with trigger mode while having one timer
191  * in 32kHz mode, and the other timer running in sysclk mode and use
192  * the high resolution speeds (matters more for delay than tick timer
193  */
194 
195 void
196 gptimer_cpu_initclocks(void)
197 {
198 	stathz = hz;
199 	profhz = stathz * 10;
200 	clockintr_init(CL_RNDSTAT);
201 
202 	gptimer_nsec_cycle_ratio = TIMER_FREQUENCY * (1ULL << 32) / 1000000000;
203 	gptimer_nsec_max = UINT64_MAX / gptimer_nsec_cycle_ratio;
204 
205 	prcm_setclock(1, PRCM_CLK_SPEED_32);
206 	prcm_setclock(2, PRCM_CLK_SPEED_32);
207 
208 	/* establish interrupts */
209 	arm_intr_establish(gptimer_irq, IPL_CLOCK, gptimer_intr,
210 	    NULL, "tick");
211 
212 	/* setup timer 0 (hardware timer 2) */
213 	/* reset? - XXX */
214 	gptimer_wait(GP_TWPS_ALL);
215 	bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TIER, GP_TIER_OVF_EN);
216 	gptimer_wait(GP_TWPS_ALL);
217 	bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TWER, GP_TWER_OVF_EN);
218 	gptimer_wait(GP_TWPS_ALL);
219 
220 	/* start the clock interrupt cycle */
221 	clockintr_cpu_init(&gptimer_intrclock);
222 	clockintr_trigger();
223 }
224 
225 void
226 gptimer_wait(int reg)
227 {
228 	while (bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TWPS) & reg)
229 		;
230 }
231 
232 /*
233  * Clear all interrupt status bits.
234  */
235 void
236 gptimer_reset_tisr(void)
237 {
238 	u_int32_t tisr;
239 
240 	tisr = bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TISR);
241 	bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TISR, tisr);
242 }
243 
244 void
245 gptimer_rearm(void *unused, uint64_t nsecs)
246 {
247 	uint32_t cycles;
248 	u_long s;
249 
250 	if (nsecs > gptimer_nsec_max)
251 		nsecs = gptimer_nsec_max;
252 	cycles = (nsecs * gptimer_nsec_cycle_ratio) >> 32;
253 
254 	s = intr_disable();
255 	gptimer_reset_tisr();
256         bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCRR,
257 	    UINT32_MAX - cycles);
258 	bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR, GP_TCLR_ST);
259 	gptimer_wait(GP_TWPS_ALL);
260 	intr_restore(s);
261 }
262 
263 void
264 gptimer_trigger(void *unused)
265 {
266 	u_long s;
267 
268 	s = intr_disable();
269 
270 	/* stop timer. */
271 	bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR, 0);
272 	gptimer_wait(GP_TWPS_ALL);
273 
274 	/* clear interrupt status bits. */
275 	gptimer_reset_tisr();
276 
277 	/* set shortest possible timeout. */
278 	bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCRR, UINT32_MAX);
279 
280 	/* start timer, wait for writes to post. */
281 	bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR, GP_TCLR_ST);
282 	gptimer_wait(GP_TWPS_ALL);
283 
284 	intr_restore(s);
285 }
286 
287 void
288 gptimer_delay(u_int usecs)
289 {
290 	u_int32_t clock, oclock, delta, delaycnt;
291 	volatile int j;
292 	int csec, usec;
293 
294 	if (usecs > (0x80000000 / (TIMER_FREQUENCY))) {
295 		csec = usecs / 10000;
296 		usec = usecs % 10000;
297 
298 		delaycnt = (TIMER_FREQUENCY / 100) * csec +
299 		    (TIMER_FREQUENCY / 100) * usec / 10000;
300 	} else {
301 		delaycnt = TIMER_FREQUENCY * usecs / 1000000;
302 	}
303 	if (delaycnt <= 1)
304 		for (j = 100; j > 0; j--)
305 			;
306 
307 	if (gptimer_ioh1 == 0) {
308 		/* BAH */
309 		for (; usecs > 0; usecs--)
310 			for (j = 100; j > 0; j--)
311 				;
312 		return;
313 	}
314 	oclock = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR);
315 	while (1) {
316 		for (j = 100; j > 0; j--)
317 			;
318 		clock = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR);
319 		delta = clock - oclock;
320 		if (delta > delaycnt)
321 			break;
322 	}
323 
324 }
325 
326 void
327 gptimer_setstatclockrate(int newhz)
328 {
329 	clockintr_setstatclockrate(newhz);
330 }
331 
332 
333 u_int
334 gptimer_get_timecount(struct timecounter *tc)
335 {
336 	return bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR);
337 }
338