]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
1dc4da74 IY |
2 | /* |
3 | * (C) Copyright 2002 | |
4 | * Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
5 | * Marius Groeger <[email protected]> | |
6 | * | |
7 | * (C) Copyright 2002 | |
8 | * Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
9 | * Alex Zuepke <[email protected]> | |
10 | * | |
11 | * (C) Copyright 2002 | |
12 | * Gary Jennejohn, DENX Software Engineering, <[email protected]> | |
13 | * | |
14 | * (C) Copyright 2009 | |
15 | * Ilya Yanok, Emcraft Systems Ltd, <[email protected]> | |
1dc4da74 IY |
16 | */ |
17 | ||
18 | #include <common.h> | |
19 | #include <div64.h> | |
691d719d | 20 | #include <init.h> |
1045315d | 21 | #include <time.h> |
401d1c4f | 22 | #include <asm/global_data.h> |
1dc4da74 IY |
23 | #include <asm/io.h> |
24 | #include <asm/arch/imx-regs.h> | |
25a5818f | 25 | #include <asm/ptrace.h> |
c05ed00a | 26 | #include <linux/delay.h> |
1dc4da74 IY |
27 | |
28 | /* General purpose timers bitfields */ | |
29 | #define GPTCR_SWR (1 << 15) /* Software reset */ | |
30 | #define GPTCR_FRR (1 << 8) /* Freerun / restart */ | |
31 | #define GPTCR_CLKSOURCE_32 (4 << 1) /* Clock source */ | |
32 | #define GPTCR_TEN 1 /* Timer enable */ | |
33 | ||
c9ac3ba1 HS |
34 | DECLARE_GLOBAL_DATA_PTR; |
35 | ||
66ee6923 | 36 | #define timestamp (gd->arch.tbl) |
582601da | 37 | #define lastinc (gd->arch.lastinc) |
1dc4da74 IY |
38 | |
39 | /* | |
40 | * "time" is measured in 1 / CONFIG_SYS_HZ seconds, | |
41 | * "tick" is internal timer period | |
42 | */ | |
43 | #ifdef CONFIG_MX27_TIMER_HIGH_PRECISION | |
44 | /* ~0.4% error - measured with stop-watch on 100s boot-delay */ | |
45 | static inline unsigned long long tick_to_time(unsigned long long tick) | |
46 | { | |
47 | tick *= CONFIG_SYS_HZ; | |
48 | do_div(tick, CONFIG_MX27_CLK32); | |
49 | return tick; | |
50 | } | |
51 | ||
52 | static inline unsigned long long time_to_tick(unsigned long long time) | |
53 | { | |
54 | time *= CONFIG_MX27_CLK32; | |
55 | do_div(time, CONFIG_SYS_HZ); | |
56 | return time; | |
57 | } | |
58 | ||
59 | static inline unsigned long long us_to_tick(unsigned long long us) | |
60 | { | |
61 | us = us * CONFIG_MX27_CLK32 + 999999; | |
62 | do_div(us, 1000000); | |
63 | return us; | |
64 | } | |
65 | #else | |
66 | /* ~2% error */ | |
67 | #define TICK_PER_TIME ((CONFIG_MX27_CLK32 + CONFIG_SYS_HZ / 2) / \ | |
68 | CONFIG_SYS_HZ) | |
69 | #define US_PER_TICK (1000000 / CONFIG_MX27_CLK32) | |
70 | ||
71 | static inline unsigned long long tick_to_time(unsigned long long tick) | |
72 | { | |
73 | do_div(tick, TICK_PER_TIME); | |
74 | return tick; | |
75 | } | |
76 | ||
77 | static inline unsigned long long time_to_tick(unsigned long long time) | |
78 | { | |
79 | return time * TICK_PER_TIME; | |
80 | } | |
81 | ||
82 | static inline unsigned long long us_to_tick(unsigned long long us) | |
83 | { | |
84 | us += US_PER_TICK - 1; | |
85 | do_div(us, US_PER_TICK); | |
86 | return us; | |
87 | } | |
88 | #endif | |
89 | ||
90 | /* nothing really to do with interrupts, just starts up a counter. */ | |
91 | /* The 32768Hz 32-bit timer overruns in 131072 seconds */ | |
92 | int timer_init(void) | |
93 | { | |
94 | int i; | |
95 | struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE; | |
96 | struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; | |
97 | ||
98 | /* setup GP Timer 1 */ | |
99 | writel(GPTCR_SWR, ®s->gpt_tctl); | |
100 | ||
101 | writel(readl(&pll->pccr0) | PCCR0_GPT1_EN, &pll->pccr0); | |
102 | writel(readl(&pll->pccr1) | PCCR1_PERCLK1_EN, &pll->pccr1); | |
103 | ||
104 | for (i = 0; i < 100; i++) | |
105 | writel(0, ®s->gpt_tctl); /* We have no udelay by now */ | |
106 | writel(0, ®s->gpt_tprer); /* 32Khz */ | |
107 | /* Freerun Mode, PERCLK1 input */ | |
108 | writel(readl(®s->gpt_tctl) | GPTCR_CLKSOURCE_32 | GPTCR_FRR, | |
109 | ®s->gpt_tctl); | |
110 | writel(readl(®s->gpt_tctl) | GPTCR_TEN, ®s->gpt_tctl); | |
111 | ||
112 | return 0; | |
113 | } | |
114 | ||
77f11a99 | 115 | unsigned long long get_ticks(void) |
1dc4da74 IY |
116 | { |
117 | struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE; | |
118 | ulong now = readl(®s->gpt_tcn); /* current tick value */ | |
119 | ||
120 | if (now >= lastinc) { | |
121 | /* | |
122 | * normal mode (non roll) | |
123 | * move stamp forward with absolut diff ticks | |
124 | */ | |
125 | timestamp += (now - lastinc); | |
126 | } else { | |
127 | /* we have rollover of incrementer */ | |
128 | timestamp += (0xFFFFFFFF - lastinc) + now; | |
129 | } | |
130 | lastinc = now; | |
131 | return timestamp; | |
132 | } | |
133 | ||
6180ea7e | 134 | static ulong get_timer_masked(void) |
1dc4da74 IY |
135 | { |
136 | /* | |
137 | * get_ticks() returns a long long (64 bit), it wraps in | |
138 | * 2^64 / CONFIG_MX27_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~ | |
139 | * 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in | |
140 | * 5 * 10^6 days - long enough. | |
141 | */ | |
142 | return tick_to_time(get_ticks()); | |
143 | } | |
144 | ||
77f11a99 | 145 | ulong get_timer(ulong base) |
1dc4da74 | 146 | { |
77f11a99 | 147 | return get_timer_masked() - base; |
1dc4da74 IY |
148 | } |
149 | ||
8e5e9b94 | 150 | /* delay x useconds AND preserve advance timstamp value */ |
77f11a99 | 151 | void __udelay(unsigned long usec) |
1dc4da74 IY |
152 | { |
153 | unsigned long long tmp; | |
154 | ulong tmo; | |
155 | ||
156 | tmo = us_to_tick(usec); | |
157 | tmp = get_ticks() + tmo; /* get current timestamp */ | |
158 | ||
159 | while (get_ticks() < tmp) /* loop till event */ | |
160 | /*NOP*/; | |
161 | } | |
63b1e004 SB |
162 | |
163 | ulong get_tbclk(void) | |
164 | { | |
165 | return CONFIG_MX27_CLK32; | |
166 | } |