1ea0364f1SPeter Tyser /* 2ea0364f1SPeter Tyser * (C) Copyright 2003 Josef Baumgartner <josef.baumgartner@telex.de> 3ea0364f1SPeter Tyser * 4ea0364f1SPeter Tyser * (C) Copyright 2000 5ea0364f1SPeter Tyser * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 6ea0364f1SPeter Tyser * 7ea0364f1SPeter Tyser * See file CREDITS for list of people who contributed to this 8ea0364f1SPeter Tyser * project. 9ea0364f1SPeter Tyser * 10ea0364f1SPeter Tyser * This program is free software; you can redistribute it and/or 11ea0364f1SPeter Tyser * modify it under the terms of the GNU General Public License as 12ea0364f1SPeter Tyser * published by the Free Software Foundation; either version 2 of 13ea0364f1SPeter Tyser * the License, or (at your option) any later version. 14ea0364f1SPeter Tyser * 15ea0364f1SPeter Tyser * This program is distributed in the hope that it will be useful, 16ea0364f1SPeter Tyser * but WITHOUT ANY WARRANTY; without even the implied warranty of 17ea0364f1SPeter Tyser * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18ea0364f1SPeter Tyser * GNU General Public License for more details. 19ea0364f1SPeter Tyser * 20ea0364f1SPeter Tyser * You should have received a copy of the GNU General Public License 21ea0364f1SPeter Tyser * along with this program; if not, write to the Free Software 22ea0364f1SPeter Tyser * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 23ea0364f1SPeter Tyser * MA 02111-1307 USA 24ea0364f1SPeter Tyser */ 25ea0364f1SPeter Tyser 26ea0364f1SPeter Tyser #include <common.h> 27ea0364f1SPeter Tyser 28ea0364f1SPeter Tyser #include <asm/timer.h> 29ea0364f1SPeter Tyser #include <asm/immap.h> 30ea0364f1SPeter Tyser #include <watchdog.h> 31ea0364f1SPeter Tyser 32ea0364f1SPeter Tyser DECLARE_GLOBAL_DATA_PTR; 33ea0364f1SPeter Tyser 34ea0364f1SPeter Tyser static volatile ulong timestamp = 0; 35ea0364f1SPeter Tyser 36ea0364f1SPeter Tyser #ifndef CONFIG_SYS_WATCHDOG_FREQ 37ea0364f1SPeter Tyser #define CONFIG_SYS_WATCHDOG_FREQ (CONFIG_SYS_HZ / 2) 38ea0364f1SPeter Tyser #endif 39ea0364f1SPeter Tyser 40ea0364f1SPeter Tyser #if defined(CONFIG_MCFTMR) 41ea0364f1SPeter Tyser #ifndef CONFIG_SYS_UDELAY_BASE 42ea0364f1SPeter Tyser # error "uDelay base not defined!" 43ea0364f1SPeter Tyser #endif 44ea0364f1SPeter Tyser 45ea0364f1SPeter Tyser #if !defined(CONFIG_SYS_TMR_BASE) || !defined(CONFIG_SYS_INTR_BASE) || !defined(CONFIG_SYS_TMRINTR_NO) || !defined(CONFIG_SYS_TMRINTR_MASK) 46ea0364f1SPeter Tyser # error "TMR_BASE, INTR_BASE, TMRINTR_NO or TMRINTR_MASk not defined!" 47ea0364f1SPeter Tyser #endif 48ea0364f1SPeter Tyser extern void dtimer_intr_setup(void); 49ea0364f1SPeter Tyser 50ea0364f1SPeter Tyser void __udelay(unsigned long usec) 51ea0364f1SPeter Tyser { 52ea0364f1SPeter Tyser volatile dtmr_t *timerp = (dtmr_t *) (CONFIG_SYS_UDELAY_BASE); 53ea0364f1SPeter Tyser uint start, now, tmp; 54ea0364f1SPeter Tyser 55ea0364f1SPeter Tyser while (usec > 0) { 56ea0364f1SPeter Tyser if (usec > 65000) 57ea0364f1SPeter Tyser tmp = 65000; 58ea0364f1SPeter Tyser else 59ea0364f1SPeter Tyser tmp = usec; 60ea0364f1SPeter Tyser usec = usec - tmp; 61ea0364f1SPeter Tyser 62ea0364f1SPeter Tyser /* Set up TIMER 3 as timebase clock */ 63ea0364f1SPeter Tyser timerp->tmr = DTIM_DTMR_RST_RST; 64ea0364f1SPeter Tyser timerp->tcn = 0; 65ea0364f1SPeter Tyser /* set period to 1 us */ 66ea0364f1SPeter Tyser timerp->tmr = 67ea0364f1SPeter Tyser CONFIG_SYS_TIMER_PRESCALER | DTIM_DTMR_CLK_DIV1 | DTIM_DTMR_FRR | 68ea0364f1SPeter Tyser DTIM_DTMR_RST_EN; 69ea0364f1SPeter Tyser 70ea0364f1SPeter Tyser start = now = timerp->tcn; 71ea0364f1SPeter Tyser while (now < start + tmp) 72ea0364f1SPeter Tyser now = timerp->tcn; 73ea0364f1SPeter Tyser } 74ea0364f1SPeter Tyser } 75ea0364f1SPeter Tyser 76ea0364f1SPeter Tyser void dtimer_interrupt(void *not_used) 77ea0364f1SPeter Tyser { 78ea0364f1SPeter Tyser volatile dtmr_t *timerp = (dtmr_t *) (CONFIG_SYS_TMR_BASE); 79ea0364f1SPeter Tyser 80ea0364f1SPeter Tyser /* check for timer interrupt asserted */ 81ea0364f1SPeter Tyser if ((CONFIG_SYS_TMRPND_REG & CONFIG_SYS_TMRINTR_MASK) == CONFIG_SYS_TMRINTR_PEND) { 82ea0364f1SPeter Tyser timerp->ter = (DTIM_DTER_CAP | DTIM_DTER_REF); 83ea0364f1SPeter Tyser timestamp++; 84ea0364f1SPeter Tyser 85ea0364f1SPeter Tyser #if defined(CONFIG_WATCHDOG) || defined (CONFIG_HW_WATCHDOG) 86ea0364f1SPeter Tyser if ((timestamp % (CONFIG_SYS_WATCHDOG_FREQ)) == 0) { 87ea0364f1SPeter Tyser WATCHDOG_RESET (); 88ea0364f1SPeter Tyser } 89ea0364f1SPeter Tyser #endif /* CONFIG_WATCHDOG || CONFIG_HW_WATCHDOG */ 90ea0364f1SPeter Tyser return; 91ea0364f1SPeter Tyser } 92ea0364f1SPeter Tyser } 93ea0364f1SPeter Tyser 94ea0364f1SPeter Tyser void timer_init(void) 95ea0364f1SPeter Tyser { 96ea0364f1SPeter Tyser volatile dtmr_t *timerp = (dtmr_t *) (CONFIG_SYS_TMR_BASE); 97ea0364f1SPeter Tyser 98ea0364f1SPeter Tyser timestamp = 0; 99ea0364f1SPeter Tyser 100ea0364f1SPeter Tyser timerp->tcn = 0; 101ea0364f1SPeter Tyser timerp->trr = 0; 102ea0364f1SPeter Tyser 103ea0364f1SPeter Tyser /* Set up TIMER 4 as clock */ 104ea0364f1SPeter Tyser timerp->tmr = DTIM_DTMR_RST_RST; 105ea0364f1SPeter Tyser 106ea0364f1SPeter Tyser /* initialize and enable timer interrupt */ 107ea0364f1SPeter Tyser irq_install_handler(CONFIG_SYS_TMRINTR_NO, dtimer_interrupt, 0); 108ea0364f1SPeter Tyser 109ea0364f1SPeter Tyser timerp->tcn = 0; 110ea0364f1SPeter Tyser timerp->trr = 1000; /* Interrupt every ms */ 111ea0364f1SPeter Tyser 112ea0364f1SPeter Tyser dtimer_intr_setup(); 113ea0364f1SPeter Tyser 114ea0364f1SPeter Tyser /* set a period of 1us, set timer mode to restart and enable timer and interrupt */ 115ea0364f1SPeter Tyser timerp->tmr = CONFIG_SYS_TIMER_PRESCALER | DTIM_DTMR_CLK_DIV1 | 116ea0364f1SPeter Tyser DTIM_DTMR_FRR | DTIM_DTMR_ORRI | DTIM_DTMR_RST_EN; 117ea0364f1SPeter Tyser } 118ea0364f1SPeter Tyser 119ea0364f1SPeter Tyser void reset_timer(void) 120ea0364f1SPeter Tyser { 121ea0364f1SPeter Tyser timestamp = 0; 122ea0364f1SPeter Tyser } 123ea0364f1SPeter Tyser 124ea0364f1SPeter Tyser ulong get_timer(ulong base) 125ea0364f1SPeter Tyser { 126ea0364f1SPeter Tyser return (timestamp - base); 127ea0364f1SPeter Tyser } 128ea0364f1SPeter Tyser 129ea0364f1SPeter Tyser #endif /* CONFIG_MCFTMR */ 130ea0364f1SPeter Tyser 131ea0364f1SPeter Tyser #if defined(CONFIG_MCFPIT) 132ea0364f1SPeter Tyser #if !defined(CONFIG_SYS_PIT_BASE) 133ea0364f1SPeter Tyser # error "CONFIG_SYS_PIT_BASE not defined!" 134ea0364f1SPeter Tyser #endif 135ea0364f1SPeter Tyser 136ea0364f1SPeter Tyser static unsigned short lastinc; 137ea0364f1SPeter Tyser 138ea0364f1SPeter Tyser void __udelay(unsigned long usec) 139ea0364f1SPeter Tyser { 140ea0364f1SPeter Tyser volatile pit_t *timerp = (pit_t *) (CONFIG_SYS_UDELAY_BASE); 141ea0364f1SPeter Tyser uint tmp; 142ea0364f1SPeter Tyser 143ea0364f1SPeter Tyser while (usec > 0) { 144ea0364f1SPeter Tyser if (usec > 65000) 145ea0364f1SPeter Tyser tmp = 65000; 146ea0364f1SPeter Tyser else 147ea0364f1SPeter Tyser tmp = usec; 148ea0364f1SPeter Tyser usec = usec - tmp; 149ea0364f1SPeter Tyser 150ea0364f1SPeter Tyser /* Set up TIMER 3 as timebase clock */ 151ea0364f1SPeter Tyser timerp->pcsr = PIT_PCSR_OVW; 152ea0364f1SPeter Tyser timerp->pmr = 0; 153ea0364f1SPeter Tyser /* set period to 1 us */ 154ea0364f1SPeter Tyser timerp->pcsr |= PIT_PCSR_PRE(CONFIG_SYS_PIT_PRESCALE) | PIT_PCSR_EN; 155ea0364f1SPeter Tyser 156ea0364f1SPeter Tyser timerp->pmr = tmp; 157ea0364f1SPeter Tyser while (timerp->pcntr > 0) ; 158ea0364f1SPeter Tyser } 159ea0364f1SPeter Tyser } 160ea0364f1SPeter Tyser 161ea0364f1SPeter Tyser void timer_init(void) 162ea0364f1SPeter Tyser { 163ea0364f1SPeter Tyser volatile pit_t *timerp = (pit_t *) (CONFIG_SYS_PIT_BASE); 164ea0364f1SPeter Tyser timestamp = 0; 165ea0364f1SPeter Tyser 166ea0364f1SPeter Tyser /* Set up TIMER 4 as poll clock */ 167ea0364f1SPeter Tyser timerp->pcsr = PIT_PCSR_OVW; 168ea0364f1SPeter Tyser timerp->pmr = lastinc = 0; 169ea0364f1SPeter Tyser timerp->pcsr |= PIT_PCSR_PRE(CONFIG_SYS_PIT_PRESCALE) | PIT_PCSR_EN; 170ea0364f1SPeter Tyser } 171ea0364f1SPeter Tyser 172ea0364f1SPeter Tyser ulong get_timer(ulong base) 173ea0364f1SPeter Tyser { 174ea0364f1SPeter Tyser unsigned short now, diff; 175ea0364f1SPeter Tyser volatile pit_t *timerp = (pit_t *) (CONFIG_SYS_PIT_BASE); 176ea0364f1SPeter Tyser 177ea0364f1SPeter Tyser now = timerp->pcntr; 178ea0364f1SPeter Tyser diff = -(now - lastinc); 179ea0364f1SPeter Tyser 180ea0364f1SPeter Tyser timestamp += diff; 181ea0364f1SPeter Tyser lastinc = now; 182ea0364f1SPeter Tyser return timestamp - base; 183ea0364f1SPeter Tyser } 184ea0364f1SPeter Tyser 185ea0364f1SPeter Tyser void wait_ticks(unsigned long ticks) 186ea0364f1SPeter Tyser { 187*5c8404afSGraeme Russ u32 start = get_timer(0); 188*5c8404afSGraeme Russ while (get_timer(start) < ticks) ; 189ea0364f1SPeter Tyser } 190ea0364f1SPeter Tyser #endif /* CONFIG_MCFPIT */ 191ea0364f1SPeter Tyser 192ea0364f1SPeter Tyser /* 193ea0364f1SPeter Tyser * This function is derived from PowerPC code (read timebase as long long). 194ea0364f1SPeter Tyser * On M68K it just returns the timer value. 195ea0364f1SPeter Tyser */ 196ea0364f1SPeter Tyser unsigned long long get_ticks(void) 197ea0364f1SPeter Tyser { 198ea0364f1SPeter Tyser return get_timer(0); 199ea0364f1SPeter Tyser } 200ea0364f1SPeter Tyser 201ea0364f1SPeter Tyser unsigned long usec2ticks(unsigned long usec) 202ea0364f1SPeter Tyser { 203ea0364f1SPeter Tyser return get_timer(usec); 204ea0364f1SPeter Tyser } 205ea0364f1SPeter Tyser 206ea0364f1SPeter Tyser /* 207ea0364f1SPeter Tyser * This function is derived from PowerPC code (timebase clock frequency). 208ea0364f1SPeter Tyser * On M68K it returns the number of timer ticks per second. 209ea0364f1SPeter Tyser */ 210ea0364f1SPeter Tyser ulong get_tbclk(void) 211ea0364f1SPeter Tyser { 212ea0364f1SPeter Tyser ulong tbclk; 213ea0364f1SPeter Tyser tbclk = CONFIG_SYS_HZ; 214ea0364f1SPeter Tyser return tbclk; 215ea0364f1SPeter Tyser } 216