Fix a typo
[kugel-rb/myfork.git] / firmware / timer.c
blob1cd913bb358968658cb2741858cb5202dad91cb9
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 Jens Arnold
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include <stdbool.h>
23 #include "config.h"
24 #include "cpu.h"
25 #include "system.h"
26 #include "timer.h"
27 #include "logf.h"
29 static int timer_prio = -1;
30 void SHAREDBSS_ATTR (*pfn_timer)(void) = NULL; /* timer callback */
31 void SHAREDBSS_ATTR (*pfn_unregister)(void) = NULL; /* unregister callback */
32 #ifdef CPU_COLDFIRE
33 static int base_prescale;
34 #elif defined CPU_PP || CONFIG_CPU == PNX0101
35 static long SHAREDBSS_ATTR cycles_new = 0;
36 #endif
38 #ifndef __TIMER_SET
39 /* Define these if not defined by target to make the #else cases compile
40 * even if the target doesn't have them implemented. */
41 #define __TIMER_SET(cycles, set) false
42 #define __TIMER_REGISTER(reg_prio, unregister_callback, cycles, \
43 int_prio, timer_callback) false
44 #define __TIMER_UNREGISTER(...)
45 #endif
47 /* interrupt handler */
48 #if CONFIG_CPU == SH7034
49 void IMIA4(void) __attribute__((interrupt_handler));
50 void IMIA4(void)
52 if (pfn_timer != NULL)
53 pfn_timer();
54 and_b(~0x01, &TSR4); /* clear the interrupt */
56 #elif defined CPU_COLDFIRE
57 void TIMER1(void) __attribute__ ((interrupt_handler));
58 void TIMER1(void)
60 if (pfn_timer != NULL)
61 pfn_timer();
62 TER1 = 0xff; /* clear all events */
64 #elif CONFIG_CPU == AS3525
65 void INT_TIMER1(void)
67 if (pfn_timer != NULL)
68 pfn_timer();
70 TIMER1_INTCLR = 0; /* clear interrupt */
72 #elif defined(CPU_PP)
73 void TIMER2(void)
75 TIMER2_VAL; /* ACK interrupt */
76 if (cycles_new > 0)
78 TIMER2_CFG = 0xc0000000 | (cycles_new - 1);
79 cycles_new = 0;
81 if (pfn_timer != NULL)
83 cycles_new = -1;
84 /* "lock" the variable, in case timer_set_period()
85 * is called within pfn_timer() */
86 pfn_timer();
87 cycles_new = 0;
90 #elif CONFIG_CPU == PNX0101
91 void TIMER1_ISR(void)
93 if (cycles_new > 0)
95 TIMER1.load = cycles_new - 1;
96 cycles_new = 0;
98 if (pfn_timer != NULL)
100 cycles_new = -1;
101 /* "lock" the variable, in case timer_set_period()
102 * is called within pfn_timer() */
103 pfn_timer();
104 cycles_new = 0;
106 TIMER1.clr = 1; /* clear the interrupt */
108 #endif /* CONFIG_CPU */
110 static bool timer_set(long cycles, bool start)
112 #if CONFIG_CPU == SH7034 || defined(CPU_COLDFIRE)
113 int phi = 0; /* bits for the prescaler */
114 int prescale = 1;
116 while (cycles > 0x10000)
117 { /* work out the smallest prescaler that makes it fit */
118 #if CONFIG_CPU == SH7034
119 phi++;
120 #endif
121 prescale <<= 1;
122 cycles >>= 1;
124 #endif
126 #if CONFIG_CPU == PNX0101
127 if (start)
129 if (pfn_unregister != NULL)
131 pfn_unregister();
132 pfn_unregister = NULL;
134 TIMER1.ctrl &= ~0x80; /* disable the counter */
135 TIMER1.ctrl |= 0x40; /* reload after counting down to zero */
136 TIMER1.ctrl &= ~0xc; /* no prescaler */
137 TIMER1.clr = 1; /* clear an interrupt event */
139 if (start || (cycles_new == -1)) /* within isr, cycles_new is "locked" */
140 { /* enable timer */
141 TIMER1.load = cycles - 1;
142 TIMER1.ctrl |= 0x80; /* enable the counter */
144 else
145 cycles_new = cycles;
147 return true;
148 #elif CONFIG_CPU == SH7034
149 if (prescale > 8)
150 return false;
152 if (start)
154 if (pfn_unregister != NULL)
156 pfn_unregister();
157 pfn_unregister = NULL;
160 and_b(~0x10, &TSTR); /* Stop the timer 4 */
161 and_b(~0x10, &TSNC); /* No synchronization */
162 and_b(~0x10, &TMDR); /* Operate normally */
164 TIER4 = 0xF9; /* Enable GRA match interrupt */
167 TCR4 = 0x20 | phi; /* clear at GRA match, set prescaler */
168 GRA4 = (unsigned short)(cycles - 1);
169 if (start || (TCNT4 >= GRA4))
170 TCNT4 = 0;
171 and_b(~0x01, &TSR4); /* clear an eventual interrupt */
173 return true;
174 #elif CONFIG_CPU == AS3525
175 if (start)
177 if (pfn_unregister != NULL)
179 pfn_unregister();
180 pfn_unregister = NULL;
184 TIMER1_LOAD = TIMER1_BGLOAD = cycles;
185 /* /!\ bit 4 (reserved) must not be modified
186 * periodic mode, interrupt enabled, no prescale, 32 bits counter */
187 TIMER1_CONTROL = (TIMER1_CONTROL & (1<<4)) |
188 TIMER_ENABLE |
189 TIMER_PERIODIC |
190 TIMER_INT_ENABLE |
191 TIMER_32_BIT;
192 return true;
193 #elif defined CPU_COLDFIRE
194 if (prescale > 4096/CPUFREQ_MAX_MULT)
195 return false;
197 if (prescale > 256/CPUFREQ_MAX_MULT)
199 phi = 0x05; /* prescale sysclk/16, timer enabled */
200 prescale >>= 4;
202 else
203 phi = 0x03; /* prescale sysclk, timer enabled */
205 base_prescale = prescale;
206 prescale *= (cpu_frequency / CPU_FREQ);
208 if (start)
210 if (pfn_unregister != NULL)
212 pfn_unregister();
213 pfn_unregister = NULL;
215 phi &= ~1; /* timer disabled at start */
217 /* If it is already enabled, writing a 0 to the RST bit will clear
218 the register, so we clear RST explicitly before writing the real
219 data. */
220 TMR1 = 0;
223 /* We are using timer 1 */
224 TMR1 = 0x0018 | (unsigned short)phi | ((unsigned short)(prescale - 1) << 8);
225 TRR1 = (unsigned short)(cycles - 1);
226 if (start || (TCN1 >= TRR1))
227 TCN1 = 0; /* reset the timer */
228 TER1 = 0xff; /* clear all events */
230 return true;
231 #elif defined(CPU_PP)
232 if (cycles > 0x20000000 || cycles < 2)
233 return false;
235 if (start)
237 if (pfn_unregister != NULL)
239 pfn_unregister();
240 pfn_unregister = NULL;
242 CPU_INT_DIS = TIMER2_MASK;
243 COP_INT_DIS = TIMER2_MASK;
245 if (start || (cycles_new == -1)) /* within isr, cycles_new is "locked" */
246 TIMER2_CFG = 0xc0000000 | (cycles - 1); /* enable timer */
247 else
248 cycles_new = cycles;
250 return true;
251 #else
252 return __TIMER_SET(cycles, start);
253 #endif /* CONFIG_CPU */
256 #ifdef CPU_COLDFIRE
257 void timers_adjust_prescale(int multiplier, bool enable_irq)
259 /* tick timer */
260 TMR0 = (TMR0 & 0x00ef)
261 | ((unsigned short)(multiplier - 1) << 8)
262 | (enable_irq ? 0x10 : 0);
264 if (pfn_timer)
266 /* user timer */
267 int prescale = base_prescale * multiplier;
268 TMR1 = (TMR1 & 0x00ef)
269 | ((unsigned short)(prescale - 1) << 8)
270 | (enable_irq ? 0x10 : 0);
273 #endif
275 /* Register a user timer, called every <cycles> TIMER_FREQ cycles */
276 bool timer_register(int reg_prio, void (*unregister_callback)(void),
277 long cycles, int int_prio, void (*timer_callback)(void)
278 IF_COP(, int core))
280 if (reg_prio <= timer_prio || cycles == 0)
281 return false;
283 #if CONFIG_CPU == SH7034
284 if (int_prio < 1 || int_prio > 15)
285 return false;
286 #endif
288 if (!timer_set(cycles, true))
289 return false;
291 pfn_timer = timer_callback;
292 pfn_unregister = unregister_callback;
293 timer_prio = reg_prio;
295 #if CONFIG_CPU == SH7034
296 IPRD = (IPRD & 0xFF0F) | int_prio << 4; /* interrupt priority */
297 or_b(0x10, &TSTR); /* start timer 4 */
298 return true;
299 #elif defined CPU_COLDFIRE
300 ICR2 = 0x90; /* interrupt on level 4.0 */
301 and_l(~(1<<10), &IMR);
302 TMR1 |= 1; /* start timer */
303 return true;
304 #elif defined(CPU_PP)
305 /* unmask interrupt source */
306 #if NUM_CORES > 1
307 if (core == COP)
308 COP_INT_EN = TIMER2_MASK;
309 else
310 #endif
311 CPU_INT_EN = TIMER2_MASK;
312 return true;
313 #elif CONFIG_CPU == PNX0101
314 irq_set_int_handler(IRQ_TIMER1, TIMER1_ISR);
315 irq_enable_int(IRQ_TIMER1);
316 return true;
317 #elif CONFIG_CPU == AS3525
318 CGU_PERI |= CGU_TIMER1_CLOCK_ENABLE; /* enable peripheral */
319 VIC_INT_ENABLE |= INTERRUPT_TIMER1;
320 return true;
321 #else
322 return __TIMER_REGISTER(reg_prio, unregister_callback, cycles,
323 int_prio, timer_callback);
324 #endif
325 /* Cover for targets that don't use all these */
326 (void)reg_prio;
327 (void)unregister_callback;
328 (void)cycles;
329 /* TODO: Implement for PortalPlayer and iFP (if possible) */
330 (void)int_prio;
331 (void)timer_callback;
334 bool timer_set_period(long cycles)
336 return timer_set(cycles, false);
339 void timer_unregister(void)
341 #if CONFIG_CPU == SH7034
342 and_b(~0x10, &TSTR); /* stop the timer 4 */
343 IPRD = (IPRD & 0xFF0F); /* disable interrupt */
344 #elif defined CPU_COLDFIRE
345 TMR1 = 0; /* disable timer 1 */
346 or_l((1<<10), &IMR); /* disable interrupt */
347 #elif defined(CPU_PP)
348 TIMER2_CFG = 0; /* stop timer 2 */
349 CPU_INT_DIS = TIMER2_MASK;
350 COP_INT_DIS = TIMER2_MASK;
351 #elif CONFIG_CPU == PNX0101
352 TIMER1.ctrl &= ~0x80; /* disable timer 1 */
353 irq_disable_int(IRQ_TIMER1);
354 #elif CONFIG_CPU == AS3525
355 TIMER1_CONTROL &= 0x10; /* disable timer 1 (don't modify bit 4) */
356 VIC_INT_EN_CLEAR = INTERRUPT_TIMER1; /* disable interrupt */
357 CGU_PERI &= ~CGU_TIMER1_CLOCK_ENABLE; /* disable peripheral */
358 #else
359 __TIMER_UNREGISTER();
360 #endif
361 pfn_timer = NULL;
362 pfn_unregister = NULL;
363 timer_prio = -1;