]>
Commit | Line | Data |
---|---|---|
445a886d ML |
1 | /* |
2 | * (C) Copyright 2009 Faraday Technology | |
3 | * Po-Yu Chuang <ratbert@faraday-tech.com> | |
4 | * | |
5 | * Copyright (C) 2011 Andes Technology Corporation | |
6 | * Shawn Lin, Andes Technology Corporation <nobuhiro@andestech.com> | |
7 | * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com> | |
8 | * | |
1a459660 | 9 | * SPDX-License-Identifier: GPL-2.0+ |
445a886d | 10 | */ |
f5076f86 | 11 | #ifndef CONFIG_TIMER |
445a886d ML |
12 | #include <common.h> |
13 | #include <asm/io.h> | |
14 | #include <faraday/fttmr010.h> | |
15 | ||
16 | static ulong timestamp; | |
17 | static ulong lastdec; | |
18 | ||
19 | int timer_init(void) | |
20 | { | |
39c87743 | 21 | struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE; |
445a886d ML |
22 | unsigned int cr; |
23 | ||
24 | debug("%s()\n", __func__); | |
25 | ||
26 | /* disable timers */ | |
27 | writel(0, &tmr->cr); | |
28 | ||
29 | #ifdef CONFIG_FTTMR010_EXT_CLK | |
30 | /* use 32768Hz oscillator for RTC, WDT, TIMER */ | |
31 | ftpmu010_32768osc_enable(); | |
32 | #endif | |
33 | ||
34 | /* setup timer */ | |
35 | writel(TIMER_LOAD_VAL, &tmr->timer3_load); | |
36 | writel(TIMER_LOAD_VAL, &tmr->timer3_counter); | |
37 | writel(0, &tmr->timer3_match1); | |
38 | writel(0, &tmr->timer3_match2); | |
39 | ||
40 | /* we don't want timer to issue interrupts */ | |
41 | writel(FTTMR010_TM3_MATCH1 | | |
42 | FTTMR010_TM3_MATCH2 | | |
43 | FTTMR010_TM3_OVERFLOW, | |
44 | &tmr->interrupt_mask); | |
45 | ||
46 | cr = readl(&tmr->cr); | |
47 | #ifdef CONFIG_FTTMR010_EXT_CLK | |
48 | cr |= FTTMR010_TM3_CLOCK; /* use external clock */ | |
49 | #endif | |
50 | cr |= FTTMR010_TM3_ENABLE; | |
51 | writel(cr, &tmr->cr); | |
52 | ||
53 | /* init the timestamp and lastdec value */ | |
54 | reset_timer_masked(); | |
55 | ||
56 | return 0; | |
57 | } | |
58 | ||
59 | /* | |
60 | * timer without interrupts | |
61 | */ | |
62 | ||
63 | /* | |
64 | * reset time | |
65 | */ | |
66 | void reset_timer_masked(void) | |
67 | { | |
39c87743 | 68 | struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE; |
445a886d ML |
69 | |
70 | /* capure current decrementer value time */ | |
71 | #ifdef CONFIG_FTTMR010_EXT_CLK | |
72 | lastdec = readl(&tmr->timer3_counter) / (TIMER_CLOCK / CONFIG_SYS_HZ); | |
73 | #else | |
4fc96705 AL |
74 | lastdec = readl(&tmr->timer3_counter) / |
75 | (CONFIG_SYS_CLK_FREQ / 2 / CONFIG_SYS_HZ); | |
445a886d ML |
76 | #endif |
77 | timestamp = 0; /* start "advancing" time stamp from 0 */ | |
78 | ||
79 | debug("%s(): lastdec = %lx\n", __func__, lastdec); | |
80 | } | |
81 | ||
82 | void reset_timer(void) | |
83 | { | |
84 | debug("%s()\n", __func__); | |
85 | reset_timer_masked(); | |
86 | } | |
87 | ||
88 | /* | |
89 | * return timer ticks | |
90 | */ | |
91 | ulong get_timer_masked(void) | |
92 | { | |
39c87743 | 93 | struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE; |
445a886d ML |
94 | |
95 | /* current tick value */ | |
96 | #ifdef CONFIG_FTTMR010_EXT_CLK | |
97 | ulong now = readl(&tmr->timer3_counter) / (TIMER_CLOCK / CONFIG_SYS_HZ); | |
98 | #else | |
4fc96705 AL |
99 | ulong now = readl(&tmr->timer3_counter) / |
100 | (CONFIG_SYS_CLK_FREQ / 2 / CONFIG_SYS_HZ); | |
445a886d ML |
101 | #endif |
102 | ||
103 | debug("%s(): now = %lx, lastdec = %lx\n", __func__, now, lastdec); | |
104 | ||
105 | if (lastdec >= now) { | |
106 | /* | |
107 | * normal mode (non roll) | |
108 | * move stamp fordward with absoulte diff ticks | |
109 | */ | |
110 | timestamp += lastdec - now; | |
111 | } else { | |
112 | /* | |
113 | * we have overflow of the count down timer | |
114 | * | |
115 | * nts = ts + ld + (TLV - now) | |
116 | * ts=old stamp, ld=time that passed before passing through -1 | |
117 | * (TLV-now) amount of time after passing though -1 | |
118 | * nts = new "advancing time stamp"...it could also roll and | |
119 | * cause problems. | |
120 | */ | |
121 | timestamp += lastdec + TIMER_LOAD_VAL - now; | |
122 | } | |
123 | ||
124 | lastdec = now; | |
125 | ||
126 | debug("%s() returns %lx\n", __func__, timestamp); | |
127 | ||
128 | return timestamp; | |
129 | } | |
130 | ||
131 | /* | |
132 | * return difference between timer ticks and base | |
133 | */ | |
134 | ulong get_timer(ulong base) | |
135 | { | |
136 | debug("%s(%lx)\n", __func__, base); | |
137 | return get_timer_masked() - base; | |
138 | } | |
139 | ||
140 | void set_timer(ulong t) | |
141 | { | |
142 | debug("%s(%lx)\n", __func__, t); | |
143 | timestamp = t; | |
144 | } | |
145 | ||
146 | /* delay x useconds AND preserve advance timestamp value */ | |
147 | void __udelay(unsigned long usec) | |
148 | { | |
39c87743 | 149 | struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE; |
445a886d ML |
150 | |
151 | #ifdef CONFIG_FTTMR010_EXT_CLK | |
152 | long tmo = usec * (TIMER_CLOCK / 1000) / 1000; | |
153 | #else | |
154 | long tmo = usec * ((CONFIG_SYS_CLK_FREQ / 2) / 1000) / 1000; | |
155 | #endif | |
156 | unsigned long now, last = readl(&tmr->timer3_counter); | |
157 | ||
158 | debug("%s(%lu)\n", __func__, usec); | |
159 | while (tmo > 0) { | |
160 | now = readl(&tmr->timer3_counter); | |
161 | if (now > last) /* count down timer overflow */ | |
162 | tmo -= TIMER_LOAD_VAL + last - now; | |
163 | else | |
164 | tmo -= last - now; | |
165 | last = now; | |
166 | } | |
167 | } | |
168 | ||
169 | /* | |
170 | * This function is derived from PowerPC code (read timebase as long long). | |
171 | * On ARM it just returns the timer value. | |
172 | */ | |
173 | unsigned long long get_ticks(void) | |
174 | { | |
175 | debug("%s()\n", __func__); | |
176 | return get_timer(0); | |
177 | } | |
178 | ||
179 | /* | |
180 | * This function is derived from PowerPC code (timebase clock frequency). | |
181 | * On ARM it returns the number of timer ticks per second. | |
182 | */ | |
183 | ulong get_tbclk(void) | |
184 | { | |
185 | debug("%s()\n", __func__); | |
186 | #ifdef CONFIG_FTTMR010_EXT_CLK | |
187 | return CONFIG_SYS_HZ; | |
188 | #else | |
189 | return CONFIG_SYS_CLK_FREQ; | |
190 | #endif | |
191 | } | |
f5076f86 | 192 | #endif /* CONFIG_TIMER */ |