1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
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 */
33 static int base_prescale
;
34 #elif defined CPU_PP || CONFIG_CPU == PNX0101
35 static long SHAREDBSS_ATTR cycles_new
= 0;
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(...)
47 /* interrupt handler */
48 #if CONFIG_CPU == SH7034
49 void IMIA4(void) __attribute__((interrupt_handler
));
52 if (pfn_timer
!= NULL
)
54 and_b(~0x01, &TSR4
); /* clear the interrupt */
56 #elif defined CPU_COLDFIRE
57 void TIMER1(void) __attribute__ ((interrupt_handler
));
60 if (pfn_timer
!= NULL
)
62 TER1
= 0xff; /* clear all events */
64 #elif CONFIG_CPU == AS3525
67 if (pfn_timer
!= NULL
)
70 TIMER1_INTCLR
= 0; /* clear interrupt */
75 TIMER2_VAL
; /* ACK interrupt */
78 TIMER2_CFG
= 0xc0000000 | (cycles_new
- 1);
81 if (pfn_timer
!= NULL
)
84 /* "lock" the variable, in case timer_set_period()
85 * is called within pfn_timer() */
90 #elif CONFIG_CPU == PNX0101
95 TIMER1
.load
= cycles_new
- 1;
98 if (pfn_timer
!= NULL
)
101 /* "lock" the variable, in case timer_set_period()
102 * is called within pfn_timer() */
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 */
116 while (cycles
> 0x10000)
117 { /* work out the smallest prescaler that makes it fit */
118 #if CONFIG_CPU == SH7034
126 #if CONFIG_CPU == PNX0101
129 if (pfn_unregister
!= NULL
)
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" */
141 TIMER1
.load
= cycles
- 1;
142 TIMER1
.ctrl
|= 0x80; /* enable the counter */
148 #elif CONFIG_CPU == SH7034
154 if (pfn_unregister
!= NULL
)
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
))
171 and_b(~0x01, &TSR4
); /* clear an eventual interrupt */
174 #elif CONFIG_CPU == AS3525
177 if (pfn_unregister
!= NULL
)
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)) |
193 #elif defined CPU_COLDFIRE
194 if (prescale
> 4096/CPUFREQ_MAX_MULT
)
197 if (prescale
> 256/CPUFREQ_MAX_MULT
)
199 phi
= 0x05; /* prescale sysclk/16, timer enabled */
203 phi
= 0x03; /* prescale sysclk, timer enabled */
205 base_prescale
= prescale
;
206 prescale
*= (cpu_frequency
/ CPU_FREQ
);
210 if (pfn_unregister
!= NULL
)
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
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 */
231 #elif defined(CPU_PP)
232 if (cycles
> 0x20000000 || cycles
< 2)
237 if (pfn_unregister
!= NULL
)
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 */
252 return __TIMER_SET(cycles
, start
);
253 #endif /* CONFIG_CPU */
257 void timers_adjust_prescale(int multiplier
, bool enable_irq
)
260 TMR0
= (TMR0
& 0x00ef)
261 | ((unsigned short)(multiplier
- 1) << 8)
262 | (enable_irq
? 0x10 : 0);
267 int prescale
= base_prescale
* multiplier
;
268 TMR1
= (TMR1
& 0x00ef)
269 | ((unsigned short)(prescale
- 1) << 8)
270 | (enable_irq
? 0x10 : 0);
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)
280 if (reg_prio
<= timer_prio
|| cycles
== 0)
283 #if CONFIG_CPU == SH7034
284 if (int_prio
< 1 || int_prio
> 15)
288 if (!timer_set(cycles
, true))
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 */
299 #elif defined CPU_COLDFIRE
300 ICR2
= 0x90; /* interrupt on level 4.0 */
301 and_l(~(1<<10), &IMR
);
302 TMR1
|= 1; /* start timer */
304 #elif defined(CPU_PP)
305 /* unmask interrupt source */
308 COP_INT_EN
= TIMER2_MASK
;
311 CPU_INT_EN
= TIMER2_MASK
;
313 #elif CONFIG_CPU == PNX0101
314 irq_set_int_handler(IRQ_TIMER1
, TIMER1_ISR
);
315 irq_enable_int(IRQ_TIMER1
);
317 #elif CONFIG_CPU == AS3525
318 CGU_PERI
|= CGU_TIMER1_CLOCK_ENABLE
; /* enable peripheral */
319 VIC_INT_ENABLE
|= INTERRUPT_TIMER1
;
322 return __TIMER_REGISTER(reg_prio
, unregister_callback
, cycles
,
323 int_prio
, timer_callback
);
325 /* Cover for targets that don't use all these */
327 (void)unregister_callback
;
329 /* TODO: Implement for PortalPlayer and iFP (if possible) */
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 */
359 __TIMER_UNREGISTER();
362 pfn_unregister
= NULL
;