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