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) || CONFIG_CPU == AS3525
113 int phi
= 0; /* bits for the prescaler */
116 #if CONFIG_CPU == SH7034 || defined(CPU_COLDFIRE)
117 #define PRESCALE_STEP 1
118 #else /* CONFIG_CPU == AS3525 */
119 #define PRESCALE_STEP 4
122 while (cycles
> 0x10000)
123 { /* work out the smallest prescaler that makes it fit */
124 #if CONFIG_CPU == SH7034 || CONFIG_CPU == AS3525
127 prescale
<<= PRESCALE_STEP
;
128 cycles
>>= PRESCALE_STEP
;
132 #if CONFIG_CPU == PNX0101
135 if (pfn_unregister
!= NULL
)
138 pfn_unregister
= NULL
;
140 TIMER1
.ctrl
&= ~0x80; /* disable the counter */
141 TIMER1
.ctrl
|= 0x40; /* reload after counting down to zero */
142 TIMER1
.ctrl
&= ~0xc; /* no prescaler */
143 TIMER1
.clr
= 1; /* clear an interrupt event */
145 if (start
|| (cycles_new
== -1)) /* within isr, cycles_new is "locked" */
147 TIMER1
.load
= cycles
- 1;
148 TIMER1
.ctrl
|= 0x80; /* enable the counter */
154 #elif CONFIG_CPU == SH7034
160 if (pfn_unregister
!= NULL
)
163 pfn_unregister
= NULL
;
166 and_b(~0x10, &TSTR
); /* Stop the timer 4 */
167 and_b(~0x10, &TSNC
); /* No synchronization */
168 and_b(~0x10, &TMDR
); /* Operate normally */
170 TIER4
= 0xF9; /* Enable GRA match interrupt */
173 TCR4
= 0x20 | phi
; /* clear at GRA match, set prescaler */
174 GRA4
= (unsigned short)(cycles
- 1);
175 if (start
|| (TCNT4
>= GRA4
))
177 and_b(~0x01, &TSR4
); /* clear an eventual interrupt */
180 #elif CONFIG_CPU == AS3525
181 /* XXX: 32 bits cycles could be used */
182 if (prescale
> 256 || cycles
> 0x10000)
187 if (pfn_unregister
!= NULL
)
190 pfn_unregister
= NULL
;
194 TIMER1_LOAD
= TIMER1_BGLOAD
= cycles
;
195 /* /!\ bit 4 (reserved) must not be modified
196 * periodic mode, interrupt enabled, 16 bits counter */
197 TIMER1_CONTROL
= (TIMER1_CONTROL
& (1<<4)) | 0xe0 | (phi
<<2);
199 #elif defined CPU_COLDFIRE
200 if (prescale
> 4096/CPUFREQ_MAX_MULT
)
203 if (prescale
> 256/CPUFREQ_MAX_MULT
)
205 phi
= 0x05; /* prescale sysclk/16, timer enabled */
209 phi
= 0x03; /* prescale sysclk, timer enabled */
211 base_prescale
= prescale
;
212 prescale
*= (cpu_frequency
/ CPU_FREQ
);
216 if (pfn_unregister
!= NULL
)
219 pfn_unregister
= NULL
;
221 phi
&= ~1; /* timer disabled at start */
223 /* If it is already enabled, writing a 0 to the RST bit will clear
224 the register, so we clear RST explicitly before writing the real
229 /* We are using timer 1 */
230 TMR1
= 0x0018 | (unsigned short)phi
| ((unsigned short)(prescale
- 1) << 8);
231 TRR1
= (unsigned short)(cycles
- 1);
232 if (start
|| (TCN1
>= TRR1
))
233 TCN1
= 0; /* reset the timer */
234 TER1
= 0xff; /* clear all events */
237 #elif defined(CPU_PP)
238 if (cycles
> 0x20000000 || cycles
< 2)
243 if (pfn_unregister
!= NULL
)
246 pfn_unregister
= NULL
;
248 CPU_INT_DIS
= TIMER2_MASK
;
249 COP_INT_DIS
= TIMER2_MASK
;
251 if (start
|| (cycles_new
== -1)) /* within isr, cycles_new is "locked" */
252 TIMER2_CFG
= 0xc0000000 | (cycles
- 1); /* enable timer */
258 return __TIMER_SET(cycles
, start
);
259 #endif /* CONFIG_CPU */
263 void timers_adjust_prescale(int multiplier
, bool enable_irq
)
266 TMR0
= (TMR0
& 0x00ef)
267 | ((unsigned short)(multiplier
- 1) << 8)
268 | (enable_irq
? 0x10 : 0);
273 int prescale
= base_prescale
* multiplier
;
274 TMR1
= (TMR1
& 0x00ef)
275 | ((unsigned short)(prescale
- 1) << 8)
276 | (enable_irq
? 0x10 : 0);
281 /* Register a user timer, called every <cycles> TIMER_FREQ cycles */
282 bool timer_register(int reg_prio
, void (*unregister_callback
)(void),
283 long cycles
, int int_prio
, void (*timer_callback
)(void)
286 if (reg_prio
<= timer_prio
|| cycles
== 0)
289 #if CONFIG_CPU == SH7034
290 if (int_prio
< 1 || int_prio
> 15)
294 if (!timer_set(cycles
, true))
297 pfn_timer
= timer_callback
;
298 pfn_unregister
= unregister_callback
;
299 timer_prio
= reg_prio
;
301 #if CONFIG_CPU == SH7034
302 IPRD
= (IPRD
& 0xFF0F) | int_prio
<< 4; /* interrupt priority */
303 or_b(0x10, &TSTR
); /* start timer 4 */
305 #elif defined CPU_COLDFIRE
306 ICR2
= 0x90; /* interrupt on level 4.0 */
307 and_l(~(1<<10), &IMR
);
308 TMR1
|= 1; /* start timer */
310 #elif defined(CPU_PP)
311 /* unmask interrupt source */
314 COP_INT_EN
= TIMER2_MASK
;
317 CPU_INT_EN
= TIMER2_MASK
;
319 #elif CONFIG_CPU == PNX0101
320 irq_set_int_handler(IRQ_TIMER1
, TIMER1_ISR
);
321 irq_enable_int(IRQ_TIMER1
);
323 #elif CONFIG_CPU == AS3525
324 CGU_PERI
|= CGU_TIMER1_CLOCK_ENABLE
; /* enable peripheral */
325 VIC_INT_ENABLE
|= INTERRUPT_TIMER1
;
328 return __TIMER_REGISTER(reg_prio
, unregister_callback
, cycles
,
329 int_prio
, timer_callback
);
331 /* Cover for targets that don't use all these */
333 (void)unregister_callback
;
335 /* TODO: Implement for PortalPlayer and iFP (if possible) */
337 (void)timer_callback
;
340 bool timer_set_period(long cycles
)
342 return timer_set(cycles
, false);
345 void timer_unregister(void)
347 #if CONFIG_CPU == SH7034
348 and_b(~0x10, &TSTR
); /* stop the timer 4 */
349 IPRD
= (IPRD
& 0xFF0F); /* disable interrupt */
350 #elif defined CPU_COLDFIRE
351 TMR1
= 0; /* disable timer 1 */
352 or_l((1<<10), &IMR
); /* disable interrupt */
353 #elif defined(CPU_PP)
354 TIMER2_CFG
= 0; /* stop timer 2 */
355 CPU_INT_DIS
= TIMER2_MASK
;
356 COP_INT_DIS
= TIMER2_MASK
;
357 #elif CONFIG_CPU == PNX0101
358 TIMER1
.ctrl
&= ~0x80; /* disable timer 1 */
359 irq_disable_int(IRQ_TIMER1
);
360 #elif CONFIG_CPU == AS3525
361 TIMER1_CONTROL
&= 0x10; /* disable timer 1 (don't modify bit 4) */
362 VIC_INT_EN_CLEAR
= INTERRUPT_TIMER1
; /* disable interrupt */
363 CGU_PERI
&= ~CGU_TIMER1_CLOCK_ENABLE
; /* disable peripheral */
365 __TIMER_UNREGISTER();
368 pfn_unregister
= NULL
;