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 * 71a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 8ea0364f1SPeter Tyser */ 9ea0364f1SPeter Tyser 10ea0364f1SPeter Tyser #include <common.h> 11ea0364f1SPeter Tyser 12ea0364f1SPeter Tyser #include <asm/timer.h> 13ea0364f1SPeter Tyser #include <asm/immap.h> 14ea0364f1SPeter Tyser #include <watchdog.h> 15ea0364f1SPeter Tyser 16ea0364f1SPeter Tyser DECLARE_GLOBAL_DATA_PTR; 17ea0364f1SPeter Tyser 18ea0364f1SPeter Tyser static volatile ulong timestamp = 0; 19ea0364f1SPeter Tyser 20ea0364f1SPeter Tyser #ifndef CONFIG_SYS_WATCHDOG_FREQ 21ea0364f1SPeter Tyser #define CONFIG_SYS_WATCHDOG_FREQ (CONFIG_SYS_HZ / 2) 22ea0364f1SPeter Tyser #endif 23ea0364f1SPeter Tyser 24ea0364f1SPeter Tyser #if defined(CONFIG_MCFTMR) 25ea0364f1SPeter Tyser #ifndef CONFIG_SYS_UDELAY_BASE 26ea0364f1SPeter Tyser # error "uDelay base not defined!" 27ea0364f1SPeter Tyser #endif 28ea0364f1SPeter Tyser 29ea0364f1SPeter Tyser #if !defined(CONFIG_SYS_TMR_BASE) || !defined(CONFIG_SYS_INTR_BASE) || !defined(CONFIG_SYS_TMRINTR_NO) || !defined(CONFIG_SYS_TMRINTR_MASK) 30ea0364f1SPeter Tyser # error "TMR_BASE, INTR_BASE, TMRINTR_NO or TMRINTR_MASk not defined!" 31ea0364f1SPeter Tyser #endif 32ea0364f1SPeter Tyser extern void dtimer_intr_setup(void); 33ea0364f1SPeter Tyser 34ea0364f1SPeter Tyser void __udelay(unsigned long usec) 35ea0364f1SPeter Tyser { 36ea0364f1SPeter Tyser volatile dtmr_t *timerp = (dtmr_t *) (CONFIG_SYS_UDELAY_BASE); 37ea0364f1SPeter Tyser uint start, now, tmp; 38ea0364f1SPeter Tyser 39ea0364f1SPeter Tyser while (usec > 0) { 40ea0364f1SPeter Tyser if (usec > 65000) 41ea0364f1SPeter Tyser tmp = 65000; 42ea0364f1SPeter Tyser else 43ea0364f1SPeter Tyser tmp = usec; 44ea0364f1SPeter Tyser usec = usec - tmp; 45ea0364f1SPeter Tyser 46ea0364f1SPeter Tyser /* Set up TIMER 3 as timebase clock */ 47ea0364f1SPeter Tyser timerp->tmr = DTIM_DTMR_RST_RST; 48ea0364f1SPeter Tyser timerp->tcn = 0; 49ea0364f1SPeter Tyser /* set period to 1 us */ 50ea0364f1SPeter Tyser timerp->tmr = 51ea0364f1SPeter Tyser CONFIG_SYS_TIMER_PRESCALER | DTIM_DTMR_CLK_DIV1 | DTIM_DTMR_FRR | 52ea0364f1SPeter Tyser DTIM_DTMR_RST_EN; 53ea0364f1SPeter Tyser 54ea0364f1SPeter Tyser start = now = timerp->tcn; 55ea0364f1SPeter Tyser while (now < start + tmp) 56ea0364f1SPeter Tyser now = timerp->tcn; 57ea0364f1SPeter Tyser } 58ea0364f1SPeter Tyser } 59ea0364f1SPeter Tyser 60ea0364f1SPeter Tyser void dtimer_interrupt(void *not_used) 61ea0364f1SPeter Tyser { 62ea0364f1SPeter Tyser volatile dtmr_t *timerp = (dtmr_t *) (CONFIG_SYS_TMR_BASE); 63ea0364f1SPeter Tyser 64ea0364f1SPeter Tyser /* check for timer interrupt asserted */ 65ea0364f1SPeter Tyser if ((CONFIG_SYS_TMRPND_REG & CONFIG_SYS_TMRINTR_MASK) == CONFIG_SYS_TMRINTR_PEND) { 66ea0364f1SPeter Tyser timerp->ter = (DTIM_DTER_CAP | DTIM_DTER_REF); 67ea0364f1SPeter Tyser timestamp++; 68ea0364f1SPeter Tyser 69ea0364f1SPeter Tyser #if defined(CONFIG_WATCHDOG) || defined (CONFIG_HW_WATCHDOG) 70ea0364f1SPeter Tyser if ((timestamp % (CONFIG_SYS_WATCHDOG_FREQ)) == 0) { 71ea0364f1SPeter Tyser WATCHDOG_RESET (); 72ea0364f1SPeter Tyser } 73ea0364f1SPeter Tyser #endif /* CONFIG_WATCHDOG || CONFIG_HW_WATCHDOG */ 74ea0364f1SPeter Tyser return; 75ea0364f1SPeter Tyser } 76ea0364f1SPeter Tyser } 77ea0364f1SPeter Tyser 78444ddfc7SJason Jin int timer_init(void) 79ea0364f1SPeter Tyser { 80ea0364f1SPeter Tyser volatile dtmr_t *timerp = (dtmr_t *) (CONFIG_SYS_TMR_BASE); 81ea0364f1SPeter Tyser 82ea0364f1SPeter Tyser timestamp = 0; 83ea0364f1SPeter Tyser 84ea0364f1SPeter Tyser timerp->tcn = 0; 85ea0364f1SPeter Tyser timerp->trr = 0; 86ea0364f1SPeter Tyser 87ea0364f1SPeter Tyser /* Set up TIMER 4 as clock */ 88ea0364f1SPeter Tyser timerp->tmr = DTIM_DTMR_RST_RST; 89ea0364f1SPeter Tyser 90ea0364f1SPeter Tyser /* initialize and enable timer interrupt */ 91ea0364f1SPeter Tyser irq_install_handler(CONFIG_SYS_TMRINTR_NO, dtimer_interrupt, 0); 92ea0364f1SPeter Tyser 93ea0364f1SPeter Tyser timerp->tcn = 0; 94ea0364f1SPeter Tyser timerp->trr = 1000; /* Interrupt every ms */ 95ea0364f1SPeter Tyser 96ea0364f1SPeter Tyser dtimer_intr_setup(); 97ea0364f1SPeter Tyser 98ea0364f1SPeter Tyser /* set a period of 1us, set timer mode to restart and enable timer and interrupt */ 99ea0364f1SPeter Tyser timerp->tmr = CONFIG_SYS_TIMER_PRESCALER | DTIM_DTMR_CLK_DIV1 | 100ea0364f1SPeter Tyser DTIM_DTMR_FRR | DTIM_DTMR_ORRI | DTIM_DTMR_RST_EN; 101444ddfc7SJason Jin 102444ddfc7SJason Jin return 0; 103ea0364f1SPeter Tyser } 104ea0364f1SPeter Tyser 105ea0364f1SPeter Tyser ulong get_timer(ulong base) 106ea0364f1SPeter Tyser { 107ea0364f1SPeter Tyser return (timestamp - base); 108ea0364f1SPeter Tyser } 109ea0364f1SPeter Tyser 110ea0364f1SPeter Tyser #endif /* CONFIG_MCFTMR */ 111ea0364f1SPeter Tyser 112ea0364f1SPeter Tyser #if defined(CONFIG_MCFPIT) 113ea0364f1SPeter Tyser #if !defined(CONFIG_SYS_PIT_BASE) 114ea0364f1SPeter Tyser # error "CONFIG_SYS_PIT_BASE not defined!" 115ea0364f1SPeter Tyser #endif 116ea0364f1SPeter Tyser 117ea0364f1SPeter Tyser static unsigned short lastinc; 118ea0364f1SPeter Tyser 119ea0364f1SPeter Tyser void __udelay(unsigned long usec) 120ea0364f1SPeter Tyser { 121ea0364f1SPeter Tyser volatile pit_t *timerp = (pit_t *) (CONFIG_SYS_UDELAY_BASE); 122ea0364f1SPeter Tyser uint tmp; 123ea0364f1SPeter Tyser 124ea0364f1SPeter Tyser while (usec > 0) { 125ea0364f1SPeter Tyser if (usec > 65000) 126ea0364f1SPeter Tyser tmp = 65000; 127ea0364f1SPeter Tyser else 128ea0364f1SPeter Tyser tmp = usec; 129ea0364f1SPeter Tyser usec = usec - tmp; 130ea0364f1SPeter Tyser 131ea0364f1SPeter Tyser /* Set up TIMER 3 as timebase clock */ 132ea0364f1SPeter Tyser timerp->pcsr = PIT_PCSR_OVW; 133ea0364f1SPeter Tyser timerp->pmr = 0; 134ea0364f1SPeter Tyser /* set period to 1 us */ 135ea0364f1SPeter Tyser timerp->pcsr |= PIT_PCSR_PRE(CONFIG_SYS_PIT_PRESCALE) | PIT_PCSR_EN; 136ea0364f1SPeter Tyser 137ea0364f1SPeter Tyser timerp->pmr = tmp; 138ea0364f1SPeter Tyser while (timerp->pcntr > 0) ; 139ea0364f1SPeter Tyser } 140ea0364f1SPeter Tyser } 141ea0364f1SPeter Tyser 142ea0364f1SPeter Tyser void timer_init(void) 143ea0364f1SPeter Tyser { 144ea0364f1SPeter Tyser volatile pit_t *timerp = (pit_t *) (CONFIG_SYS_PIT_BASE); 145ea0364f1SPeter Tyser timestamp = 0; 146ea0364f1SPeter Tyser 147ea0364f1SPeter Tyser /* Set up TIMER 4 as poll clock */ 148ea0364f1SPeter Tyser timerp->pcsr = PIT_PCSR_OVW; 149ea0364f1SPeter Tyser timerp->pmr = lastinc = 0; 150ea0364f1SPeter Tyser timerp->pcsr |= PIT_PCSR_PRE(CONFIG_SYS_PIT_PRESCALE) | PIT_PCSR_EN; 151444ddfc7SJason Jin 152444ddfc7SJason Jin return 0; 153ea0364f1SPeter Tyser } 154ea0364f1SPeter Tyser 155ea0364f1SPeter Tyser ulong get_timer(ulong base) 156ea0364f1SPeter Tyser { 157ea0364f1SPeter Tyser unsigned short now, diff; 158ea0364f1SPeter Tyser volatile pit_t *timerp = (pit_t *) (CONFIG_SYS_PIT_BASE); 159ea0364f1SPeter Tyser 160ea0364f1SPeter Tyser now = timerp->pcntr; 161ea0364f1SPeter Tyser diff = -(now - lastinc); 162ea0364f1SPeter Tyser 163ea0364f1SPeter Tyser timestamp += diff; 164ea0364f1SPeter Tyser lastinc = now; 165ea0364f1SPeter Tyser return timestamp - base; 166ea0364f1SPeter Tyser } 167ea0364f1SPeter Tyser 168ea0364f1SPeter Tyser void wait_ticks(unsigned long ticks) 169ea0364f1SPeter Tyser { 1705c8404afSGraeme Russ u32 start = get_timer(0); 1715c8404afSGraeme Russ while (get_timer(start) < ticks) ; 172ea0364f1SPeter Tyser } 173ea0364f1SPeter Tyser #endif /* CONFIG_MCFPIT */ 174ea0364f1SPeter Tyser 175ea0364f1SPeter Tyser /* 176ea0364f1SPeter Tyser * This function is derived from PowerPC code (read timebase as long long). 177ea0364f1SPeter Tyser * On M68K it just returns the timer value. 178ea0364f1SPeter Tyser */ 179ea0364f1SPeter Tyser unsigned long long get_ticks(void) 180ea0364f1SPeter Tyser { 181ea0364f1SPeter Tyser return get_timer(0); 182ea0364f1SPeter Tyser } 183ea0364f1SPeter Tyser 184ea0364f1SPeter Tyser unsigned long usec2ticks(unsigned long usec) 185ea0364f1SPeter Tyser { 186ea0364f1SPeter Tyser return get_timer(usec); 187ea0364f1SPeter Tyser } 188ea0364f1SPeter Tyser 189ea0364f1SPeter Tyser /* 190ea0364f1SPeter Tyser * This function is derived from PowerPC code (timebase clock frequency). 191ea0364f1SPeter Tyser * On M68K it returns the number of timer ticks per second. 192ea0364f1SPeter Tyser */ 193ea0364f1SPeter Tyser ulong get_tbclk(void) 194ea0364f1SPeter Tyser { 195*63a7578eSMasahiro Yamada return CONFIG_SYS_HZ; 196ea0364f1SPeter Tyser } 197