/* * Copyright (C) 2004 by Green Hills Software,Inc. * * This program is the property of Green Hills Software, Inc, * its contents are proprietary information and no part of it * is to be disclosed to anyone except employees of Green Hills * Software, Inc., or as agreed in writing signed by the President * of Green Hills Software, Inc. */ /*** * ColdFire timer support. * Set SYSTEM_CLOCK to the appropriate value. * Check that the memory mapped register positions are correct * for your board. * If your code makes use of MBAR or ACR0, modify the TIMER_INIT * code appropriately. * Make sure no other interrupts use the same priority and level * as the timer interrupt. * * Recompile libsys with the appropriate cpu selected. */ #define MBARx 0x10000000 /* M5407C3 50Mhz M5307C3 45Mhz M5272C3 66Mhz M5249C3 70Mhz */ #define SYSTEM_CLOCK (50000000) /* 50Mhz timer clock */ #if defined(__MCF5407) || defined(__MCF5307) #define TIMER0 (MBARx+0x140) /* timer0 base */ #define ICR1 (MBARx+0x04D) /* timer0 interrupt control register */ #define IMR (MBARx+0x044) /* interrupt mask register */ #elif defined(__MCF5272) #define TIMER0 (MBARx+0x200) #define ICR1 (MBARx+0x020) /* external interrupts 1-4 and timers */ #elif defined(__MCF5282) /* Default system clock frequency to 64 MHz */ #undef SYSTEM_CLOCK #define SYSTEM_CLOCK (64000000) #define IPSBAR 0x40000000 #define TIMER0 (IPSBAR + 0x00150000) #elif defined(__MCF5213) /* Default system clock frequency to 48 MHz */ #undef SYSTEM_CLOCK #define SYSTEM_CLOCK (48000000) #define IPSBAR 0x40000000 #define TIMER0 (IPSBAR + 0x00150000) #else /* older ColdFire V2 cores */ #define TIMER0 (MBARx+0x100) /* timer 0 base */ #define ICR1 (MBARx+0x01C) /* timer0 interrupt control register */ #define IMR (MBARx+0x04D) /* interrupt mask register */ #endif #if defined(__MCF5282) || defined(__MCF5213) struct __ghs_coldfire_timer { uint16_t pcsr; /* PIT Control and Status Register (PCSR) */ uint16_t pmr; /* PIT Modulus Register (PMR) */ uint16_t pcntr; /* PIT Count Register (PCNTR) */ }; #else /* Other ColdFire cores */ struct __ghs_coldfire_timer { uint16_t tmr; /* timer mode register */ uint16_t pad0; uint16_t trr; /* timer reference register */ uint16_t pad1; uint16_t tcr; /* timer capture register */ uint16_t pad2; uint16_t tcn; /* timer counter register */ uint16_t pad3; uint8_t pad4; uint8_t ter; /* timer event register */ }; #endif /* TICKS_PER_SEC: on some targets you may be able to read or * compute this value. If so, define a function called * __ghs_manprf_timer_ticks_per_sec that returns the timer * frequency. Otherwise, you'll want to set this value here. */ #pragma weak __ghs_manprf_timer_ticks_per_sec unsigned int __ghs_manprf_timer_ticks_per_sec(void); unsigned int TICKS_PER_SEC(void) { if(__ghs_manprf_timer_ticks_per_sec) { return __ghs_manprf_timer_ticks_per_sec(); } else { /* We scale the timer source by 256 to compensate for 16 bit timers */ return (SYSTEM_CLOCK/256); } } uint32_t __ghs_exception_pc; void __ghs_manprf_timer_coldfire_handler(void); /* Wrapper for __ghs_manprf_timer_handler so we can disable interrupts and store the exception pc/sr */ #pragma asm __ghs_manprf_timer_coldfire_handler: MOVE.W #0x2700,%SR ; disable interrupts MOVE.L %D0,-(%A7) ; save D0 ; save exception info to global variables MOVE.L 8(%A7),%D0 MOVE.L %D0,__ghs_exception_pc MOVE.L (%A7)+,%D0 ;restore D0 and A7 JMP __ghs_manprf_timer_handler FSIZE __ghs_manprf_timer_coldfire_handler,4 SCALL __ghs_manprf_timer_coldfire_handler,__ghs_manprf_timer_handler TYPE __ghs_manprf_timer_coldfire_handler,@function SIZE __ghs_manprf_timer_coldfire_handler,.-__ghs_manprf_timer_coldfire_handler #pragma endasm #if defined(__MCF5272) /* locate the interrupt handler at the correct exception vector */ #pragma asm ; position this handler at autovector 5 ORG 0x114 DC.L __ghs_manprf_timer_coldfire_handler previous #pragma endasm static void setup_timer_interrupt() { volatile uint32_t *icr1 = (uint32_t*)ICR1; /* enable timer interrupts with priority 6*/ *icr1 |= 0xe000; } #elif defined(__MCF5282) /* Declare a pointer to the start of the vector table section */ extern char *__ghsbegin_vector; static void setup_timer_interrupt() { volatile uint32_t *icr55 = (uint32_t*)(IPSBAR + 0xc74); /* Interrupt level (1-7) and priority (0-7) must be unique. For simplicity, just assume we'll use values in the following pattern: ICR8 level 1, priority 0 ... ICR15 level 1, priority 7 ICR16 level 2, priority 0 ... ICR63 level 7, priority 7 */ /* Write the ICR55 value to set a unique level and priority */ *icr55 = 0x28 | /* Level 5 */ 0x03; /* Priority 3 */ /* Store the interrupt handler function into the vector table */ *(volatile uint32_t *)(__ghsbegin_vector + (64+55) * 4) = (uint32_t)__ghs_manprf_timer_coldfire_handler; /* Write Interrupt Mask Register High (IMRL) for INTC0 to clear bit 0, to prevent masking all interrupts */ *(volatile uint32_t *)(IPSBAR + 0xc08) &= (uint32_t)(~1); /* Write Interrupt Mask Register High (IMRH) for INTC0 to clear bit 23, unmasking source 55 (PIT0) interrupts */ *(volatile uint32_t *)(IPSBAR + 0xc08) &= (uint32_t)(~(1 << 23)); /* unmask the PIT0 interrupt */ } #elif defined(__MCF5213) /* Declare a pointer to the start of the vector table section */ extern char *__ghsbegin_vector; static void setup_timer_interrupt() { volatile uint32_t *icr55 = (uint32_t*)(IPSBAR + 0xc74); /* Interrupt level (1-7) and priority (0-7) must be unique. For simplicity, just assume we'll use values in the following pattern: ICR8 level 1, priority 0 ... ICR15 level 1, priority 7 ICR16 level 2, priority 0 ... ICR63 level 7, priority 7 */ /* Write the ICR55 value to set a unique level and priority */ *icr55 = 0x28 | /* Level 5 */ 0x03; /* Priority 3 */ /* Store the interrupt handler function into the vector table */ *(volatile uint32_t *)(__ghsbegin_vector + (64+55) * 4) = (uint32_t)__ghs_manprf_timer_coldfire_handler; /* Write Interrupt Mask Register High (IMRL) for INTC0 to clear bit 0, to prevent masking all interrupts */ *(volatile uint32_t *)(IPSBAR + 0xc08) &= (uint32_t)(~1); /* Write Interrupt Mask Register High (IMRH) for INTC0 to clear bit 23, unmasking source 55 (PIT0) interrupts */ *(volatile uint32_t *)(IPSBAR + 0xc08) &= (uint32_t)(~(1 << 23)); /* unmask the PIT0 interrupt */ } #else /* chips that use autovectored timer interrupts */ /* locate the interrupt handler at the correct exception vector */ #pragma asm ; position this handler at autovector 5 ORG 0x74 DC.L __ghs_manprf_timer_coldfire_handler previous #pragma endasm static void setup_timer_interrupt() { volatile uint8_t *icr1 = (uint8_t*)ICR1; /* interrupt controller for timer0 */ volatile uint32_t *imr = (uint32_t*)IMR; /* interrupt mask register */ /* give timer0 level 5, priority 3 (autovector at 5) */ *icr1 = 0x80 | 0x17; /* unmask the timer0 interrupt */ *imr &= ~(0x200); } #endif #if defined(__MCF5282) /* Initialize the timer. This will overwrite MBAR and ACR0 */ void TIMER_INIT(unsigned int count) { volatile struct __ghs_coldfire_timer *timer = (struct __ghs_coldfire_timer*)(TIMER0); /* Setup Internal Perepheral System Base Address register (IPSBAR) */ *(volatile uint32_t *)(0x40000000) = IPSBAR | 1; setup_timer_interrupt(); /* Write to PIT0 Control and Status Register (PCSR) to initialize the timer. Set Overwrite (OVW) so the value written to PMR is immediately loaded into the PCNTR. */ timer->pcsr = 0x0010; /* Write to PIT0 Modulus Register (PMR) to set the reload value */ timer->pmr = count; /* Write to PIT0 Control and Status Register (PCSR) to initialize the timer. */ timer->pcsr = 0x0700 | /* Prescaler (PRE) = 0b0111 to divide system clock by 256 */ 0x0020 | /* Halted (HALTED) stops timer in halted mode */ 0x0008 | /* PIT Interrupt Enable (PIE) to enable PIT interrupts */ 0x0002 | /* Reload (RLD) */ 0x0001; /* PIT Enable (EN) */ } /* Clear the timer interrupt and reset the timer Interrupts will be enabled with RTE restores the status register. */ void CLEAR_TIMER_INTERRUPT() { volatile struct __ghs_coldfire_timer *timer = (struct __ghs_coldfire_timer*)(TIMER0); /* Write to PIT0 Control and Status Register (PCSR) PIT Interrupt Flag (PIF) to clear the PIT interrupt */ timer->pcsr = 0x0700 | /* Prescaler (PRE) = 0b0111 to divide system clock by 256 */ 0x0020 | /* Halted (HALTED) stops timer in halted mode */ 0x0008 | /* PIT Interrupt Enable (PIE) to enable PIT interrupts */ 0x0004 | /* PIT Interrupt Flag (PIF) to clear the PIT interrupt */ 0x0002 | /* Reload (RLD) */ 0x0001; /* PIT Enable (EN) */ } #elif defined(__MCF5213) /* Initialize the timer. This will overwrite MBAR and ACR0 */ void TIMER_INIT(unsigned int count) { volatile struct __ghs_coldfire_timer *timer = (struct __ghs_coldfire_timer*)(TIMER0); /* Setup Internal Peripheral System Base Address register (IPSBAR) */ *(volatile uint32_t *)(0x40000000) = IPSBAR | 1; setup_timer_interrupt(); /* Write to PIT0 Control and Status Register (PCSR) to initialize the timer. Set Overwrite (OVW) so the value written to PMR is immediately loaded into the PCNTR. */ timer->pcsr = 0x0010; /* Write to PIT0 Modulus Register (PMR) to set the reload value */ timer->pmr = count; /* Write to PIT0 Control and Status Register (PCSR) to initialize the timer. */ timer->pcsr = 0x0700 | /* Prescaler (PRE) = 0b0111 to divide system clock by 256 */ 0x0020 | /* Debug mode bit (DBG) stops timer in halted/debug mode */ 0x0008 | /* PIT Interrupt Enable (PIE) to enable PIT interrupts */ 0x0002 | /* Reload (RLD) */ 0x0001; /* PIT Enable (EN) */ } /* Clear the timer interrupt and reset the timer Interrupts will be enabled with RTE restores the status register. */ void CLEAR_TIMER_INTERRUPT() { volatile struct __ghs_coldfire_timer *timer = (struct __ghs_coldfire_timer*)(TIMER0); /* Write to PIT0 Control and Status Register (PCSR) PIT Interrupt Flag (PIF) to clear the PIT interrupt */ timer->pcsr = 0x0700 | /* Prescaler (PRE) = 0b0111 to divide system clock by 256 */ 0x0020 | /* Debug mode bit (DBG) stops timer in halted/debug mode */ 0x0008 | /* PIT Interrupt Enable (PIE) to enable PIT interrupts */ 0x0004 | /* PIT Interrupt Flag (PIF) to clear the PIT interrupt */ 0x0002 | /* Reload (RLD) */ 0x0001; /* PIT Enable (EN) */ } #else /* Initialize the timer. This will overwrite MBAR and ACR0 */ void TIMER_INIT(unsigned int count) { volatile struct __ghs_coldfire_timer *timer = (struct __ghs_coldfire_timer*)(TIMER0); __MOVEC_MBAR(MBARx|0x1); __MOVEC_ACR0(MBARx|0xc040); /* do not cache memory mapped area */ /* reset/disable timer */ timer->tmr = 0x0000; timer->tcn = 0; timer->trr = count; setup_timer_interrupt(); /* set and enable tmr0 */ timer->tmr = 0xff13; } /* Clear the timer interrupt and reset the timer Interrupts will be enabled with RTE restores the status register. */ void CLEAR_TIMER_INTERRUPT() { volatile struct __ghs_coldfire_timer *timer = (struct __ghs_coldfire_timer*)(TIMER0); timer->ter = 0x3; /* write event bits to clear */ timer->tcn = 0x0; } #endif /* Enable PIT interrupts by clearing the Status Register (SR) interrupt priority mask (I) field. */ #define ENABLE_TIMER_INTERRUPT __EI /* Return the exception PC */ uint32_t GET_EPC(void) { return __ghs_exception_pc; }