Cleaner solution to plugin-included core files.
[kugel-rb.git] / firmware / timer.c
bloba11cd10b7ea590415a197bd04ddae1bfd82e6bfc
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 /* interrupt handler */
39 #if CONFIG_CPU == SH7034
40 void IMIA4(void) __attribute__((interrupt_handler));
41 void IMIA4(void)
43 if (pfn_timer != NULL)
44 pfn_timer();
45 and_b(~0x01, &TSR4); /* clear the interrupt */
47 #elif defined CPU_COLDFIRE
48 void TIMER1(void) __attribute__ ((interrupt_handler));
49 void TIMER1(void)
51 if (pfn_timer != NULL)
52 pfn_timer();
53 TER1 = 0xff; /* clear all events */
55 #elif CONFIG_CPU == AS3525
56 void INT_TIMER1(void)
58 if (pfn_timer != NULL)
59 pfn_timer();
61 TIMER1_INTCLR = 0; /* clear interrupt */
63 #elif defined(CPU_PP)
64 void TIMER2(void)
66 TIMER2_VAL; /* ACK interrupt */
67 if (cycles_new > 0)
69 TIMER2_CFG = 0xc0000000 | (cycles_new - 1);
70 cycles_new = 0;
72 if (pfn_timer != NULL)
74 cycles_new = -1;
75 /* "lock" the variable, in case timer_set_period()
76 * is called within pfn_timer() */
77 pfn_timer();
78 cycles_new = 0;
81 #elif CONFIG_CPU == PNX0101
82 void TIMER1_ISR(void)
84 if (cycles_new > 0)
86 TIMER1.load = cycles_new - 1;
87 cycles_new = 0;
89 if (pfn_timer != NULL)
91 cycles_new = -1;
92 /* "lock" the variable, in case timer_set_period()
93 * is called within pfn_timer() */
94 pfn_timer();
95 cycles_new = 0;
97 TIMER1.clr = 1; /* clear the interrupt */
99 #endif /* CONFIG_CPU */
101 static bool timer_set(long cycles, bool start)
103 #if CONFIG_CPU == SH7034 || defined(CPU_COLDFIRE) || CONFIG_CPU == AS3525
104 int phi = 0; /* bits for the prescaler */
105 int prescale = 1;
107 #if CONFIG_CPU == SH7034 || defined(CPU_COLDFIRE)
108 #define PRESCALE_STEP 1
109 #else /* CONFIG_CPU == AS3525 */
110 #define PRESCALE_STEP 4
111 #endif
113 while (cycles > 0x10000)
114 { /* work out the smallest prescaler that makes it fit */
115 #if CONFIG_CPU == SH7034 || CONFIG_CPU == AS3525
116 phi++;
117 #endif
118 prescale <<= PRESCALE_STEP;
119 cycles >>= PRESCALE_STEP;
121 #endif
123 #if CONFIG_CPU == PNX0101
124 if (start)
126 if (pfn_unregister != NULL)
128 pfn_unregister();
129 pfn_unregister = NULL;
131 TIMER1.ctrl &= ~0x80; /* disable the counter */
132 TIMER1.ctrl |= 0x40; /* reload after counting down to zero */
133 TIMER1.ctrl &= ~0xc; /* no prescaler */
134 TIMER1.clr = 1; /* clear an interrupt event */
136 if (start || (cycles_new == -1)) /* within isr, cycles_new is "locked" */
137 { /* enable timer */
138 TIMER1.load = cycles - 1;
139 TIMER1.ctrl |= 0x80; /* enable the counter */
141 else
142 cycles_new = cycles;
144 return true;
145 #elif CONFIG_CPU == SH7034
146 if (prescale > 8)
147 return false;
149 if (start)
151 if (pfn_unregister != NULL)
153 pfn_unregister();
154 pfn_unregister = NULL;
157 and_b(~0x10, &TSTR); /* Stop the timer 4 */
158 and_b(~0x10, &TSNC); /* No synchronization */
159 and_b(~0x10, &TMDR); /* Operate normally */
161 TIER4 = 0xF9; /* Enable GRA match interrupt */
164 TCR4 = 0x20 | phi; /* clear at GRA match, set prescaler */
165 GRA4 = (unsigned short)(cycles - 1);
166 if (start || (TCNT4 >= GRA4))
167 TCNT4 = 0;
168 and_b(~0x01, &TSR4); /* clear an eventual interrupt */
170 return true;
171 #elif CONFIG_CPU == AS3525
172 /* XXX: 32 bits cycles could be used */
173 if (prescale > 256 || cycles > 0x10000)
174 return false;
176 if (start)
178 if (pfn_unregister != NULL)
180 pfn_unregister();
181 pfn_unregister = NULL;
185 TIMER1_LOAD = TIMER1_BGLOAD = cycles;
186 /* /!\ bit 4 (reserved) must not be modified
187 * periodic mode, interrupt enabled, 16 bits counter */
188 TIMER1_CONTROL = (TIMER1_CONTROL & (1<<4)) | 0xe0 | (phi<<2);
189 return true;
190 #elif defined CPU_COLDFIRE
191 if (prescale > 4096/CPUFREQ_MAX_MULT)
192 return false;
194 if (prescale > 256/CPUFREQ_MAX_MULT)
196 phi = 0x05; /* prescale sysclk/16, timer enabled */
197 prescale >>= 4;
199 else
200 phi = 0x03; /* prescale sysclk, timer enabled */
202 base_prescale = prescale;
203 prescale *= (cpu_frequency / CPU_FREQ);
205 if (start)
207 if (pfn_unregister != NULL)
209 pfn_unregister();
210 pfn_unregister = NULL;
212 phi &= ~1; /* timer disabled at start */
214 /* If it is already enabled, writing a 0 to the RST bit will clear
215 the register, so we clear RST explicitly before writing the real
216 data. */
217 TMR1 = 0;
220 /* We are using timer 1 */
221 TMR1 = 0x0018 | (unsigned short)phi | ((unsigned short)(prescale - 1) << 8);
222 TRR1 = (unsigned short)(cycles - 1);
223 if (start || (TCN1 >= TRR1))
224 TCN1 = 0; /* reset the timer */
225 TER1 = 0xff; /* clear all events */
227 return true;
228 #elif defined(CPU_PP)
229 if (cycles > 0x20000000 || cycles < 2)
230 return false;
232 if (start)
234 if (pfn_unregister != NULL)
236 pfn_unregister();
237 pfn_unregister = NULL;
239 CPU_INT_DIS = TIMER2_MASK;
240 COP_INT_DIS = TIMER2_MASK;
242 if (start || (cycles_new == -1)) /* within isr, cycles_new is "locked" */
243 TIMER2_CFG = 0xc0000000 | (cycles - 1); /* enable timer */
244 else
245 cycles_new = cycles;
247 return true;
248 #elif (CONFIG_CPU == IMX31L)
249 /* TODO */
250 (void)cycles; (void)start;
251 return false;
252 #else
253 return __TIMER_SET(cycles, start);
254 #endif /* CONFIG_CPU */
257 #ifdef CPU_COLDFIRE
258 void timers_adjust_prescale(int multiplier, bool enable_irq)
260 /* tick timer */
261 TMR0 = (TMR0 & 0x00ef)
262 | ((unsigned short)(multiplier - 1) << 8)
263 | (enable_irq ? 0x10 : 0);
265 if (pfn_timer)
267 /* user timer */
268 int prescale = base_prescale * multiplier;
269 TMR1 = (TMR1 & 0x00ef)
270 | ((unsigned short)(prescale - 1) << 8)
271 | (enable_irq ? 0x10 : 0);
274 #endif
276 /* Register a user timer, called every <cycles> TIMER_FREQ cycles */
277 bool timer_register(int reg_prio, void (*unregister_callback)(void),
278 long cycles, int int_prio, void (*timer_callback)(void)
279 IF_COP(, int core))
281 if (reg_prio <= timer_prio || cycles == 0)
282 return false;
284 #if CONFIG_CPU == SH7034
285 if (int_prio < 1 || int_prio > 15)
286 return false;
287 #endif
289 if (!timer_set(cycles, true))
290 return false;
292 pfn_timer = timer_callback;
293 pfn_unregister = unregister_callback;
294 timer_prio = reg_prio;
296 #if CONFIG_CPU == SH7034
297 IPRD = (IPRD & 0xFF0F) | int_prio << 4; /* interrupt priority */
298 or_b(0x10, &TSTR); /* start timer 4 */
299 return true;
300 #elif defined CPU_COLDFIRE
301 ICR2 = 0x90; /* interrupt on level 4.0 */
302 and_l(~(1<<10), &IMR);
303 TMR1 |= 1; /* start timer */
304 return true;
305 #elif defined(CPU_PP)
306 /* unmask interrupt source */
307 #if NUM_CORES > 1
308 if (core == COP)
309 COP_INT_EN = TIMER2_MASK;
310 else
311 #endif
312 CPU_INT_EN = TIMER2_MASK;
313 return true;
314 #elif CONFIG_CPU == PNX0101
315 irq_set_int_handler(IRQ_TIMER1, TIMER1_ISR);
316 irq_enable_int(IRQ_TIMER1);
317 return true;
318 #elif CONFIG_CPU == AS3525
319 CGU_PERI |= CGU_TIMER1_CLOCK_ENABLE; /* enable peripheral */
320 VIC_INT_ENABLE |= INTERRUPT_TIMER1;
321 return true;
322 #elif CONFIG_CPU == IMX31L
323 /* TODO */
324 return false;
325 #else
326 return __TIMER_REGISTER(reg_prio, unregister_callback, cycles,
327 int_prio, timer_callback);
328 #endif
329 /* Cover for targets that don't use all these */
330 (void)reg_prio;
331 (void)unregister_callback;
332 (void)cycles;
333 /* TODO: Implement for PortalPlayer and iFP (if possible) */
334 (void)int_prio;
335 (void)timer_callback;
338 bool timer_set_period(long cycles)
340 return timer_set(cycles, false);
343 void timer_unregister(void)
345 #if CONFIG_CPU == SH7034
346 and_b(~0x10, &TSTR); /* stop the timer 4 */
347 IPRD = (IPRD & 0xFF0F); /* disable interrupt */
348 #elif defined CPU_COLDFIRE
349 TMR1 = 0; /* disable timer 1 */
350 or_l((1<<10), &IMR); /* disable interrupt */
351 #elif defined(CPU_PP)
352 TIMER2_CFG = 0; /* stop timer 2 */
353 CPU_INT_DIS = TIMER2_MASK;
354 COP_INT_DIS = TIMER2_MASK;
355 #elif CONFIG_CPU == PNX0101
356 TIMER1.ctrl &= ~0x80; /* disable timer 1 */
357 irq_disable_int(IRQ_TIMER1);
358 #elif CONFIG_CPU == AS3525
359 TIMER1_CONTROL &= 0x10; /* disable timer 1 (don't modify bit 4) */
360 VIC_INT_EN_CLEAR = INTERRUPT_TIMER1; /* disable interrupt */
361 CGU_PERI &= ~CGU_TIMER1_CLOCK_ENABLE; /* disable peripheral */
362 #elif CONFIG_CPU == S3C2440 || CONFIG_CPU == DM320
363 __TIMER_UNREGISTER();
364 #endif
365 pfn_timer = NULL;
366 pfn_unregister = NULL;
367 timer_prio = -1;