1 #include "kernel/kernel.h"
2 #include "kernel/clock.h"
4 #include <machine/cpu.h>
5 #include <minix/board.h>
6 #include <minix/mmio.h>
11 #include "arch_proto.h"
12 #include "bsp_timer.h"
13 #include "omap_timer_registers.h"
14 #include "omap_intr_registers.h"
17 /* interrupt handler hook */
18 static irq_hook_t omap3_timer_hook
;
19 static u64_t high_frc
;
21 struct omap_timer_registers
;
27 struct omap_timer_registers
*regs
;
30 struct omap_timer_registers
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
,
78 /* AM335X has a different ip block for the non
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 */
103 static struct omap_timer dm37xx_timer
= {
104 .base
= OMAP3_GPTIMER1_BASE
,
105 .irq_nr
= OMAP3_GPT1_IRQ
,
109 /* free running timer */
110 static struct omap_timer dm37xx_fr_timer
= {
111 .base
= OMAP3_GPTIMER10_BASE
,
112 .irq_nr
= OMAP3_GPT10_IRQ
,
117 static struct omap_timer am335x_timer
= {
118 .base
= AM335X_DMTIMER1_1MS_BASE
,
119 .irq_nr
= AM335X_INT_TINT1_1MS
,
123 /* free running timer */
124 static struct omap_timer am335x_fr_timer
= {
125 .base
= AM335X_DMTIMER7_BASE
,
126 .irq_nr
= AM335X_INT_TINT7
,
130 static struct omap_timer
*timer
;
131 static struct omap_timer
*fr_timer
;
136 bsp_register_timer_handler(const irq_handler_t handler
)
138 /* Initialize the CLOCK's interrupt hook. */
139 omap3_timer_hook
.proc_nr_e
= NONE
;
140 omap3_timer_hook
.irq
= timer
->irq_nr
;
142 put_irq_handler(&omap3_timer_hook
, timer
->irq_nr
, handler
);
143 /* only unmask interrupts after registering */
144 bsp_irq_unmask(timer
->irq_nr
);
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 */
156 /* callback for when the free running clock gets mapped */
158 kern_phys_fr_user_mapped(vir_bytes id
, phys_bytes address
)
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;
174 omap3_frclock_init(void)
178 /* enable the clock */
179 if (BOARD_IS_BBXM(machine
.board_id
)) {
180 fr_timer
= &dm37xx_fr_timer
;
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
);
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);
193 mmio_clear(fr_timer
->base
+ fr_timer
->regs
->TCLR
,
196 /* Use functional clock source for GPTIMER10 */
197 mmio_set(OMAP3_CM_CLKSEL_CORE
, OMAP3_CLKSEL_GPT10
);
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
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
);
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
);
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
);
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
);
234 mmio_clear(fr_timer
->base
+ fr_timer
->regs
->TCLR
,
237 /* 24Mhz / 16 = 1.5 Mhz */
238 mmio_set(fr_timer
->base
+ fr_timer
->regs
->TCLR
,
239 (3 << OMAP3_TCLR_PTV
));
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);
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
);
255 mmio_set(fr_timer
->base
+ fr_timer
->regs
->TCLR
,
256 OMAP3_TCLR_OVF_TRG
| OMAP3_TCLR_AR
| OMAP3_TCLR_ST
|
264 mmio_clear(fr_timer
->base
+ fr_timer
->regs
->TCLR
, OMAP3_TCLR_ST
);
268 bsp_timer_init(unsigned freq
)
270 /* we only support 1ms resolution */
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
);
278 mmio_clear(timer
->base
+ timer
->regs
->TCLR
, OMAP3_TCLR_ST
);
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
);
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
);
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
);
306 mmio_clear(timer
->base
+ timer
->regs
->TCLR
, OMAP3_TCLR_ST
);
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);
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
);
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();
334 mmio_clear(timer
->base
+ timer
->regs
->TCLR
, OMAP3_TCLR_ST
);
343 return mmio_read(fr_timer
->base
+ fr_timer
->regs
->TCRR
);
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.
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
361 frc_overflow_check(u32_t cur_frc
)
363 static int prev_frc_valid
;
364 static u32_t prev_frc
;
365 if (prev_frc_valid
&& prev_frc
> cur_frc
) {
373 bsp_timer_int_handler()
375 /* Clear all interrupts */
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
);
386 frc_overflow_check(now
);
389 /* Use the free running clock as TSC */
391 read_tsc_64(u64_t
* t
)
395 frc_overflow_check(now
);
396 *t
= (u64_t
) now
+ (high_frc
<< 32);