xref: /openbsd/sys/arch/armv7/omap/gptimer.c (revision 0ed1bf01)
1 /* $OpenBSD: gptimer.c,v 1.23 2023/09/17 14:50:51 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_cpu_startclock(void);
103 void gptimer_delay(u_int);
104 void gptimer_reset_tisr(void);
105 void gptimer_setstatclockrate(int newhz);
106 
107 bus_space_tag_t gptimer_iot;
108 bus_space_handle_t gptimer_ioh0, gptimer_ioh1;
109 int gptimer_irq = 0;
110 
111 u_int gptimer_get_timecount(struct timecounter *);
112 
113 static struct timecounter gptimer_timecounter = {
114 	.tc_get_timecount = gptimer_get_timecount,
115 	.tc_counter_mask = 0xffffffff,
116 	.tc_frequency = 0,
117 	.tc_name = "gptimer",
118 	.tc_quality = 0,
119 	.tc_priv = NULL,
120 	.tc_user = 0,
121 };
122 
123 uint64_t gptimer_nsec_cycle_ratio;
124 uint64_t gptimer_nsec_max;
125 
126 void gptimer_rearm(void *, uint64_t);
127 void gptimer_trigger(void *);
128 
129 const struct intrclock gptimer_intrclock = {
130 	.ic_rearm = gptimer_rearm,
131 	.ic_trigger = gptimer_trigger
132 };
133 
134 const struct cfattach	gptimer_ca = {
135 	sizeof (struct device), NULL, gptimer_attach
136 };
137 
138 struct cfdriver gptimer_cd = {
139 	NULL, "gptimer", DV_DULL
140 };
141 
142 void
gptimer_attach(struct device * parent,struct device * self,void * args)143 gptimer_attach(struct device *parent, struct device *self, void *args)
144 {
145 	struct armv7_attach_args *aa = args;
146 	bus_space_handle_t ioh;
147 	u_int32_t rev;
148 
149 	gptimer_iot = aa->aa_iot;
150 	if (bus_space_map(gptimer_iot, aa->aa_dev->mem[0].addr,
151 	    aa->aa_dev->mem[0].size, 0, &ioh))
152 		panic("gptimer_attach: bus_space_map failed!");
153 
154 	rev = bus_space_read_4(gptimer_iot, ioh, GP_TIDR);
155 
156 	printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf);
157 	if (self->dv_unit == 0) {
158 		gptimer_ioh0 = ioh;
159 		gptimer_irq = aa->aa_dev->irq[0];
160 		bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR, 0);
161 	} else if (self->dv_unit == 1) {
162 		/* start timer because it is used in delay */
163 		gptimer_ioh1 = ioh;
164 		bus_space_write_4(gptimer_iot, gptimer_ioh1, GP_TCRR, 0);
165 		gptimer_wait(GP_TWPS_ALL);
166 		bus_space_write_4(gptimer_iot, gptimer_ioh1, GP_TLDR, 0);
167 		gptimer_wait(GP_TWPS_ALL);
168 		bus_space_write_4(gptimer_iot, gptimer_ioh1, GP_TCLR,
169 		    GP_TCLR_AR | GP_TCLR_ST);
170 		gptimer_wait(GP_TWPS_ALL);
171 
172 		gptimer_timecounter.tc_frequency = TIMER_FREQUENCY;
173 		tc_init(&gptimer_timecounter);
174 	}
175 	else
176 		panic("attaching too many gptimers at 0x%lx",
177 		    aa->aa_dev->mem[0].addr);
178 
179 	arm_clock_register(gptimer_cpu_initclocks, gptimer_delay,
180 	    gptimer_setstatclockrate, gptimer_cpu_startclock);
181 }
182 
183 int
gptimer_intr(void * frame)184 gptimer_intr(void *frame)
185 {
186 	clockintr_dispatch(frame);
187 	return 1;
188 }
189 
190 /*
191  * would be interesting to play with trigger mode while having one timer
192  * in 32kHz mode, and the other timer running in sysclk mode and use
193  * the high resolution speeds (matters more for delay than tick timer
194  */
195 
196 void
gptimer_cpu_initclocks(void)197 gptimer_cpu_initclocks(void)
198 {
199 	stathz = hz;
200 	profhz = stathz * 10;
201 	statclock_is_randomized = 1;
202 
203 	gptimer_nsec_cycle_ratio = TIMER_FREQUENCY * (1ULL << 32) / 1000000000;
204 	gptimer_nsec_max = UINT64_MAX / gptimer_nsec_cycle_ratio;
205 
206 	prcm_setclock(1, PRCM_CLK_SPEED_32);
207 	prcm_setclock(2, PRCM_CLK_SPEED_32);
208 
209 	/* establish interrupts */
210 	arm_intr_establish(gptimer_irq, IPL_CLOCK, gptimer_intr,
211 	    NULL, "tick");
212 
213 	/* setup timer 0 (hardware timer 2) */
214 	/* reset? - XXX */
215 	gptimer_wait(GP_TWPS_ALL);
216 	bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TIER, GP_TIER_OVF_EN);
217 	gptimer_wait(GP_TWPS_ALL);
218 	bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TWER, GP_TWER_OVF_EN);
219 	gptimer_wait(GP_TWPS_ALL);
220 }
221 
222 void
gptimer_cpu_startclock(void)223 gptimer_cpu_startclock(void)
224 {
225 	/* start the clock interrupt cycle */
226 	clockintr_cpu_init(&gptimer_intrclock);
227 	clockintr_trigger();
228 }
229 
230 void
gptimer_wait(int reg)231 gptimer_wait(int reg)
232 {
233 	while (bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TWPS) & reg)
234 		;
235 }
236 
237 /*
238  * Clear all interrupt status bits.
239  */
240 void
gptimer_reset_tisr(void)241 gptimer_reset_tisr(void)
242 {
243 	u_int32_t tisr;
244 
245 	tisr = bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TISR);
246 	bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TISR, tisr);
247 }
248 
249 void
gptimer_rearm(void * unused,uint64_t nsecs)250 gptimer_rearm(void *unused, uint64_t nsecs)
251 {
252 	uint32_t cycles;
253 	u_long s;
254 
255 	if (nsecs > gptimer_nsec_max)
256 		nsecs = gptimer_nsec_max;
257 	cycles = (nsecs * gptimer_nsec_cycle_ratio) >> 32;
258 
259 	s = intr_disable();
260 	gptimer_reset_tisr();
261         bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCRR,
262 	    UINT32_MAX - cycles);
263 	bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR, GP_TCLR_ST);
264 	gptimer_wait(GP_TWPS_ALL);
265 	intr_restore(s);
266 }
267 
268 void
gptimer_trigger(void * unused)269 gptimer_trigger(void *unused)
270 {
271 	u_long s;
272 
273 	s = intr_disable();
274 
275 	/* stop timer. */
276 	bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR, 0);
277 	gptimer_wait(GP_TWPS_ALL);
278 
279 	/* clear interrupt status bits. */
280 	gptimer_reset_tisr();
281 
282 	/* set shortest possible timeout. */
283 	bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCRR, UINT32_MAX);
284 
285 	/* start timer, wait for writes to post. */
286 	bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR, GP_TCLR_ST);
287 	gptimer_wait(GP_TWPS_ALL);
288 
289 	intr_restore(s);
290 }
291 
292 void
gptimer_delay(u_int usecs)293 gptimer_delay(u_int usecs)
294 {
295 	u_int32_t clock, oclock, delta, delaycnt;
296 	volatile int j;
297 	int csec, usec;
298 
299 	if (usecs > (0x80000000 / (TIMER_FREQUENCY))) {
300 		csec = usecs / 10000;
301 		usec = usecs % 10000;
302 
303 		delaycnt = (TIMER_FREQUENCY / 100) * csec +
304 		    (TIMER_FREQUENCY / 100) * usec / 10000;
305 	} else {
306 		delaycnt = TIMER_FREQUENCY * usecs / 1000000;
307 	}
308 	if (delaycnt <= 1)
309 		for (j = 100; j > 0; j--)
310 			;
311 
312 	if (gptimer_ioh1 == 0) {
313 		/* BAH */
314 		for (; usecs > 0; usecs--)
315 			for (j = 100; j > 0; j--)
316 				;
317 		return;
318 	}
319 	oclock = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR);
320 	while (1) {
321 		for (j = 100; j > 0; j--)
322 			;
323 		clock = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR);
324 		delta = clock - oclock;
325 		if (delta > delaycnt)
326 			break;
327 	}
328 
329 }
330 
331 void
gptimer_setstatclockrate(int newhz)332 gptimer_setstatclockrate(int newhz)
333 {
334 }
335 
336 
337 u_int
gptimer_get_timecount(struct timecounter * tc)338 gptimer_get_timecount(struct timecounter *tc)
339 {
340 	return bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR);
341 }
342