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