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;
38 /* interrupt handler */
39 #if CONFIG_CPU == SH7034
40 void IMIA4(void) __attribute__((interrupt_handler
));
43 if (pfn_timer
!= NULL
)
45 and_b(~0x01, &TSR4
); /* clear the interrupt */
47 #elif defined CPU_COLDFIRE
48 void TIMER1(void) __attribute__ ((interrupt_handler
));
51 if (pfn_timer
!= NULL
)
53 TER1
= 0xff; /* clear all events */
58 TIMER2_VAL
; /* ACK interrupt */
61 TIMER2_CFG
= 0xc0000000 | (cycles_new
- 1);
64 if (pfn_timer
!= NULL
)
67 /* "lock" the variable, in case timer_set_period()
68 * is called within pfn_timer() */
73 #elif CONFIG_CPU == PNX0101
78 TIMER1
.load
= cycles_new
- 1;
81 if (pfn_timer
!= NULL
)
84 /* "lock" the variable, in case timer_set_period()
85 * is called within pfn_timer() */
89 TIMER1
.clr
= 1; /* clear the interrupt */
91 #endif /* CONFIG_CPU */
93 static bool timer_set(long cycles
, bool start
)
95 #if (CONFIG_CPU == SH7034) || defined(CPU_COLDFIRE)
96 int phi
= 0; /* bits for the prescaler */
99 while (cycles
> 0x10000)
100 { /* work out the smallest prescaler that makes it fit */
101 #if CONFIG_CPU == SH7034
109 #if CONFIG_CPU == PNX0101
112 if (pfn_unregister
!= NULL
)
115 pfn_unregister
= NULL
;
117 TIMER1
.ctrl
&= ~0x80; /* disable the counter */
118 TIMER1
.ctrl
|= 0x40; /* reload after counting down to zero */
119 TIMER1
.ctrl
&= ~0xc; /* no prescaler */
120 TIMER1
.clr
= 1; /* clear an interrupt event */
122 if (start
|| (cycles_new
== -1)) /* within isr, cycles_new is "locked" */
124 TIMER1
.load
= cycles
- 1;
125 TIMER1
.ctrl
|= 0x80; /* enable the counter */
131 #elif CONFIG_CPU == SH7034
137 if (pfn_unregister
!= NULL
)
140 pfn_unregister
= NULL
;
143 and_b(~0x10, &TSTR
); /* Stop the timer 4 */
144 and_b(~0x10, &TSNC
); /* No synchronization */
145 and_b(~0x10, &TMDR
); /* Operate normally */
147 TIER4
= 0xF9; /* Enable GRA match interrupt */
150 TCR4
= 0x20 | phi
; /* clear at GRA match, set prescaler */
151 GRA4
= (unsigned short)(cycles
- 1);
152 if (start
|| (TCNT4
>= GRA4
))
154 and_b(~0x01, &TSR4
); /* clear an eventual interrupt */
157 #elif defined CPU_COLDFIRE
158 if (prescale
> 4096/CPUFREQ_MAX_MULT
)
161 if (prescale
> 256/CPUFREQ_MAX_MULT
)
163 phi
= 0x05; /* prescale sysclk/16, timer enabled */
167 phi
= 0x03; /* prescale sysclk, timer enabled */
169 base_prescale
= prescale
;
170 prescale
*= (cpu_frequency
/ CPU_FREQ
);
174 if (pfn_unregister
!= NULL
)
177 pfn_unregister
= NULL
;
179 phi
&= ~1; /* timer disabled at start */
181 /* If it is already enabled, writing a 0 to the RST bit will clear
182 the register, so we clear RST explicitly before writing the real
187 /* We are using timer 1 */
188 TMR1
= 0x0018 | (unsigned short)phi
| ((unsigned short)(prescale
- 1) << 8);
189 TRR1
= (unsigned short)(cycles
- 1);
190 if (start
|| (TCN1
>= TRR1
))
191 TCN1
= 0; /* reset the timer */
192 TER1
= 0xff; /* clear all events */
195 #elif defined(CPU_PP)
196 if (cycles
> 0x20000000 || cycles
< 2)
201 if (pfn_unregister
!= NULL
)
204 pfn_unregister
= NULL
;
206 CPU_INT_DIS
= TIMER2_MASK
;
207 COP_INT_DIS
= TIMER2_MASK
;
209 if (start
|| (cycles_new
== -1)) /* within isr, cycles_new is "locked" */
210 TIMER2_CFG
= 0xc0000000 | (cycles
- 1); /* enable timer */
215 #elif (CONFIG_CPU == IMX31L)
217 (void)cycles
; (void)start
;
220 return __TIMER_SET(cycles
, start
);
221 #endif /* CONFIG_CPU */
225 void timers_adjust_prescale(int multiplier
, bool enable_irq
)
228 TMR0
= (TMR0
& 0x00ef)
229 | ((unsigned short)(multiplier
- 1) << 8)
230 | (enable_irq
? 0x10 : 0);
235 int prescale
= base_prescale
* multiplier
;
236 TMR1
= (TMR1
& 0x00ef)
237 | ((unsigned short)(prescale
- 1) << 8)
238 | (enable_irq
? 0x10 : 0);
243 /* Register a user timer, called every <cycles> TIMER_FREQ cycles */
244 bool timer_register(int reg_prio
, void (*unregister_callback
)(void),
245 long cycles
, int int_prio
, void (*timer_callback
)(void)
248 if (reg_prio
<= timer_prio
|| cycles
== 0)
251 #if CONFIG_CPU == SH7034
252 if (int_prio
< 1 || int_prio
> 15)
256 if (!timer_set(cycles
, true))
259 pfn_timer
= timer_callback
;
260 pfn_unregister
= unregister_callback
;
261 timer_prio
= reg_prio
;
263 #if CONFIG_CPU == SH7034
264 IPRD
= (IPRD
& 0xFF0F) | int_prio
<< 4; /* interrupt priority */
265 or_b(0x10, &TSTR
); /* start timer 4 */
267 #elif defined CPU_COLDFIRE
268 ICR2
= 0x90; /* interrupt on level 4.0 */
269 and_l(~(1<<10), &IMR
);
270 TMR1
|= 1; /* start timer */
272 #elif defined(CPU_PP)
273 /* unmask interrupt source */
276 COP_INT_EN
= TIMER2_MASK
;
279 CPU_INT_EN
= TIMER2_MASK
;
281 #elif CONFIG_CPU == PNX0101
282 irq_set_int_handler(IRQ_TIMER1
, TIMER1_ISR
);
283 irq_enable_int(IRQ_TIMER1
);
285 #elif CONFIG_CPU == IMX31L
289 return __TIMER_REGISTER(reg_prio
, unregister_callback
, cycles
,
290 int_prio
, timer_callback
);
292 /* Cover for targets that don't use all these */
294 (void)unregister_callback
;
296 /* TODO: Implement for PortalPlayer and iFP (if possible) */
298 (void)timer_callback
;
301 bool timer_set_period(long cycles
)
303 return timer_set(cycles
, false);
306 void timer_unregister(void)
308 #if CONFIG_CPU == SH7034
309 and_b(~0x10, &TSTR
); /* stop the timer 4 */
310 IPRD
= (IPRD
& 0xFF0F); /* disable interrupt */
311 #elif defined CPU_COLDFIRE
312 TMR1
= 0; /* disable timer 1 */
313 or_l((1<<10), &IMR
); /* disable interrupt */
314 #elif defined(CPU_PP)
315 TIMER2_CFG
= 0; /* stop timer 2 */
316 CPU_INT_DIS
= TIMER2_MASK
;
317 COP_INT_DIS
= TIMER2_MASK
;
318 #elif CONFIG_CPU == PNX0101
319 TIMER1
.ctrl
&= ~0x80; /* disable timer 1 */
320 irq_disable_int(IRQ_TIMER1
);
321 #elif CONFIG_CPU == S3C2440 || CONFIG_CPU == DM320
322 __TIMER_UNREGISTER();
325 pfn_unregister
= NULL
;