]>
Commit | Line | Data |
---|---|---|
b9bb0531 SB |
1 | /* |
2 | * (C) Copyright 2007 | |
3 | * Sascha Hauer, Pengutronix | |
4 | * | |
5 | * (C) Copyright 2008-2009 Freescale Semiconductor, Inc. | |
6 | * | |
1a459660 | 7 | * SPDX-License-Identifier: GPL-2.0+ |
b9bb0531 SB |
8 | */ |
9 | ||
10 | #include <common.h> | |
11 | #include <asm/io.h> | |
31bb50f8 | 12 | #include <div64.h> |
b9bb0531 | 13 | #include <asm/arch/imx-regs.h> |
543d2479 | 14 | #include <asm/arch/crm_regs.h> |
31bb50f8 SB |
15 | #include <asm/arch/clock.h> |
16 | ||
17 | DECLARE_GLOBAL_DATA_PTR; | |
18 | ||
66ee6923 | 19 | #define timestamp (gd->arch.tbl) |
582601da | 20 | #define lastinc (gd->arch.lastinc) |
b9bb0531 SB |
21 | |
22 | /* General purpose timers bitfields */ | |
23 | #define GPTCR_SWR (1<<15) /* Software reset */ | |
24 | #define GPTCR_FRR (1<<9) /* Freerun / restart */ | |
543d2479 | 25 | #define GPTCR_CLKSOURCE_32 (4<<6) /* Clock source */ |
b9bb0531 | 26 | #define GPTCR_TEN (1) /* Timer enable */ |
31bb50f8 | 27 | |
543d2479 BT |
28 | /* |
29 | * "time" is measured in 1 / CONFIG_SYS_HZ seconds, | |
30 | * "tick" is internal timer period | |
31 | */ | |
32 | /* ~0.4% error - measured with stop-watch on 100s boot-delay */ | |
31bb50f8 SB |
33 | static inline unsigned long long tick_to_time(unsigned long long tick) |
34 | { | |
35 | tick *= CONFIG_SYS_HZ; | |
543d2479 | 36 | do_div(tick, MXC_CLK32); |
31bb50f8 SB |
37 | |
38 | return tick; | |
39 | } | |
40 | ||
543d2479 | 41 | static inline unsigned long long us_to_tick(unsigned long long us) |
31bb50f8 | 42 | { |
543d2479 BT |
43 | us = us * MXC_CLK32 + 999999; |
44 | do_div(us, 1000000); | |
31bb50f8 | 45 | |
543d2479 | 46 | return us; |
31bb50f8 | 47 | } |
b9bb0531 | 48 | |
543d2479 BT |
49 | /* |
50 | * nothing really to do with interrupts, just starts up a counter. | |
51 | * The 32KHz 32-bit timer overruns in 134217 seconds | |
52 | */ | |
b9bb0531 SB |
53 | int timer_init(void) |
54 | { | |
55 | int i; | |
56 | struct gpt_regs *gpt = (struct gpt_regs *)GPT1_BASE_ADDR; | |
543d2479 | 57 | struct ccm_regs *ccm = (struct ccm_regs *)CCM_BASE_ADDR; |
b9bb0531 SB |
58 | |
59 | /* setup GP Timer 1 */ | |
60 | writel(GPTCR_SWR, &gpt->ctrl); | |
b9bb0531 | 61 | |
543d2479 BT |
62 | writel(readl(&ccm->cgr1) | 3 << MXC_CCM_CGR1_GPT_OFFSET, &ccm->cgr1); |
63 | ||
64 | for (i = 0; i < 100; i++) | |
65 | writel(0, &gpt->ctrl); /* We have no udelay by now */ | |
66 | writel(0, &gpt->pre); /* prescaler = 1 */ | |
67 | /* Freerun Mode, 32KHz input */ | |
68 | writel(readl(&gpt->ctrl) | GPTCR_CLKSOURCE_32 | GPTCR_FRR, | |
69 | &gpt->ctrl); | |
70 | writel(readl(&gpt->ctrl) | GPTCR_TEN, &gpt->ctrl); | |
b9bb0531 SB |
71 | |
72 | return 0; | |
73 | } | |
74 | ||
31bb50f8 | 75 | unsigned long long get_ticks(void) |
b9bb0531 SB |
76 | { |
77 | struct gpt_regs *gpt = (struct gpt_regs *)GPT1_BASE_ADDR; | |
31bb50f8 SB |
78 | ulong now = readl(&gpt->counter); /* current tick value */ |
79 | ||
80 | if (now >= lastinc) { | |
81 | /* | |
82 | * normal mode (non roll) | |
83 | * move stamp forward with absolut diff ticks | |
84 | */ | |
85 | timestamp += (now - lastinc); | |
86 | } else { | |
87 | /* we have rollover of incrementer */ | |
88 | timestamp += (0xFFFFFFFF - lastinc) + now; | |
89 | } | |
90 | lastinc = now; | |
91 | return timestamp; | |
b9bb0531 SB |
92 | } |
93 | ||
31bb50f8 | 94 | ulong get_timer_masked(void) |
b9bb0531 | 95 | { |
31bb50f8 SB |
96 | /* |
97 | * get_ticks() returns a long long (64 bit), it wraps in | |
9c6c5c06 | 98 | * 2^64 / MXC_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~ |
31bb50f8 SB |
99 | * 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in |
100 | * 5 * 10^6 days - long enough. | |
101 | */ | |
102 | return tick_to_time(get_ticks()); | |
b9bb0531 SB |
103 | } |
104 | ||
b9bb0531 SB |
105 | ulong get_timer(ulong base) |
106 | { | |
31bb50f8 SB |
107 | return get_timer_masked() - base; |
108 | } | |
b9bb0531 | 109 | |
31bb50f8 SB |
110 | /* delay x useconds AND preserve advance timstamp value */ |
111 | void __udelay(unsigned long usec) | |
112 | { | |
113 | unsigned long long tmp; | |
114 | ulong tmo; | |
b9bb0531 | 115 | |
31bb50f8 SB |
116 | tmo = us_to_tick(usec); |
117 | tmp = get_ticks() + tmo; /* get current timestamp */ | |
b9bb0531 | 118 | |
31bb50f8 SB |
119 | while (get_ticks() < tmp) /* loop till event */ |
120 | /*NOP*/; | |
b9bb0531 SB |
121 | } |
122 | ||
b9bb0531 | 123 | /* |
31bb50f8 SB |
124 | * This function is derived from PowerPC code (timebase clock frequency). |
125 | * On ARM it returns the number of timer ticks per second. | |
b9bb0531 | 126 | */ |
31bb50f8 | 127 | ulong get_tbclk(void) |
b9bb0531 | 128 | { |
543d2479 | 129 | return MXC_CLK32; |
b9bb0531 | 130 | } |