1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2005 Jens Arnold
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
27 static int timer_prio
= -1;
28 void (*pfn_timer
)(void) = NULL
; /* timer callback */
29 void (*pfn_unregister
)(void) = NULL
; /* unregister callback */
31 static int base_prescale
;
32 #elif defined CPU_PP || CONFIG_CPU == PNX0101
33 static long cycles_new
= 0;
36 /* interrupt handler */
37 #if CONFIG_CPU == SH7034
38 void IMIA4(void) __attribute__((interrupt_handler
));
41 if (pfn_timer
!= NULL
)
43 and_b(~0x01, &TSR4
); /* clear the interrupt */
45 #elif defined CPU_COLDFIRE
46 void TIMER1(void) __attribute__ ((interrupt_handler
));
49 if (pfn_timer
!= NULL
)
51 TER1
= 0xff; /* clear all events */
56 TIMER2_VAL
; /* ACK interrupt */
59 TIMER2_CFG
= 0xc0000000 | (cycles_new
- 1);
62 if (pfn_timer
!= NULL
)
65 /* "lock" the variable, in case timer_set_period()
66 * is called within pfn_timer() */
71 #elif CONFIG_CPU == PNX0101
76 TIMER1
.load
= cycles_new
- 1;
79 if (pfn_timer
!= NULL
)
82 /* "lock" the variable, in case timer_set_period()
83 * is called within pfn_timer() */
87 TIMER1
.clr
= 1; /* clear the interrupt */
89 #endif /* CONFIG_CPU */
91 static bool timer_set(long cycles
, bool start
)
93 #if (CONFIG_CPU == SH7034) || defined(CPU_COLDFIRE)
94 int phi
= 0; /* bits for the prescaler */
97 while (cycles
> 0x10000)
98 { /* work out the smallest prescaler that makes it fit */
99 #if CONFIG_CPU == SH7034
107 #if CONFIG_CPU == PNX0101
110 if (pfn_unregister
!= NULL
)
113 pfn_unregister
= NULL
;
115 TIMER1
.ctrl
&= ~0x80; /* disable the counter */
116 TIMER1
.ctrl
|= 0x40; /* reload after counting down to zero */
117 TIMER1
.ctrl
&= ~0xc; /* no prescaler */
118 TIMER1
.clr
= 1; /* clear an interrupt event */
120 if (start
|| (cycles_new
== -1)) /* within isr, cycles_new is "locked" */
122 TIMER1
.load
= cycles
- 1;
123 TIMER1
.ctrl
|= 0x80; /* enable the counter */
129 #elif CONFIG_CPU == SH7034
135 if (pfn_unregister
!= NULL
)
138 pfn_unregister
= NULL
;
141 and_b(~0x10, &TSTR
); /* Stop the timer 4 */
142 and_b(~0x10, &TSNC
); /* No synchronization */
143 and_b(~0x10, &TMDR
); /* Operate normally */
145 TIER4
= 0xF9; /* Enable GRA match interrupt */
148 TCR4
= 0x20 | phi
; /* clear at GRA match, set prescaler */
149 GRA4
= (unsigned short)(cycles
- 1);
150 if (start
|| (TCNT4
>= GRA4
))
152 and_b(~0x01, &TSR4
); /* clear an eventual interrupt */
155 #elif defined CPU_COLDFIRE
156 if (prescale
> 4096/CPUFREQ_MAX_MULT
)
159 if (prescale
> 256/CPUFREQ_MAX_MULT
)
161 phi
= 0x05; /* prescale sysclk/16, timer enabled */
165 phi
= 0x03; /* prescale sysclk, timer enabled */
167 base_prescale
= prescale
;
168 prescale
*= (cpu_frequency
/ CPU_FREQ
);
172 if (pfn_unregister
!= NULL
)
175 pfn_unregister
= NULL
;
177 phi
&= ~1; /* timer disabled at start */
179 /* If it is already enabled, writing a 0 to the RST bit will clear
180 the register, so we clear RST explicitly before writing the real
185 /* We are using timer 1 */
186 TMR1
= 0x0018 | (unsigned short)phi
| ((unsigned short)(prescale
- 1) << 8);
187 TRR1
= (unsigned short)(cycles
- 1);
188 if (start
|| (TCN1
>= TRR1
))
189 TCN1
= 0; /* reset the timer */
190 TER1
= 0xff; /* clear all events */
193 #elif defined(CPU_PP)
194 if (cycles
> 0x20000000 || cycles
< 2)
199 if (pfn_unregister
!= NULL
)
202 pfn_unregister
= NULL
;
205 if (start
|| (cycles_new
== -1)) /* within isr, cycles_new is "locked" */
206 TIMER2_CFG
= 0xc0000000 | (cycles
- 1); /* enable timer */
211 #elif (CONFIG_CPU == IMX31L)
214 return __TIMER_SET(cycles
, start
);
215 #endif /* CONFIG_CPU */
219 void timers_adjust_prescale(int multiplier
, bool enable_irq
)
222 TMR0
= (TMR0
& 0x00ef)
223 | ((unsigned short)(multiplier
- 1) << 8)
224 | (enable_irq
? 0x10 : 0);
229 int prescale
= base_prescale
* multiplier
;
230 TMR1
= (TMR1
& 0x00ef)
231 | ((unsigned short)(prescale
- 1) << 8)
232 | (enable_irq
? 0x10 : 0);
237 /* Register a user timer, called every <cycles> TIMER_FREQ cycles */
238 bool timer_register(int reg_prio
, void (*unregister_callback
)(void),
239 long cycles
, int int_prio
, void (*timer_callback
)(void))
241 if (reg_prio
<= timer_prio
|| cycles
== 0)
244 #if CONFIG_CPU == SH7034
245 if (int_prio
< 1 || int_prio
> 15)
249 if (!timer_set(cycles
, true))
252 pfn_timer
= timer_callback
;
253 pfn_unregister
= unregister_callback
;
254 timer_prio
= reg_prio
;
256 #if CONFIG_CPU == SH7034
257 IPRD
= (IPRD
& 0xFF0F) | int_prio
<< 4; /* interrupt priority */
258 or_b(0x10, &TSTR
); /* start timer 4 */
260 #elif defined CPU_COLDFIRE
261 ICR2
= 0x90; /* interrupt on level 4.0 */
262 and_l(~(1<<10), &IMR
);
263 TMR1
|= 1; /* start timer */
265 #elif defined(CPU_PP)
266 /* unmask interrupt source */
267 CPU_INT_EN
= TIMER2_MASK
;
269 #elif CONFIG_CPU == PNX0101
270 irq_set_int_handler(IRQ_TIMER1
, TIMER1_ISR
);
271 irq_enable_int(IRQ_TIMER1
);
273 #elif CONFIG_CPU == IMX31L
276 return __TIMER_REGISTER(reg_prio
, unregister_callback
, cycles
,
277 int_prio
, timer_callback
);
279 /* Cover for targets that don't use all these */
281 (void)unregister_callback
;
283 /* TODO: Implement for PortalPlayer and iFP (if possible) */
285 (void)timer_callback
;
288 bool timer_set_period(long cycles
)
290 return timer_set(cycles
, false);
293 void timer_unregister(void)
295 #if CONFIG_CPU == SH7034
296 and_b(~0x10, &TSTR
); /* stop the timer 4 */
297 IPRD
= (IPRD
& 0xFF0F); /* disable interrupt */
298 #elif defined CPU_COLDFIRE
299 TMR1
= 0; /* disable timer 1 */
300 or_l((1<<10), &IMR
); /* disable interrupt */
301 #elif defined(CPU_PP)
302 TIMER2_CFG
= 0; /* stop timer 2 */
303 CPU_INT_CLR
= TIMER2_MASK
;
304 #elif CONFIG_CPU == PNX0101
305 TIMER1
.ctrl
&= ~0x80; /* disable timer 1 */
306 irq_disable_int(IRQ_TIMER1
);
307 #elif CONFIG_CPU == S3C2440
308 __TIMER_UNREGISTER();
311 pfn_unregister
= NULL
;