Hide symbols by default on 64 bit sim buildsto avoid clashing, fixes crashing on...
[kugel-rb.git] / firmware / timer.c
blobd15ba64443e0a037285911523161a96794ef0191
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 Jens Arnold
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include <stdbool.h>
21 #include "config.h"
22 #include "cpu.h"
23 #include "system.h"
24 #include "timer.h"
25 #include "logf.h"
27 static int timer_prio = -1;
28 void (*pfn_timer)(void) = NULL; /* timer callback */
29 void (*pfn_unregister)(void) = NULL; /* unregister callback */
30 #ifdef CPU_COLDFIRE
31 static int base_prescale;
32 #elif defined CPU_PP || CONFIG_CPU == PNX0101
33 static long cycles_new = 0;
34 #endif
36 /* interrupt handler */
37 #if CONFIG_CPU == SH7034
38 void IMIA4(void) __attribute__((interrupt_handler));
39 void IMIA4(void)
41 if (pfn_timer != NULL)
42 pfn_timer();
43 and_b(~0x01, &TSR4); /* clear the interrupt */
45 #elif defined CPU_COLDFIRE
46 void TIMER1(void) __attribute__ ((interrupt_handler));
47 void TIMER1(void)
49 if (pfn_timer != NULL)
50 pfn_timer();
51 TER1 = 0xff; /* clear all events */
53 #elif defined(CPU_PP)
54 void TIMER2(void)
56 TIMER2_VAL; /* ACK interrupt */
57 if (cycles_new > 0)
59 TIMER2_CFG = 0xc0000000 | (cycles_new - 1);
60 cycles_new = 0;
62 if (pfn_timer != NULL)
64 cycles_new = -1;
65 /* "lock" the variable, in case timer_set_period()
66 * is called within pfn_timer() */
67 pfn_timer();
68 cycles_new = 0;
71 #elif CONFIG_CPU == PNX0101
72 void TIMER1_ISR(void)
74 if (cycles_new > 0)
76 TIMER1.load = cycles_new - 1;
77 cycles_new = 0;
79 if (pfn_timer != NULL)
81 cycles_new = -1;
82 /* "lock" the variable, in case timer_set_period()
83 * is called within pfn_timer() */
84 pfn_timer();
85 cycles_new = 0;
87 TIMER1.clr = 1; /* clear the interrupt */
89 #endif /* CONFIG_CPU */
91 static bool timer_set(long cycles, bool start)
93 #if (CONFIG_CPU == SH7034) || defined(CPU_COLDFIRE)
94 int phi = 0; /* bits for the prescaler */
95 int prescale = 1;
97 while (cycles > 0x10000)
98 { /* work out the smallest prescaler that makes it fit */
99 #if CONFIG_CPU == SH7034
100 phi++;
101 #endif
102 prescale *= 2;
103 cycles >>= 1;
105 #endif
107 #if CONFIG_CPU == PNX0101
108 if (start)
110 if (pfn_unregister != NULL)
112 pfn_unregister();
113 pfn_unregister = NULL;
115 TIMER1.ctrl &= ~0x80; /* disable the counter */
116 TIMER1.ctrl |= 0x40; /* reload after counting down to zero */
117 TIMER1.ctrl &= ~0xc; /* no prescaler */
118 TIMER1.clr = 1; /* clear an interrupt event */
120 if (start || (cycles_new == -1)) /* within isr, cycles_new is "locked" */
121 { /* enable timer */
122 TIMER1.load = cycles - 1;
123 TIMER1.ctrl |= 0x80; /* enable the counter */
125 else
126 cycles_new = cycles;
128 return true;
129 #elif CONFIG_CPU == SH7034
130 if (prescale > 8)
131 return false;
133 if (start)
135 if (pfn_unregister != NULL)
137 pfn_unregister();
138 pfn_unregister = NULL;
141 and_b(~0x10, &TSTR); /* Stop the timer 4 */
142 and_b(~0x10, &TSNC); /* No synchronization */
143 and_b(~0x10, &TMDR); /* Operate normally */
145 TIER4 = 0xF9; /* Enable GRA match interrupt */
148 TCR4 = 0x20 | phi; /* clear at GRA match, set prescaler */
149 GRA4 = (unsigned short)(cycles - 1);
150 if (start || (TCNT4 >= GRA4))
151 TCNT4 = 0;
152 and_b(~0x01, &TSR4); /* clear an eventual interrupt */
154 return true;
155 #elif defined CPU_COLDFIRE
156 if (prescale > 4096/CPUFREQ_MAX_MULT)
157 return false;
159 if (prescale > 256/CPUFREQ_MAX_MULT)
161 phi = 0x05; /* prescale sysclk/16, timer enabled */
162 prescale >>= 4;
164 else
165 phi = 0x03; /* prescale sysclk, timer enabled */
167 base_prescale = prescale;
168 prescale *= (cpu_frequency / CPU_FREQ);
170 if (start)
172 if (pfn_unregister != NULL)
174 pfn_unregister();
175 pfn_unregister = NULL;
177 phi &= ~1; /* timer disabled at start */
179 /* If it is already enabled, writing a 0 to the RST bit will clear
180 the register, so we clear RST explicitly before writing the real
181 data. */
182 TMR1 = 0;
185 /* We are using timer 1 */
186 TMR1 = 0x0018 | (unsigned short)phi | ((unsigned short)(prescale - 1) << 8);
187 TRR1 = (unsigned short)(cycles - 1);
188 if (start || (TCN1 >= TRR1))
189 TCN1 = 0; /* reset the timer */
190 TER1 = 0xff; /* clear all events */
192 return true;
193 #elif defined(CPU_PP)
194 if (cycles > 0x20000000 || cycles < 2)
195 return false;
197 if (start)
199 if (pfn_unregister != NULL)
201 pfn_unregister();
202 pfn_unregister = NULL;
205 if (start || (cycles_new == -1)) /* within isr, cycles_new is "locked" */
206 TIMER2_CFG = 0xc0000000 | (cycles - 1); /* enable timer */
207 else
208 cycles_new = cycles;
210 return true;
211 #elif (CONFIG_CPU == IMX31L)
212 /* TODO */
213 #else
214 return __TIMER_SET(cycles, start);
215 #endif /* CONFIG_CPU */
218 #ifdef CPU_COLDFIRE
219 void timers_adjust_prescale(int multiplier, bool enable_irq)
221 /* tick timer */
222 TMR0 = (TMR0 & 0x00ef)
223 | ((unsigned short)(multiplier - 1) << 8)
224 | (enable_irq ? 0x10 : 0);
226 if (pfn_timer)
228 /* user timer */
229 int prescale = base_prescale * multiplier;
230 TMR1 = (TMR1 & 0x00ef)
231 | ((unsigned short)(prescale - 1) << 8)
232 | (enable_irq ? 0x10 : 0);
235 #endif
237 /* Register a user timer, called every <cycles> TIMER_FREQ cycles */
238 bool timer_register(int reg_prio, void (*unregister_callback)(void),
239 long cycles, int int_prio, void (*timer_callback)(void))
241 if (reg_prio <= timer_prio || cycles == 0)
242 return false;
244 #if CONFIG_CPU == SH7034
245 if (int_prio < 1 || int_prio > 15)
246 return false;
247 #endif
249 if (!timer_set(cycles, true))
250 return false;
252 pfn_timer = timer_callback;
253 pfn_unregister = unregister_callback;
254 timer_prio = reg_prio;
256 #if CONFIG_CPU == SH7034
257 IPRD = (IPRD & 0xFF0F) | int_prio << 4; /* interrupt priority */
258 or_b(0x10, &TSTR); /* start timer 4 */
259 return true;
260 #elif defined CPU_COLDFIRE
261 ICR2 = 0x90; /* interrupt on level 4.0 */
262 and_l(~(1<<10), &IMR);
263 TMR1 |= 1; /* start timer */
264 return true;
265 #elif defined(CPU_PP)
266 /* unmask interrupt source */
267 CPU_INT_EN = TIMER2_MASK;
268 return true;
269 #elif CONFIG_CPU == PNX0101
270 irq_set_int_handler(IRQ_TIMER1, TIMER1_ISR);
271 irq_enable_int(IRQ_TIMER1);
272 return true;
273 #elif CONFIG_CPU == IMX31L
274 /* TODO */
275 #else
276 return __TIMER_REGISTER(reg_prio, unregister_callback, cycles,
277 int_prio, timer_callback);
278 #endif
279 /* Cover for targets that don't use all these */
280 (void)reg_prio;
281 (void)unregister_callback;
282 (void)cycles;
283 /* TODO: Implement for PortalPlayer and iFP (if possible) */
284 (void)int_prio;
285 (void)timer_callback;
288 bool timer_set_period(long cycles)
290 return timer_set(cycles, false);
293 void timer_unregister(void)
295 #if CONFIG_CPU == SH7034
296 and_b(~0x10, &TSTR); /* stop the timer 4 */
297 IPRD = (IPRD & 0xFF0F); /* disable interrupt */
298 #elif defined CPU_COLDFIRE
299 TMR1 = 0; /* disable timer 1 */
300 or_l((1<<10), &IMR); /* disable interrupt */
301 #elif defined(CPU_PP)
302 TIMER2_CFG = 0; /* stop timer 2 */
303 CPU_INT_CLR = TIMER2_MASK;
304 #elif CONFIG_CPU == PNX0101
305 TIMER1.ctrl &= ~0x80; /* disable timer 1 */
306 irq_disable_int(IRQ_TIMER1);
307 #elif CONFIG_CPU == S3C2440
308 __TIMER_UNREGISTER();
309 #endif
310 pfn_timer = NULL;
311 pfn_unregister = NULL;
312 timer_prio = -1;