xref: /minix3/minix/kernel/arch/earm/bsp/ti/omap_timer.c (revision 6077d1ad241af1cd2881b708610d6ceb54ed9612)
1433d6423SLionel Sambuc #include "kernel/kernel.h"
2433d6423SLionel Sambuc #include "kernel/clock.h"
3433d6423SLionel Sambuc #include <sys/types.h>
4433d6423SLionel Sambuc #include <machine/cpu.h>
5433d6423SLionel Sambuc #include <minix/board.h>
6433d6423SLionel Sambuc #include <minix/mmio.h>
7433d6423SLionel Sambuc #include <assert.h>
8433d6423SLionel Sambuc #include <io.h>
9433d6423SLionel Sambuc #include <stdlib.h>
10433d6423SLionel Sambuc #include <stdio.h>
11433d6423SLionel Sambuc #include "arch_proto.h"
12433d6423SLionel Sambuc #include "bsp_timer.h"
13433d6423SLionel Sambuc #include "omap_timer_registers.h"
14433d6423SLionel Sambuc #include "omap_intr_registers.h"
15433d6423SLionel Sambuc #include "bsp_intr.h"
16433d6423SLionel Sambuc 
17433d6423SLionel Sambuc /* interrupt handler hook */
18433d6423SLionel Sambuc static irq_hook_t omap3_timer_hook;
19433d6423SLionel Sambuc static u64_t high_frc;
20433d6423SLionel Sambuc 
21433d6423SLionel Sambuc struct omap_timer_registers;
22433d6423SLionel Sambuc 
23433d6423SLionel Sambuc struct omap_timer
24433d6423SLionel Sambuc {
25433d6423SLionel Sambuc 	vir_bytes base;
26433d6423SLionel Sambuc 	int irq_nr;
27433d6423SLionel Sambuc 	struct omap_timer_registers *regs;
28433d6423SLionel Sambuc };
29433d6423SLionel Sambuc 
30433d6423SLionel Sambuc struct omap_timer_registers
31433d6423SLionel Sambuc {
32433d6423SLionel Sambuc 	vir_bytes TIDR;
33433d6423SLionel Sambuc 	vir_bytes TIOCP_CFG;
34433d6423SLionel Sambuc 	vir_bytes TISTAT;
35433d6423SLionel Sambuc 	vir_bytes TISR;
36433d6423SLionel Sambuc 	vir_bytes TIER;
37433d6423SLionel Sambuc 	vir_bytes TWER;
38433d6423SLionel Sambuc 	vir_bytes TCLR;
39433d6423SLionel Sambuc 	vir_bytes TCRR;
40433d6423SLionel Sambuc 	vir_bytes TLDR;
41433d6423SLionel Sambuc 	vir_bytes TTGR;
42433d6423SLionel Sambuc 	vir_bytes TWPS;
43433d6423SLionel Sambuc 	vir_bytes TMAR;
44433d6423SLionel Sambuc 	vir_bytes TCAR1;
45433d6423SLionel Sambuc 	vir_bytes TSICR;
46433d6423SLionel Sambuc 	vir_bytes TCAR2;
47433d6423SLionel Sambuc 	vir_bytes TPIR;
48433d6423SLionel Sambuc 	vir_bytes TNIR;
49433d6423SLionel Sambuc 	vir_bytes TCVR;
50433d6423SLionel Sambuc 	vir_bytes TOCR;
51433d6423SLionel Sambuc 	vir_bytes TOWR;
52433d6423SLionel Sambuc 
53433d6423SLionel Sambuc };
54433d6423SLionel Sambuc 
55433d6423SLionel Sambuc static struct omap_timer_registers regs_v1 = {
56433d6423SLionel Sambuc 	.TIDR = OMAP3_TIMER_TIDR,
57433d6423SLionel Sambuc 	.TIOCP_CFG = OMAP3_TIMER_TIOCP_CFG,
58433d6423SLionel Sambuc 	.TISTAT = OMAP3_TIMER_TISTAT,
59433d6423SLionel Sambuc 	.TISR = OMAP3_TIMER_TISR,
60433d6423SLionel Sambuc 	.TIER = OMAP3_TIMER_TIER,
61433d6423SLionel Sambuc 	.TWER = OMAP3_TIMER_TWER,
62433d6423SLionel Sambuc 	.TCLR = OMAP3_TIMER_TCLR,
63433d6423SLionel Sambuc 	.TCRR = OMAP3_TIMER_TCRR,
64433d6423SLionel Sambuc 	.TLDR = OMAP3_TIMER_TLDR,
65433d6423SLionel Sambuc 	.TTGR = OMAP3_TIMER_TTGR,
66433d6423SLionel Sambuc 	.TWPS = OMAP3_TIMER_TWPS,
67433d6423SLionel Sambuc 	.TMAR = OMAP3_TIMER_TMAR,
68433d6423SLionel Sambuc 	.TCAR1 = OMAP3_TIMER_TCAR1,
69433d6423SLionel Sambuc 	.TSICR = OMAP3_TIMER_TSICR,
70433d6423SLionel Sambuc 	.TCAR2 = OMAP3_TIMER_TCAR2,
71433d6423SLionel Sambuc 	.TPIR = OMAP3_TIMER_TPIR,
72433d6423SLionel Sambuc 	.TNIR = OMAP3_TIMER_TNIR,
73433d6423SLionel Sambuc 	.TCVR = OMAP3_TIMER_TCVR,
74433d6423SLionel Sambuc 	.TOCR = OMAP3_TIMER_TOCR,
75433d6423SLionel Sambuc 	.TOWR = OMAP3_TIMER_TOWR,
76433d6423SLionel Sambuc };
77433d6423SLionel Sambuc 
78433d6423SLionel Sambuc /* AM335X has a different ip block for the non
79433d6423SLionel Sambuc  1ms timers */
80433d6423SLionel Sambuc static struct omap_timer_registers regs_v2 = {
81433d6423SLionel Sambuc 	.TIDR = AM335X_TIMER_TIDR,
82433d6423SLionel Sambuc 	.TIOCP_CFG = AM335X_TIMER_TIOCP_CFG,
83433d6423SLionel Sambuc 	.TISTAT = AM335X_TIMER_IRQSTATUS_RAW,
84433d6423SLionel Sambuc 	.TISR = AM335X_TIMER_IRQSTATUS,
85433d6423SLionel Sambuc 	.TIER = AM335X_TIMER_IRQENABLE_SET,
86433d6423SLionel Sambuc 	.TWER = AM335X_TIMER_IRQWAKEEN,
87433d6423SLionel Sambuc 	.TCLR = AM335X_TIMER_TCLR,
88433d6423SLionel Sambuc 	.TCRR = AM335X_TIMER_TCRR,
89433d6423SLionel Sambuc 	.TLDR = AM335X_TIMER_TLDR,
90433d6423SLionel Sambuc 	.TTGR = AM335X_TIMER_TTGR,
91433d6423SLionel Sambuc 	.TWPS = AM335X_TIMER_TWPS,
92433d6423SLionel Sambuc 	.TMAR = AM335X_TIMER_TMAR,
93433d6423SLionel Sambuc 	.TCAR1 = AM335X_TIMER_TCAR1,
94433d6423SLionel Sambuc 	.TSICR = AM335X_TIMER_TSICR,
95433d6423SLionel Sambuc 	.TCAR2 = AM335X_TIMER_TCAR2,
96433d6423SLionel Sambuc 	.TPIR = -1,		/* UNDEF */
97433d6423SLionel Sambuc 	.TNIR = -1,		/* UNDEF */
98433d6423SLionel Sambuc 	.TCVR = -1,		/* UNDEF */
99433d6423SLionel Sambuc 	.TOCR = -1,		/* UNDEF */
100433d6423SLionel Sambuc 	.TOWR = -1		/* UNDEF */
101433d6423SLionel Sambuc };
102433d6423SLionel Sambuc 
103433d6423SLionel Sambuc static struct omap_timer dm37xx_timer = {
104433d6423SLionel Sambuc 	.base = OMAP3_GPTIMER1_BASE,
105433d6423SLionel Sambuc 	.irq_nr = OMAP3_GPT1_IRQ,
106433d6423SLionel Sambuc 	.regs = &regs_v1
107433d6423SLionel Sambuc };
108433d6423SLionel Sambuc 
109433d6423SLionel Sambuc /* free running timer */
110433d6423SLionel Sambuc static struct omap_timer dm37xx_fr_timer = {
111433d6423SLionel Sambuc 	.base = OMAP3_GPTIMER10_BASE,
112433d6423SLionel Sambuc 	.irq_nr = OMAP3_GPT10_IRQ,
113433d6423SLionel Sambuc 	.regs = &regs_v1
114433d6423SLionel Sambuc };
115433d6423SLionel Sambuc 
116433d6423SLionel Sambuc /* normal timer */
117433d6423SLionel Sambuc static struct omap_timer am335x_timer = {
118433d6423SLionel Sambuc 	.base = AM335X_DMTIMER1_1MS_BASE,
119433d6423SLionel Sambuc 	.irq_nr = AM335X_INT_TINT1_1MS,
120433d6423SLionel Sambuc 	.regs = &regs_v1
121433d6423SLionel Sambuc };
122433d6423SLionel Sambuc 
123433d6423SLionel Sambuc /* free running timer */
124433d6423SLionel Sambuc static struct omap_timer am335x_fr_timer = {
125433d6423SLionel Sambuc 	.base = AM335X_DMTIMER7_BASE,
126433d6423SLionel Sambuc 	.irq_nr = AM335X_INT_TINT7,
127433d6423SLionel Sambuc 	.regs = &regs_v2
128433d6423SLionel Sambuc };
129433d6423SLionel Sambuc 
130433d6423SLionel Sambuc static struct omap_timer *timer;
131433d6423SLionel Sambuc static struct omap_timer *fr_timer;
132433d6423SLionel Sambuc 
133433d6423SLionel Sambuc static int done = 0;
134433d6423SLionel Sambuc 
135433d6423SLionel Sambuc int
bsp_register_timer_handler(const irq_handler_t handler)136433d6423SLionel Sambuc bsp_register_timer_handler(const irq_handler_t handler)
137433d6423SLionel Sambuc {
138433d6423SLionel Sambuc 	/* Initialize the CLOCK's interrupt hook. */
139433d6423SLionel Sambuc 	omap3_timer_hook.proc_nr_e = NONE;
140433d6423SLionel Sambuc 	omap3_timer_hook.irq = timer->irq_nr;
141433d6423SLionel Sambuc 
142433d6423SLionel Sambuc 	put_irq_handler(&omap3_timer_hook, timer->irq_nr, handler);
143433d6423SLionel Sambuc 	/* only unmask interrupts after registering */
144433d6423SLionel Sambuc 	bsp_irq_unmask(timer->irq_nr);
145433d6423SLionel Sambuc 
146433d6423SLionel Sambuc 	return 0;
147433d6423SLionel Sambuc }
148433d6423SLionel Sambuc 
149433d6423SLionel Sambuc /* meta data for remapping */
150433d6423SLionel Sambuc static kern_phys_map timer_phys_map;
151433d6423SLionel Sambuc static kern_phys_map fr_timer_phys_map;
152433d6423SLionel Sambuc static kern_phys_map fr_timer_user_phys_map;	/* struct for when the free */
153433d6423SLionel Sambuc 						/* running timer is mapped to */
154433d6423SLionel Sambuc 						/* userland */
155433d6423SLionel Sambuc 
156433d6423SLionel Sambuc /* callback for when the free running clock gets mapped */
157433d6423SLionel Sambuc int
kern_phys_fr_user_mapped(vir_bytes id,phys_bytes address)158433d6423SLionel Sambuc kern_phys_fr_user_mapped(vir_bytes id, phys_bytes address)
159433d6423SLionel Sambuc {
160433d6423SLionel Sambuc 	/* the only thing we need to do at this stage is to set the address */
161433d6423SLionel Sambuc 	/* in the kerninfo struct */
162433d6423SLionel Sambuc 	if (BOARD_IS_BBXM(machine.board_id)) {
16326f5c8f8SDavid van Moolenbroek 		arm_frclock.tcrr = address + OMAP3_TIMER_TCRR;
16426f5c8f8SDavid van Moolenbroek 		arm_frclock.hz = 1625000;
165433d6423SLionel Sambuc 	} else if (BOARD_IS_BB(machine.board_id)) {
16626f5c8f8SDavid van Moolenbroek 		arm_frclock.tcrr = address + AM335X_TIMER_TCRR;
16726f5c8f8SDavid van Moolenbroek 		arm_frclock.hz = 1500000;
168433d6423SLionel Sambuc 	}
169433d6423SLionel Sambuc 	return 0;
170433d6423SLionel Sambuc }
171433d6423SLionel Sambuc 
172433d6423SLionel Sambuc void
omap3_frclock_init(void)173433d6423SLionel Sambuc omap3_frclock_init(void)
174433d6423SLionel Sambuc {
175433d6423SLionel Sambuc 	u32_t tisr;
176433d6423SLionel Sambuc 
177433d6423SLionel Sambuc 	/* enable the clock */
178433d6423SLionel Sambuc 	if (BOARD_IS_BBXM(machine.board_id)) {
179433d6423SLionel Sambuc 		fr_timer = &dm37xx_fr_timer;
180433d6423SLionel Sambuc 
181433d6423SLionel Sambuc 		kern_phys_map_ptr(fr_timer->base, ARM_PAGE_SIZE,
182433d6423SLionel Sambuc 		    VMMF_UNCACHED | VMMF_WRITE, &fr_timer_phys_map,
183433d6423SLionel Sambuc 		    (vir_bytes) & fr_timer->base);
184433d6423SLionel Sambuc 
185433d6423SLionel Sambuc 		/* the timer is also mapped in user space hence the this */
186433d6423SLionel Sambuc 		/* second mapping and callback to set kerninfo frclock_tcrr */
187433d6423SLionel Sambuc 		kern_req_phys_map(fr_timer->base, ARM_PAGE_SIZE,
188433d6423SLionel Sambuc 		    VMMF_UNCACHED | VMMF_USER,
189433d6423SLionel Sambuc 		    &fr_timer_user_phys_map, kern_phys_fr_user_mapped, 0);
190433d6423SLionel Sambuc 
191433d6423SLionel Sambuc 		/* Stop timer */
192433d6423SLionel Sambuc 		mmio_clear(fr_timer->base + fr_timer->regs->TCLR,
193433d6423SLionel Sambuc 		    OMAP3_TCLR_ST);
194433d6423SLionel Sambuc 
195433d6423SLionel Sambuc 		/* Use functional clock source for GPTIMER10 */
196433d6423SLionel Sambuc 		mmio_set(OMAP3_CM_CLKSEL_CORE, OMAP3_CLKSEL_GPT10);
197433d6423SLionel Sambuc 
198433d6423SLionel Sambuc 		/* Scale timer down to 13/8 = 1.625 Mhz to roughly get
199433d6423SLionel Sambuc 		 * microsecond ticks */
200433d6423SLionel Sambuc 		/* The scale is computed as 2^(PTV+1). So if PTV == 2, we get
201433d6423SLionel Sambuc 		 * 2^3 = 8. */
202433d6423SLionel Sambuc 		mmio_set(fr_timer->base + fr_timer->regs->TCLR,
203433d6423SLionel Sambuc 		    (2 << OMAP3_TCLR_PTV));
204433d6423SLionel Sambuc 	} else if (BOARD_IS_BB(machine.board_id)) {
205433d6423SLionel Sambuc 		fr_timer = &am335x_fr_timer;
206433d6423SLionel Sambuc 		kern_phys_map_ptr(fr_timer->base, ARM_PAGE_SIZE,
207433d6423SLionel Sambuc 		    VMMF_UNCACHED | VMMF_WRITE,
208433d6423SLionel Sambuc 		    &fr_timer_phys_map, (vir_bytes) & fr_timer->base);
209433d6423SLionel Sambuc 
210433d6423SLionel Sambuc 		/* the timer is also mapped in user space hence the this */
211433d6423SLionel Sambuc 		/* second mapping and callback to set kerninfo frclock_tcrr */
212433d6423SLionel Sambuc 		kern_req_phys_map(fr_timer->base, ARM_PAGE_SIZE,
213433d6423SLionel Sambuc 		    VMMF_UNCACHED | VMMF_USER,
214433d6423SLionel Sambuc 		    &fr_timer_user_phys_map, kern_phys_fr_user_mapped, 0);
215433d6423SLionel Sambuc 		/* Disable the module and wait for the module to be disabled */
216433d6423SLionel Sambuc 		set32(CM_PER_TIMER7_CLKCTRL, CM_MODULEMODE_MASK,
217433d6423SLionel Sambuc 		    CM_MODULEMODE_DISABLED);
218433d6423SLionel Sambuc 		while ((mmio_read(CM_PER_TIMER7_CLKCTRL) & CM_CLKCTRL_IDLEST)
219433d6423SLionel Sambuc 		    != CM_CLKCTRL_IDLEST_DISABLE);
220433d6423SLionel Sambuc 
221433d6423SLionel Sambuc 		set32(CLKSEL_TIMER7_CLK, CLKSEL_TIMER7_CLK_SEL_MASK,
222433d6423SLionel Sambuc 		    CLKSEL_TIMER7_CLK_SEL_SEL2);
223433d6423SLionel Sambuc 		while ((read32(CLKSEL_TIMER7_CLK) & CLKSEL_TIMER7_CLK_SEL_MASK)
224433d6423SLionel Sambuc 		    != CLKSEL_TIMER7_CLK_SEL_SEL2);
225433d6423SLionel Sambuc 
226433d6423SLionel Sambuc 		/* enable the module and wait for the module to be ready */
227433d6423SLionel Sambuc 		set32(CM_PER_TIMER7_CLKCTRL, CM_MODULEMODE_MASK,
228433d6423SLionel Sambuc 		    CM_MODULEMODE_ENABLE);
229433d6423SLionel Sambuc 		while ((mmio_read(CM_PER_TIMER7_CLKCTRL) & CM_CLKCTRL_IDLEST)
230433d6423SLionel Sambuc 		    != CM_CLKCTRL_IDLEST_FUNC);
231433d6423SLionel Sambuc 
232433d6423SLionel Sambuc 		/* Stop timer */
233433d6423SLionel Sambuc 		mmio_clear(fr_timer->base + fr_timer->regs->TCLR,
234433d6423SLionel Sambuc 		    OMAP3_TCLR_ST);
235433d6423SLionel Sambuc 
236433d6423SLionel Sambuc 		/* 24Mhz / 16 = 1.5 Mhz */
237433d6423SLionel Sambuc 		mmio_set(fr_timer->base + fr_timer->regs->TCLR,
238433d6423SLionel Sambuc 		    (3 << OMAP3_TCLR_PTV));
239433d6423SLionel Sambuc 	}
240433d6423SLionel Sambuc 
241433d6423SLionel Sambuc 	/* Start and auto-reload at 0 */
242433d6423SLionel Sambuc 	mmio_write(fr_timer->base + fr_timer->regs->TLDR, 0x0);
243433d6423SLionel Sambuc 	mmio_write(fr_timer->base + fr_timer->regs->TCRR, 0x0);
244433d6423SLionel Sambuc 
245433d6423SLionel Sambuc 	/* Set up overflow interrupt */
246433d6423SLionel Sambuc 	tisr = OMAP3_TISR_MAT_IT_FLAG | OMAP3_TISR_OVF_IT_FLAG |
247433d6423SLionel Sambuc 	    OMAP3_TISR_TCAR_IT_FLAG;
248433d6423SLionel Sambuc 	/* Clear interrupt status */
249433d6423SLionel Sambuc 	mmio_write(fr_timer->base + fr_timer->regs->TISR, tisr);
250433d6423SLionel Sambuc 	mmio_write(fr_timer->base + fr_timer->regs->TIER,
251433d6423SLionel Sambuc 	    OMAP3_TIER_OVF_IT_ENA);
252433d6423SLionel Sambuc 
253433d6423SLionel Sambuc 	/* Start timer */
254433d6423SLionel Sambuc 	mmio_set(fr_timer->base + fr_timer->regs->TCLR,
255433d6423SLionel Sambuc 	    OMAP3_TCLR_OVF_TRG | OMAP3_TCLR_AR | OMAP3_TCLR_ST |
256433d6423SLionel Sambuc 	    OMAP3_TCLR_PRE);
257433d6423SLionel Sambuc 	done = 1;
258433d6423SLionel Sambuc }
259433d6423SLionel Sambuc 
260433d6423SLionel Sambuc void
omap3_frclock_stop(void)261*6077d1adSDr. Florian Grätz omap3_frclock_stop(void)
262433d6423SLionel Sambuc {
263433d6423SLionel Sambuc 	mmio_clear(fr_timer->base + fr_timer->regs->TCLR, OMAP3_TCLR_ST);
264433d6423SLionel Sambuc }
265433d6423SLionel Sambuc 
266433d6423SLionel Sambuc void
bsp_timer_init(unsigned freq)267433d6423SLionel Sambuc bsp_timer_init(unsigned freq)
268433d6423SLionel Sambuc {
269433d6423SLionel Sambuc 	/* we only support 1ms resolution */
270433d6423SLionel Sambuc 	u32_t tisr;
271433d6423SLionel Sambuc 	if (BOARD_IS_BBXM(machine.board_id)) {
272433d6423SLionel Sambuc 		timer = &dm37xx_timer;
273433d6423SLionel Sambuc 		kern_phys_map_ptr(timer->base, ARM_PAGE_SIZE,
274433d6423SLionel Sambuc 		    VMMF_UNCACHED | VMMF_WRITE,
275433d6423SLionel Sambuc 		    &timer_phys_map, (vir_bytes) & timer->base);
276433d6423SLionel Sambuc 		/* Stop timer */
277433d6423SLionel Sambuc 		mmio_clear(timer->base + timer->regs->TCLR, OMAP3_TCLR_ST);
278433d6423SLionel Sambuc 
279433d6423SLionel Sambuc 		/* Use 32 KHz clock source for GPTIMER1 */
280433d6423SLionel Sambuc 		mmio_clear(OMAP3_CM_CLKSEL_WKUP, OMAP3_CLKSEL_GPT1);
281433d6423SLionel Sambuc 	} else if (BOARD_IS_BB(machine.board_id)) {
282433d6423SLionel Sambuc 		timer = &am335x_timer;
283433d6423SLionel Sambuc 		kern_phys_map_ptr(timer->base, ARM_PAGE_SIZE,
284433d6423SLionel Sambuc 		    VMMF_UNCACHED | VMMF_WRITE,
285433d6423SLionel Sambuc 		    &timer_phys_map, (vir_bytes) & timer->base);
286433d6423SLionel Sambuc 		/* disable the module and wait for the module to be disabled */
287433d6423SLionel Sambuc 		set32(CM_WKUP_TIMER1_CLKCTRL, CM_MODULEMODE_MASK,
288433d6423SLionel Sambuc 		    CM_MODULEMODE_DISABLED);
289433d6423SLionel Sambuc 		while ((mmio_read(CM_WKUP_TIMER1_CLKCTRL) & CM_CLKCTRL_IDLEST)
290433d6423SLionel Sambuc 		    != CM_CLKCTRL_IDLEST_DISABLE);
291433d6423SLionel Sambuc 
292433d6423SLionel Sambuc 		set32(CLKSEL_TIMER1MS_CLK, CLKSEL_TIMER1MS_CLK_SEL_MASK,
293433d6423SLionel Sambuc 		    CLKSEL_TIMER1MS_CLK_SEL_SEL2);
294433d6423SLionel Sambuc 		while ((read32(CLKSEL_TIMER1MS_CLK) &
295433d6423SLionel Sambuc 			CLKSEL_TIMER1MS_CLK_SEL_MASK) !=
296433d6423SLionel Sambuc 		    CLKSEL_TIMER1MS_CLK_SEL_SEL2);
297433d6423SLionel Sambuc 
298433d6423SLionel Sambuc 		/* enable the module and wait for the module to be ready */
299433d6423SLionel Sambuc 		set32(CM_WKUP_TIMER1_CLKCTRL, CM_MODULEMODE_MASK,
300433d6423SLionel Sambuc 		    CM_MODULEMODE_ENABLE);
301433d6423SLionel Sambuc 		while ((mmio_read(CM_WKUP_TIMER1_CLKCTRL) & CM_CLKCTRL_IDLEST)
302433d6423SLionel Sambuc 		    != CM_CLKCTRL_IDLEST_FUNC);
303433d6423SLionel Sambuc 
304433d6423SLionel Sambuc 		/* Stop timer */
305433d6423SLionel Sambuc 		mmio_clear(timer->base + timer->regs->TCLR, OMAP3_TCLR_ST);
306433d6423SLionel Sambuc 	}
307433d6423SLionel Sambuc 
308433d6423SLionel Sambuc 	/* Use 1-ms tick mode for GPTIMER1 TRM 16.2.4.2.1 */
309433d6423SLionel Sambuc 	mmio_write(timer->base + timer->regs->TPIR, 232000);
310433d6423SLionel Sambuc 	mmio_write(timer->base + timer->regs->TNIR, -768000);
311433d6423SLionel Sambuc 	mmio_write(timer->base + timer->regs->TLDR,
312433d6423SLionel Sambuc 	    0xffffffff - (32768 / freq) + 1);
313433d6423SLionel Sambuc 	mmio_write(timer->base + timer->regs->TCRR,
314433d6423SLionel Sambuc 	    0xffffffff - (32768 / freq) + 1);
315433d6423SLionel Sambuc 
316433d6423SLionel Sambuc 	/* Set up overflow interrupt */
317433d6423SLionel Sambuc 	tisr = OMAP3_TISR_MAT_IT_FLAG | OMAP3_TISR_OVF_IT_FLAG |
318433d6423SLionel Sambuc 	    OMAP3_TISR_TCAR_IT_FLAG;
319433d6423SLionel Sambuc 	/* Clear interrupt status */
320433d6423SLionel Sambuc 	mmio_write(timer->base + timer->regs->TISR, tisr);
321433d6423SLionel Sambuc 	mmio_write(timer->base + timer->regs->TIER, OMAP3_TIER_OVF_IT_ENA);
322433d6423SLionel Sambuc 
323433d6423SLionel Sambuc 	/* Start timer */
324433d6423SLionel Sambuc 	mmio_set(timer->base + timer->regs->TCLR,
325433d6423SLionel Sambuc 	    OMAP3_TCLR_OVF_TRG | OMAP3_TCLR_AR | OMAP3_TCLR_ST);
326433d6423SLionel Sambuc 	/* also initilize the free runnning timer */
327433d6423SLionel Sambuc 	omap3_frclock_init();
328433d6423SLionel Sambuc }
329433d6423SLionel Sambuc 
330433d6423SLionel Sambuc void
bsp_timer_stop(void)331*6077d1adSDr. Florian Grätz bsp_timer_stop(void)
332433d6423SLionel Sambuc {
333433d6423SLionel Sambuc 	mmio_clear(timer->base + timer->regs->TCLR, OMAP3_TCLR_ST);
334433d6423SLionel Sambuc }
335433d6423SLionel Sambuc 
336433d6423SLionel Sambuc static u32_t
read_frc(void)337433d6423SLionel Sambuc read_frc(void)
338433d6423SLionel Sambuc {
339433d6423SLionel Sambuc 	if (done == 0) {
340433d6423SLionel Sambuc 		return 0;
341433d6423SLionel Sambuc 	}
342433d6423SLionel Sambuc 	return mmio_read(fr_timer->base + fr_timer->regs->TCRR);
343433d6423SLionel Sambuc }
344433d6423SLionel Sambuc 
345433d6423SLionel Sambuc /*
346433d6423SLionel Sambuc  * Check if the free running clock has overflown and
347433d6423SLionel Sambuc  * increase the high free running clock counter if
348433d6423SLionel Sambuc  * so. This method takes the current timer value as
349433d6423SLionel Sambuc  * parameter to ensure the overflow check is done
350433d6423SLionel Sambuc  * on the current timer value.
351433d6423SLionel Sambuc  *
352433d6423SLionel Sambuc  * To compose the current timer value (64 bits) you
353433d6423SLionel Sambuc  * need to follow the following sequence:
354433d6423SLionel Sambuc  *  read the current timer value.
355433d6423SLionel Sambuc  *  call the overflow check
356433d6423SLionel Sambuc  *  compose the 64 bits time based on the current timer value
357433d6423SLionel Sambuc  *   and high_frc.
358433d6423SLionel Sambuc  */
359433d6423SLionel Sambuc static void
frc_overflow_check(u32_t cur_frc)360433d6423SLionel Sambuc frc_overflow_check(u32_t cur_frc)
361433d6423SLionel Sambuc {
362433d6423SLionel Sambuc 	static int prev_frc_valid;
363433d6423SLionel Sambuc 	static u32_t prev_frc;
364433d6423SLionel Sambuc 	if (prev_frc_valid && prev_frc > cur_frc) {
365433d6423SLionel Sambuc 		high_frc++;
366433d6423SLionel Sambuc 	}
367433d6423SLionel Sambuc 	prev_frc = cur_frc;
368433d6423SLionel Sambuc 	prev_frc_valid = 1;
369433d6423SLionel Sambuc }
370433d6423SLionel Sambuc 
371433d6423SLionel Sambuc void
bsp_timer_int_handler(void)372*6077d1adSDr. Florian Grätz bsp_timer_int_handler(void)
373433d6423SLionel Sambuc {
374433d6423SLionel Sambuc 	/* Clear all interrupts */
375433d6423SLionel Sambuc 	u32_t tisr, now;
376433d6423SLionel Sambuc 
377433d6423SLionel Sambuc 	/* when the kernel itself is running interrupts are disabled. We
378433d6423SLionel Sambuc 	 * should therefore also read the overflow counter to detect this as
379433d6423SLionel Sambuc 	 * to not miss events. */
380433d6423SLionel Sambuc 	tisr = OMAP3_TISR_MAT_IT_FLAG | OMAP3_TISR_OVF_IT_FLAG |
381433d6423SLionel Sambuc 	    OMAP3_TISR_TCAR_IT_FLAG;
382433d6423SLionel Sambuc 	mmio_write(timer->base + timer->regs->TISR, tisr);
383433d6423SLionel Sambuc 
384433d6423SLionel Sambuc 	now = read_frc();
385433d6423SLionel Sambuc 	frc_overflow_check(now);
386433d6423SLionel Sambuc }
387433d6423SLionel Sambuc 
388433d6423SLionel Sambuc /* Use the free running clock as TSC */
389433d6423SLionel Sambuc void
read_tsc_64(u64_t * t)390433d6423SLionel Sambuc read_tsc_64(u64_t * t)
391433d6423SLionel Sambuc {
392433d6423SLionel Sambuc 	u32_t now;
393433d6423SLionel Sambuc 	now = read_frc();
394433d6423SLionel Sambuc 	frc_overflow_check(now);
395433d6423SLionel Sambuc 	*t = (u64_t) now + (high_frc << 32);
396433d6423SLionel Sambuc }
397