1 /*
2 * Copyright (C) 2004 by Green Hills Software,Inc.
3 *
4 * This program is the property of Green Hills Software, Inc,
5 * its contents are proprietary information and no part of it
6 * is to be disclosed to anyone except employees of Green Hills
7 * Software, Inc., or as agreed in writing signed by the President
8 * of Green Hills Software, Inc.
9 */
10 /***
11 * ColdFire timer support.
12 * Set SYSTEM_CLOCK to the appropriate value.
13 * Check that the memory mapped register positions are correct
14 * for your board.
15 * If your code makes use of MBAR or ACR0, modify the TIMER_INIT
16 * code appropriately.
17 * Make sure no other interrupts use the same priority and level
18 * as the timer interrupt.
19 *
20 * Recompile libsys with the appropriate cpu selected.
21 */
22 #define MBARx 0x10000000
23
24 /*
25 M5407C3 50Mhz
26 M5307C3 45Mhz
27 M5272C3 66Mhz
28 M5249C3 70Mhz
29 */
30 #define SYSTEM_CLOCK (50000000) /* 50Mhz timer clock */
31
32
33 #if defined(__MCF5407) || defined(__MCF5307)
34
35 #define TIMER0 (MBARx+0x140) /* timer0 base */
36 #define ICR1 (MBARx+0x04D) /* timer0 interrupt control register */
37 #define IMR (MBARx+0x044) /* interrupt mask register */
38
39 #elif defined(__MCF5272)
40
41 #define TIMER0 (MBARx+0x200)
42 #define ICR1 (MBARx+0x020) /* external interrupts 1-4 and timers */
43
44 #elif defined(__MCF5282)
45
46 /* Default system clock frequency to 64 MHz */
47 #undef SYSTEM_CLOCK
48 #define SYSTEM_CLOCK (64000000)
49
50 #define IPSBAR 0x40000000
51 #define TIMER0 (IPSBAR + 0x00150000)
52
53 #elif defined(__MCF5213)
54
55 /* Default system clock frequency to 48 MHz */
56 #undef SYSTEM_CLOCK
57 #define SYSTEM_CLOCK (48000000)
58
59 #define IPSBAR 0x40000000
60 #define TIMER0 (IPSBAR + 0x00150000)
61
62 #else /* older ColdFire V2 cores */
63
64 #define TIMER0 (MBARx+0x100) /* timer 0 base */
65 #define ICR1 (MBARx+0x01C) /* timer0 interrupt control register */
66 #define IMR (MBARx+0x04D) /* interrupt mask register */
67
68 #endif
69
70 #if defined(__MCF5282) || defined(__MCF5213)
71 struct __ghs_coldfire_timer
72 {
73 uint16_t pcsr; /* PIT Control and Status Register (PCSR) */
74 uint16_t pmr; /* PIT Modulus Register (PMR) */
75 uint16_t pcntr; /* PIT Count Register (PCNTR) */
76 };
77 #else /* Other ColdFire cores */
78 struct __ghs_coldfire_timer
79 {
80 uint16_t tmr; /* timer mode register */
81 uint16_t pad0;
82 uint16_t trr; /* timer reference register */
83 uint16_t pad1;
84 uint16_t tcr; /* timer capture register */
85 uint16_t pad2;
86 uint16_t tcn; /* timer counter register */
87 uint16_t pad3;
88 uint8_t pad4;
89 uint8_t ter; /* timer event register */
90 };
91 #endif
92
93 /* TICKS_PER_SEC: on some targets you may be able to read or
94 * compute this value. If so, define a function called
95 * __ghs_manprf_timer_ticks_per_sec that returns the timer
96 * frequency. Otherwise, you'll want to set this value here.
97 */
98 #pragma weak __ghs_manprf_timer_ticks_per_sec
99 unsigned int __ghs_manprf_timer_ticks_per_sec(void);
TICKS_PER_SEC(void)100 unsigned int TICKS_PER_SEC(void) {
101 if(__ghs_manprf_timer_ticks_per_sec) {
102 return __ghs_manprf_timer_ticks_per_sec();
103 } else {
104 /* We scale the timer source by 256 to compensate for 16 bit timers */
105 return (SYSTEM_CLOCK/256);
106 }
107 }
108
109
110 uint32_t __ghs_exception_pc;
111 void __ghs_manprf_timer_coldfire_handler(void);
112
113 /* Wrapper for __ghs_manprf_timer_handler so we can
114 disable interrupts and store the exception pc/sr
115 */
116 #pragma asm
117 __ghs_manprf_timer_coldfire_handler:
118 MOVE.W #0x2700,%SR ; disable interrupts
119 MOVE.L %D0,-(%A7) ; save D0
120 ; save exception info to global variables
121 MOVE.L 8(%A7),%D0
122 MOVE.L %D0,__ghs_exception_pc
123 MOVE.L (%A7)+,%D0 ;restore D0 and A7
124 JMP __ghs_manprf_timer_handler
125
126 FSIZE __ghs_manprf_timer_coldfire_handler,4
127 SCALL __ghs_manprf_timer_coldfire_handler,__ghs_manprf_timer_handler
128 TYPE __ghs_manprf_timer_coldfire_handler,@function
129 SIZE __ghs_manprf_timer_coldfire_handler,.-__ghs_manprf_timer_coldfire_handler
130
131 #pragma endasm
132
133 #if defined(__MCF5272)
134
135 /* locate the interrupt handler at the correct exception vector */
136 #pragma asm
137 ; position this handler at autovector 5
138 ORG 0x114
139 DC.L __ghs_manprf_timer_coldfire_handler
140 previous
141 #pragma endasm
142
143
setup_timer_interrupt()144 static void setup_timer_interrupt()
145 {
146 volatile uint32_t *icr1 = (uint32_t*)ICR1;
147
148 /* enable timer interrupts with priority 6*/
149 *icr1 |= 0xe000;
150 }
151
152 #elif defined(__MCF5282)
153
154 /* Declare a pointer to the start of the vector table section */
155 extern char *__ghsbegin_vector;
156
157 static void setup_timer_interrupt()
158 {
159 volatile uint32_t *icr55 = (uint32_t*)(IPSBAR + 0xc74);
160
161 /* Interrupt level (1-7) and priority (0-7) must be unique.
162 For simplicity, just assume we'll use values
163 in the following pattern:
164 ICR8 level 1, priority 0
165 ...
166 ICR15 level 1, priority 7
167 ICR16 level 2, priority 0
168 ...
169 ICR63 level 7, priority 7
170 */
171
172 /* Write the ICR55 value to set a unique level and priority */
173 *icr55 =
174 0x28 | /* Level 5 */
175 0x03; /* Priority 3 */
176
177 /* Store the interrupt handler function into the vector table */
178 *(volatile uint32_t *)(__ghsbegin_vector + (64+55) * 4) =
179 (uint32_t)__ghs_manprf_timer_coldfire_handler;
180
181 /* Write Interrupt Mask Register High (IMRL) for INTC0
182 to clear bit 0, to prevent masking all interrupts */
183 *(volatile uint32_t *)(IPSBAR + 0xc08) &= (uint32_t)(~1);
184
185 /* Write Interrupt Mask Register High (IMRH) for INTC0
186 to clear bit 23, unmasking source 55 (PIT0) interrupts */
187 *(volatile uint32_t *)(IPSBAR + 0xc08) &= (uint32_t)(~(1 << 23));
188 /* unmask the PIT0 interrupt */
189
190 }
191
192 #elif defined(__MCF5213)
193
194 /* Declare a pointer to the start of the vector table section */
195 extern char *__ghsbegin_vector;
196
197 static void setup_timer_interrupt()
198 {
199 volatile uint32_t *icr55 = (uint32_t*)(IPSBAR + 0xc74);
200
201 /* Interrupt level (1-7) and priority (0-7) must be unique.
202 For simplicity, just assume we'll use values
203 in the following pattern:
204 ICR8 level 1, priority 0
205 ...
206 ICR15 level 1, priority 7
207 ICR16 level 2, priority 0
208 ...
209 ICR63 level 7, priority 7
210 */
211
212 /* Write the ICR55 value to set a unique level and priority */
213 *icr55 =
214 0x28 | /* Level 5 */
215 0x03; /* Priority 3 */
216
217 /* Store the interrupt handler function into the vector table */
218 *(volatile uint32_t *)(__ghsbegin_vector + (64+55) * 4) =
219 (uint32_t)__ghs_manprf_timer_coldfire_handler;
220
221 /* Write Interrupt Mask Register High (IMRL) for INTC0
222 to clear bit 0, to prevent masking all interrupts */
223 *(volatile uint32_t *)(IPSBAR + 0xc08) &= (uint32_t)(~1);
224
225 /* Write Interrupt Mask Register High (IMRH) for INTC0
226 to clear bit 23, unmasking source 55 (PIT0) interrupts */
227 *(volatile uint32_t *)(IPSBAR + 0xc08) &= (uint32_t)(~(1 << 23));
228 /* unmask the PIT0 interrupt */
229
230 }
231
232 #else /* chips that use autovectored timer interrupts */
233
234 /* locate the interrupt handler at the correct exception vector */
235 #pragma asm
236 ; position this handler at autovector 5
237 ORG 0x74
238 DC.L __ghs_manprf_timer_coldfire_handler
239 previous
240 #pragma endasm
241
242 static void setup_timer_interrupt()
243 {
244 volatile uint8_t *icr1 = (uint8_t*)ICR1; /* interrupt controller for timer0 */
245 volatile uint32_t *imr = (uint32_t*)IMR; /* interrupt mask register */
246
247 /* give timer0 level 5, priority 3 (autovector at 5) */
248 *icr1 = 0x80 | 0x17;
249 /* unmask the timer0 interrupt */
250 *imr &= ~(0x200);
251 }
252
253 #endif
254
255 #if defined(__MCF5282)
256
257 /* Initialize the timer. This will overwrite MBAR and ACR0 */
TIMER_INIT(unsigned int count)258 void TIMER_INIT(unsigned int count)
259 {
260 volatile struct __ghs_coldfire_timer *timer =
261 (struct __ghs_coldfire_timer*)(TIMER0);
262
263 /* Setup Internal Perepheral System Base Address register (IPSBAR) */
264 *(volatile uint32_t *)(0x40000000) = IPSBAR | 1;
265
266 setup_timer_interrupt();
267
268 /* Write to PIT0 Control and Status Register (PCSR) to initialize
269 the timer.
270 Set Overwrite (OVW) so the value written to PMR is immediately
271 loaded into the PCNTR. */
272 timer->pcsr = 0x0010;
273
274 /* Write to PIT0 Modulus Register (PMR) to set the reload value */
275 timer->pmr = count;
276
277 /* Write to PIT0 Control and Status Register (PCSR) to initialize
278 the timer.
279 */
280 timer->pcsr =
281 0x0700 | /* Prescaler (PRE) = 0b0111 to divide system clock by 256 */
282 0x0020 | /* Halted (HALTED) stops timer in halted mode */
283 0x0008 | /* PIT Interrupt Enable (PIE) to enable PIT interrupts */
284 0x0002 | /* Reload (RLD) */
285 0x0001; /* PIT Enable (EN) */
286 }
287
288 /* Clear the timer interrupt and reset the timer
289 Interrupts will be enabled with RTE restores the status register.
290 */
CLEAR_TIMER_INTERRUPT()291 void CLEAR_TIMER_INTERRUPT()
292 {
293 volatile struct __ghs_coldfire_timer *timer =
294 (struct __ghs_coldfire_timer*)(TIMER0);
295
296 /* Write to PIT0 Control and Status Register (PCSR) PIT Interrupt
297 Flag (PIF) to clear the PIT interrupt
298 */
299 timer->pcsr =
300 0x0700 | /* Prescaler (PRE) = 0b0111 to divide system clock by 256 */
301 0x0020 | /* Halted (HALTED) stops timer in halted mode */
302 0x0008 | /* PIT Interrupt Enable (PIE) to enable PIT interrupts */
303 0x0004 | /* PIT Interrupt Flag (PIF) to clear the PIT interrupt */
304 0x0002 | /* Reload (RLD) */
305 0x0001; /* PIT Enable (EN) */
306 }
307
308 #elif defined(__MCF5213)
309
310 /* Initialize the timer. This will overwrite MBAR and ACR0 */
TIMER_INIT(unsigned int count)311 void TIMER_INIT(unsigned int count)
312 {
313 volatile struct __ghs_coldfire_timer *timer =
314 (struct __ghs_coldfire_timer*)(TIMER0);
315
316 /* Setup Internal Peripheral System Base Address register (IPSBAR) */
317 *(volatile uint32_t *)(0x40000000) = IPSBAR | 1;
318
319 setup_timer_interrupt();
320
321 /* Write to PIT0 Control and Status Register (PCSR) to initialize
322 the timer.
323 Set Overwrite (OVW) so the value written to PMR is immediately
324 loaded into the PCNTR. */
325 timer->pcsr = 0x0010;
326
327 /* Write to PIT0 Modulus Register (PMR) to set the reload value */
328 timer->pmr = count;
329
330 /* Write to PIT0 Control and Status Register (PCSR) to initialize
331 the timer.
332 */
333 timer->pcsr =
334 0x0700 | /* Prescaler (PRE) = 0b0111 to divide system clock by 256 */
335 0x0020 | /* Debug mode bit (DBG) stops timer in halted/debug mode */
336 0x0008 | /* PIT Interrupt Enable (PIE) to enable PIT interrupts */
337 0x0002 | /* Reload (RLD) */
338 0x0001; /* PIT Enable (EN) */
339 }
340
341 /* Clear the timer interrupt and reset the timer
342 Interrupts will be enabled with RTE restores the status register.
343 */
CLEAR_TIMER_INTERRUPT()344 void CLEAR_TIMER_INTERRUPT()
345 {
346 volatile struct __ghs_coldfire_timer *timer =
347 (struct __ghs_coldfire_timer*)(TIMER0);
348
349 /* Write to PIT0 Control and Status Register (PCSR) PIT Interrupt
350 Flag (PIF) to clear the PIT interrupt
351 */
352 timer->pcsr =
353 0x0700 | /* Prescaler (PRE) = 0b0111 to divide system clock by 256 */
354 0x0020 | /* Debug mode bit (DBG) stops timer in halted/debug mode */
355 0x0008 | /* PIT Interrupt Enable (PIE) to enable PIT interrupts */
356 0x0004 | /* PIT Interrupt Flag (PIF) to clear the PIT interrupt */
357 0x0002 | /* Reload (RLD) */
358 0x0001; /* PIT Enable (EN) */
359 }
360
361 #else
362
363 /* Initialize the timer. This will overwrite MBAR and ACR0 */
TIMER_INIT(unsigned int count)364 void TIMER_INIT(unsigned int count)
365 {
366 volatile struct __ghs_coldfire_timer *timer =
367 (struct __ghs_coldfire_timer*)(TIMER0);
368
369 __MOVEC_MBAR(MBARx|0x1);
370 __MOVEC_ACR0(MBARx|0xc040); /* do not cache memory mapped area */
371
372 /* reset/disable timer */
373 timer->tmr = 0x0000;
374 timer->tcn = 0;
375 timer->trr = count;
376
377 setup_timer_interrupt();
378
379 /* set and enable tmr0 */
380 timer->tmr = 0xff13;
381 }
382
383 /* Clear the timer interrupt and reset the timer
384 Interrupts will be enabled with RTE restores the status register.
385 */
CLEAR_TIMER_INTERRUPT()386 void CLEAR_TIMER_INTERRUPT()
387 {
388 volatile struct __ghs_coldfire_timer *timer =
389 (struct __ghs_coldfire_timer*)(TIMER0);
390
391 timer->ter = 0x3; /* write event bits to clear */
392 timer->tcn = 0x0;
393 }
394
395 #endif
396
397 /* Enable PIT interrupts by clearing the Status Register (SR)
398 interrupt priority mask (I) field. */
399 #define ENABLE_TIMER_INTERRUPT __EI
400
401 /* Return the exception PC */
GET_EPC(void)402 uint32_t GET_EPC(void)
403 {
404 return __ghs_exception_pc;
405 }
406