xref: /minix3/minix/kernel/arch/earm/bsp/ti/omap_timer.c (revision b5e2faaaaf60a8b9a02f8d72f64caa56a87eb312)
1 #include "kernel/kernel.h"
2 #include "kernel/clock.h"
3 #include <sys/types.h>
4 #include <machine/cpu.h>
5 #include <minix/board.h>
6 #include <minix/mmio.h>
7 #include <assert.h>
8 #include <io.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include "arch_proto.h"
12 #include "bsp_timer.h"
13 #include "omap_timer_registers.h"
14 #include "omap_intr_registers.h"
15 #include "bsp_intr.h"
16 
17 /* interrupt handler hook */
18 static irq_hook_t omap3_timer_hook;
19 static u64_t high_frc;
20 
21 struct omap_timer_registers;
22 
23 struct omap_timer
24 {
25 	vir_bytes base;
26 	int irq_nr;
27 	struct omap_timer_registers *regs;
28 };
29 
30 struct omap_timer_registers
31 {
32 	vir_bytes TIDR;
33 	vir_bytes TIOCP_CFG;
34 	vir_bytes TISTAT;
35 	vir_bytes TISR;
36 	vir_bytes TIER;
37 	vir_bytes TWER;
38 	vir_bytes TCLR;
39 	vir_bytes TCRR;
40 	vir_bytes TLDR;
41 	vir_bytes TTGR;
42 	vir_bytes TWPS;
43 	vir_bytes TMAR;
44 	vir_bytes TCAR1;
45 	vir_bytes TSICR;
46 	vir_bytes TCAR2;
47 	vir_bytes TPIR;
48 	vir_bytes TNIR;
49 	vir_bytes TCVR;
50 	vir_bytes TOCR;
51 	vir_bytes TOWR;
52 
53 };
54 
55 static struct omap_timer_registers regs_v1 = {
56 	.TIDR = OMAP3_TIMER_TIDR,
57 	.TIOCP_CFG = OMAP3_TIMER_TIOCP_CFG,
58 	.TISTAT = OMAP3_TIMER_TISTAT,
59 	.TISR = OMAP3_TIMER_TISR,
60 	.TIER = OMAP3_TIMER_TIER,
61 	.TWER = OMAP3_TIMER_TWER,
62 	.TCLR = OMAP3_TIMER_TCLR,
63 	.TCRR = OMAP3_TIMER_TCRR,
64 	.TLDR = OMAP3_TIMER_TLDR,
65 	.TTGR = OMAP3_TIMER_TTGR,
66 	.TWPS = OMAP3_TIMER_TWPS,
67 	.TMAR = OMAP3_TIMER_TMAR,
68 	.TCAR1 = OMAP3_TIMER_TCAR1,
69 	.TSICR = OMAP3_TIMER_TSICR,
70 	.TCAR2 = OMAP3_TIMER_TCAR2,
71 	.TPIR = OMAP3_TIMER_TPIR,
72 	.TNIR = OMAP3_TIMER_TNIR,
73 	.TCVR = OMAP3_TIMER_TCVR,
74 	.TOCR = OMAP3_TIMER_TOCR,
75 	.TOWR = OMAP3_TIMER_TOWR,
76 };
77 
78 /* AM335X has a different ip block for the non
79  1ms timers */
80 static struct omap_timer_registers regs_v2 = {
81 	.TIDR = AM335X_TIMER_TIDR,
82 	.TIOCP_CFG = AM335X_TIMER_TIOCP_CFG,
83 	.TISTAT = AM335X_TIMER_IRQSTATUS_RAW,
84 	.TISR = AM335X_TIMER_IRQSTATUS,
85 	.TIER = AM335X_TIMER_IRQENABLE_SET,
86 	.TWER = AM335X_TIMER_IRQWAKEEN,
87 	.TCLR = AM335X_TIMER_TCLR,
88 	.TCRR = AM335X_TIMER_TCRR,
89 	.TLDR = AM335X_TIMER_TLDR,
90 	.TTGR = AM335X_TIMER_TTGR,
91 	.TWPS = AM335X_TIMER_TWPS,
92 	.TMAR = AM335X_TIMER_TMAR,
93 	.TCAR1 = AM335X_TIMER_TCAR1,
94 	.TSICR = AM335X_TIMER_TSICR,
95 	.TCAR2 = AM335X_TIMER_TCAR2,
96 	.TPIR = -1,		/* UNDEF */
97 	.TNIR = -1,		/* UNDEF */
98 	.TCVR = -1,		/* UNDEF */
99 	.TOCR = -1,		/* UNDEF */
100 	.TOWR = -1		/* UNDEF */
101 };
102 
103 static struct omap_timer dm37xx_timer = {
104 	.base = OMAP3_GPTIMER1_BASE,
105 	.irq_nr = OMAP3_GPT1_IRQ,
106 	.regs = &regs_v1
107 };
108 
109 /* free running timer */
110 static struct omap_timer dm37xx_fr_timer = {
111 	.base = OMAP3_GPTIMER10_BASE,
112 	.irq_nr = OMAP3_GPT10_IRQ,
113 	.regs = &regs_v1
114 };
115 
116 /* normal timer */
117 static struct omap_timer am335x_timer = {
118 	.base = AM335X_DMTIMER1_1MS_BASE,
119 	.irq_nr = AM335X_INT_TINT1_1MS,
120 	.regs = &regs_v1
121 };
122 
123 /* free running timer */
124 static struct omap_timer am335x_fr_timer = {
125 	.base = AM335X_DMTIMER7_BASE,
126 	.irq_nr = AM335X_INT_TINT7,
127 	.regs = &regs_v2
128 };
129 
130 static struct omap_timer *timer;
131 static struct omap_timer *fr_timer;
132 
133 static int done = 0;
134 
135 int
136 bsp_register_timer_handler(const irq_handler_t handler)
137 {
138 	/* Initialize the CLOCK's interrupt hook. */
139 	omap3_timer_hook.proc_nr_e = NONE;
140 	omap3_timer_hook.irq = timer->irq_nr;
141 
142 	put_irq_handler(&omap3_timer_hook, timer->irq_nr, handler);
143 	/* only unmask interrupts after registering */
144 	bsp_irq_unmask(timer->irq_nr);
145 
146 	return 0;
147 }
148 
149 /* meta data for remapping */
150 static kern_phys_map timer_phys_map;
151 static kern_phys_map fr_timer_phys_map;
152 static kern_phys_map fr_timer_user_phys_map;	/* struct for when the free */
153 						/* running timer is mapped to */
154 						/* userland */
155 
156 /* callback for when the free running clock gets mapped */
157 int
158 kern_phys_fr_user_mapped(vir_bytes id, phys_bytes address)
159 {
160 	/* the only thing we need to do at this stage is to set the address */
161 	/* in the kerninfo struct */
162 	if (BOARD_IS_BBXM(machine.board_id)) {
163 		minix_kerninfo.minix_frclock_tcrr = address + OMAP3_TIMER_TCRR;
164 		minix_kerninfo.minix_arm_frclock_hz = 1625000;
165 	} else if (BOARD_IS_BB(machine.board_id)) {
166 		minix_kerninfo.minix_frclock_tcrr =
167 		    address + AM335X_TIMER_TCRR;
168 		minix_kerninfo.minix_arm_frclock_hz = 1500000;
169 	}
170 	return 0;
171 }
172 
173 void
174 omap3_frclock_init(void)
175 {
176 	u32_t tisr;
177 
178 	/* enable the clock */
179 	if (BOARD_IS_BBXM(machine.board_id)) {
180 		fr_timer = &dm37xx_fr_timer;
181 
182 		kern_phys_map_ptr(fr_timer->base, ARM_PAGE_SIZE,
183 		    VMMF_UNCACHED | VMMF_WRITE, &fr_timer_phys_map,
184 		    (vir_bytes) & fr_timer->base);
185 
186 		/* the timer is also mapped in user space hence the this */
187 		/* second mapping and callback to set kerninfo frclock_tcrr */
188 		kern_req_phys_map(fr_timer->base, ARM_PAGE_SIZE,
189 		    VMMF_UNCACHED | VMMF_USER,
190 		    &fr_timer_user_phys_map, kern_phys_fr_user_mapped, 0);
191 
192 		/* Stop timer */
193 		mmio_clear(fr_timer->base + fr_timer->regs->TCLR,
194 		    OMAP3_TCLR_ST);
195 
196 		/* Use functional clock source for GPTIMER10 */
197 		mmio_set(OMAP3_CM_CLKSEL_CORE, OMAP3_CLKSEL_GPT10);
198 
199 		/* Scale timer down to 13/8 = 1.625 Mhz to roughly get
200 		 * microsecond ticks */
201 		/* The scale is computed as 2^(PTV+1). So if PTV == 2, we get
202 		 * 2^3 = 8. */
203 		mmio_set(fr_timer->base + fr_timer->regs->TCLR,
204 		    (2 << OMAP3_TCLR_PTV));
205 	} else if (BOARD_IS_BB(machine.board_id)) {
206 		fr_timer = &am335x_fr_timer;
207 		kern_phys_map_ptr(fr_timer->base, ARM_PAGE_SIZE,
208 		    VMMF_UNCACHED | VMMF_WRITE,
209 		    &fr_timer_phys_map, (vir_bytes) & fr_timer->base);
210 
211 		/* the timer is also mapped in user space hence the this */
212 		/* second mapping and callback to set kerninfo frclock_tcrr */
213 		kern_req_phys_map(fr_timer->base, ARM_PAGE_SIZE,
214 		    VMMF_UNCACHED | VMMF_USER,
215 		    &fr_timer_user_phys_map, kern_phys_fr_user_mapped, 0);
216 		/* Disable the module and wait for the module to be disabled */
217 		set32(CM_PER_TIMER7_CLKCTRL, CM_MODULEMODE_MASK,
218 		    CM_MODULEMODE_DISABLED);
219 		while ((mmio_read(CM_PER_TIMER7_CLKCTRL) & CM_CLKCTRL_IDLEST)
220 		    != CM_CLKCTRL_IDLEST_DISABLE);
221 
222 		set32(CLKSEL_TIMER7_CLK, CLKSEL_TIMER7_CLK_SEL_MASK,
223 		    CLKSEL_TIMER7_CLK_SEL_SEL2);
224 		while ((read32(CLKSEL_TIMER7_CLK) & CLKSEL_TIMER7_CLK_SEL_MASK)
225 		    != CLKSEL_TIMER7_CLK_SEL_SEL2);
226 
227 		/* enable the module and wait for the module to be ready */
228 		set32(CM_PER_TIMER7_CLKCTRL, CM_MODULEMODE_MASK,
229 		    CM_MODULEMODE_ENABLE);
230 		while ((mmio_read(CM_PER_TIMER7_CLKCTRL) & CM_CLKCTRL_IDLEST)
231 		    != CM_CLKCTRL_IDLEST_FUNC);
232 
233 		/* Stop timer */
234 		mmio_clear(fr_timer->base + fr_timer->regs->TCLR,
235 		    OMAP3_TCLR_ST);
236 
237 		/* 24Mhz / 16 = 1.5 Mhz */
238 		mmio_set(fr_timer->base + fr_timer->regs->TCLR,
239 		    (3 << OMAP3_TCLR_PTV));
240 	}
241 
242 	/* Start and auto-reload at 0 */
243 	mmio_write(fr_timer->base + fr_timer->regs->TLDR, 0x0);
244 	mmio_write(fr_timer->base + fr_timer->regs->TCRR, 0x0);
245 
246 	/* Set up overflow interrupt */
247 	tisr = OMAP3_TISR_MAT_IT_FLAG | OMAP3_TISR_OVF_IT_FLAG |
248 	    OMAP3_TISR_TCAR_IT_FLAG;
249 	/* Clear interrupt status */
250 	mmio_write(fr_timer->base + fr_timer->regs->TISR, tisr);
251 	mmio_write(fr_timer->base + fr_timer->regs->TIER,
252 	    OMAP3_TIER_OVF_IT_ENA);
253 
254 	/* Start timer */
255 	mmio_set(fr_timer->base + fr_timer->regs->TCLR,
256 	    OMAP3_TCLR_OVF_TRG | OMAP3_TCLR_AR | OMAP3_TCLR_ST |
257 	    OMAP3_TCLR_PRE);
258 	done = 1;
259 }
260 
261 void
262 omap3_frclock_stop()
263 {
264 	mmio_clear(fr_timer->base + fr_timer->regs->TCLR, OMAP3_TCLR_ST);
265 }
266 
267 void
268 bsp_timer_init(unsigned freq)
269 {
270 	/* we only support 1ms resolution */
271 	u32_t tisr;
272 	if (BOARD_IS_BBXM(machine.board_id)) {
273 		timer = &dm37xx_timer;
274 		kern_phys_map_ptr(timer->base, ARM_PAGE_SIZE,
275 		    VMMF_UNCACHED | VMMF_WRITE,
276 		    &timer_phys_map, (vir_bytes) & timer->base);
277 		/* Stop timer */
278 		mmio_clear(timer->base + timer->regs->TCLR, OMAP3_TCLR_ST);
279 
280 		/* Use 32 KHz clock source for GPTIMER1 */
281 		mmio_clear(OMAP3_CM_CLKSEL_WKUP, OMAP3_CLKSEL_GPT1);
282 	} else if (BOARD_IS_BB(machine.board_id)) {
283 		timer = &am335x_timer;
284 		kern_phys_map_ptr(timer->base, ARM_PAGE_SIZE,
285 		    VMMF_UNCACHED | VMMF_WRITE,
286 		    &timer_phys_map, (vir_bytes) & timer->base);
287 		/* disable the module and wait for the module to be disabled */
288 		set32(CM_WKUP_TIMER1_CLKCTRL, CM_MODULEMODE_MASK,
289 		    CM_MODULEMODE_DISABLED);
290 		while ((mmio_read(CM_WKUP_TIMER1_CLKCTRL) & CM_CLKCTRL_IDLEST)
291 		    != CM_CLKCTRL_IDLEST_DISABLE);
292 
293 		set32(CLKSEL_TIMER1MS_CLK, CLKSEL_TIMER1MS_CLK_SEL_MASK,
294 		    CLKSEL_TIMER1MS_CLK_SEL_SEL2);
295 		while ((read32(CLKSEL_TIMER1MS_CLK) &
296 			CLKSEL_TIMER1MS_CLK_SEL_MASK) !=
297 		    CLKSEL_TIMER1MS_CLK_SEL_SEL2);
298 
299 		/* enable the module and wait for the module to be ready */
300 		set32(CM_WKUP_TIMER1_CLKCTRL, CM_MODULEMODE_MASK,
301 		    CM_MODULEMODE_ENABLE);
302 		while ((mmio_read(CM_WKUP_TIMER1_CLKCTRL) & CM_CLKCTRL_IDLEST)
303 		    != CM_CLKCTRL_IDLEST_FUNC);
304 
305 		/* Stop timer */
306 		mmio_clear(timer->base + timer->regs->TCLR, OMAP3_TCLR_ST);
307 	}
308 
309 	/* Use 1-ms tick mode for GPTIMER1 TRM 16.2.4.2.1 */
310 	mmio_write(timer->base + timer->regs->TPIR, 232000);
311 	mmio_write(timer->base + timer->regs->TNIR, -768000);
312 	mmio_write(timer->base + timer->regs->TLDR,
313 	    0xffffffff - (32768 / freq) + 1);
314 	mmio_write(timer->base + timer->regs->TCRR,
315 	    0xffffffff - (32768 / freq) + 1);
316 
317 	/* Set up overflow interrupt */
318 	tisr = OMAP3_TISR_MAT_IT_FLAG | OMAP3_TISR_OVF_IT_FLAG |
319 	    OMAP3_TISR_TCAR_IT_FLAG;
320 	/* Clear interrupt status */
321 	mmio_write(timer->base + timer->regs->TISR, tisr);
322 	mmio_write(timer->base + timer->regs->TIER, OMAP3_TIER_OVF_IT_ENA);
323 
324 	/* Start timer */
325 	mmio_set(timer->base + timer->regs->TCLR,
326 	    OMAP3_TCLR_OVF_TRG | OMAP3_TCLR_AR | OMAP3_TCLR_ST);
327 	/* also initilize the free runnning timer */
328 	omap3_frclock_init();
329 }
330 
331 void
332 bsp_timer_stop()
333 {
334 	mmio_clear(timer->base + timer->regs->TCLR, OMAP3_TCLR_ST);
335 }
336 
337 static u32_t
338 read_frc(void)
339 {
340 	if (done == 0) {
341 		return 0;
342 	}
343 	return mmio_read(fr_timer->base + fr_timer->regs->TCRR);
344 }
345 
346 /*
347  * Check if the free running clock has overflown and
348  * increase the high free running clock counter if
349  * so. This method takes the current timer value as
350  * parameter to ensure the overflow check is done
351  * on the current timer value.
352  *
353  * To compose the current timer value (64 bits) you
354  * need to follow the following sequence:
355  *  read the current timer value.
356  *  call the overflow check
357  *  compose the 64 bits time based on the current timer value
358  *   and high_frc.
359  */
360 static void
361 frc_overflow_check(u32_t cur_frc)
362 {
363 	static int prev_frc_valid;
364 	static u32_t prev_frc;
365 	if (prev_frc_valid && prev_frc > cur_frc) {
366 		high_frc++;
367 	}
368 	prev_frc = cur_frc;
369 	prev_frc_valid = 1;
370 }
371 
372 void
373 bsp_timer_int_handler()
374 {
375 	/* Clear all interrupts */
376 	u32_t tisr, now;
377 
378 	/* when the kernel itself is running interrupts are disabled. We
379 	 * should therefore also read the overflow counter to detect this as
380 	 * to not miss events. */
381 	tisr = OMAP3_TISR_MAT_IT_FLAG | OMAP3_TISR_OVF_IT_FLAG |
382 	    OMAP3_TISR_TCAR_IT_FLAG;
383 	mmio_write(timer->base + timer->regs->TISR, tisr);
384 
385 	now = read_frc();
386 	frc_overflow_check(now);
387 }
388 
389 /* Use the free running clock as TSC */
390 void
391 read_tsc_64(u64_t * t)
392 {
393 	u32_t now;
394 	now = read_frc();
395 	frc_overflow_check(now);
396 	*t = (u64_t) now + (high_frc << 32);
397 }
398