1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2003 Josef Baumgartner <josef.baumgartner@telex.de>
4  *
5  * (C) Copyright 2000
6  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
7  */
8 
9 #include <common.h>
10 #include <init.h>
11 #include <irq_func.h>
12 #include <time.h>
13 #include <asm/global_data.h>
14 #include <linux/delay.h>
15 
16 #include <asm/timer.h>
17 #include <asm/immap.h>
18 #include <watchdog.h>
19 
20 DECLARE_GLOBAL_DATA_PTR;
21 
22 static volatile ulong timestamp = 0;
23 
24 #ifndef CONFIG_SYS_WATCHDOG_FREQ
25 #define CONFIG_SYS_WATCHDOG_FREQ (CONFIG_SYS_HZ / 2)
26 #endif
27 
28 #if defined(CONFIG_MCFTMR)
29 #ifndef CONFIG_SYS_UDELAY_BASE
30 #	error	"uDelay base not defined!"
31 #endif
32 
33 #if !defined(CONFIG_SYS_TMR_BASE) || !defined(CONFIG_SYS_INTR_BASE) || !defined(CONFIG_SYS_TMRINTR_NO) || !defined(CONFIG_SYS_TMRINTR_MASK)
34 #	error	"TMR_BASE, INTR_BASE, TMRINTR_NO or TMRINTR_MASk not defined!"
35 #endif
36 extern void dtimer_intr_setup(void);
37 
__udelay(unsigned long usec)38 void __udelay(unsigned long usec)
39 {
40 	volatile dtmr_t *timerp = (dtmr_t *) (CONFIG_SYS_UDELAY_BASE);
41 	uint start, now, tmp;
42 
43 	while (usec > 0) {
44 		if (usec > 65000)
45 			tmp = 65000;
46 		else
47 			tmp = usec;
48 		usec = usec - tmp;
49 
50 		/* Set up TIMER 3 as timebase clock */
51 		timerp->tmr = DTIM_DTMR_RST_RST;
52 		timerp->tcn = 0;
53 		/* set period to 1 us */
54 		timerp->tmr =
55 		    CONFIG_SYS_TIMER_PRESCALER | DTIM_DTMR_CLK_DIV1 | DTIM_DTMR_FRR |
56 		    DTIM_DTMR_RST_EN;
57 
58 		start = now = timerp->tcn;
59 		while (now < start + tmp)
60 			now = timerp->tcn;
61 	}
62 }
63 
dtimer_interrupt(void * not_used)64 void dtimer_interrupt(void *not_used)
65 {
66 	volatile dtmr_t *timerp = (dtmr_t *) (CONFIG_SYS_TMR_BASE);
67 
68 	/* check for timer interrupt asserted */
69 	if ((CONFIG_SYS_TMRPND_REG & CONFIG_SYS_TMRINTR_MASK) == CONFIG_SYS_TMRINTR_PEND) {
70 		timerp->ter = (DTIM_DTER_CAP | DTIM_DTER_REF);
71 		timestamp++;
72 
73 		#if defined(CONFIG_WATCHDOG) || defined (CONFIG_HW_WATCHDOG)
74 		if (CONFIG_SYS_WATCHDOG_FREQ && (timestamp % (CONFIG_SYS_WATCHDOG_FREQ)) == 0) {
75 			WATCHDOG_RESET ();
76 		}
77 		#endif    /* CONFIG_WATCHDOG || CONFIG_HW_WATCHDOG */
78 		return;
79 	}
80 }
81 
timer_init(void)82 int timer_init(void)
83 {
84 	volatile dtmr_t *timerp = (dtmr_t *) (CONFIG_SYS_TMR_BASE);
85 
86 	timestamp = 0;
87 
88 	timerp->tcn = 0;
89 	timerp->trr = 0;
90 
91 	/* Set up TIMER 4 as clock */
92 	timerp->tmr = DTIM_DTMR_RST_RST;
93 
94 	/* initialize and enable timer interrupt */
95 	irq_install_handler(CONFIG_SYS_TMRINTR_NO, dtimer_interrupt, 0);
96 
97 	timerp->tcn = 0;
98 	timerp->trr = 1000;	/* Interrupt every ms */
99 
100 	dtimer_intr_setup();
101 
102 	/* set a period of 1us, set timer mode to restart and enable timer and interrupt */
103 	timerp->tmr = CONFIG_SYS_TIMER_PRESCALER | DTIM_DTMR_CLK_DIV1 |
104 	    DTIM_DTMR_FRR | DTIM_DTMR_ORRI | DTIM_DTMR_RST_EN;
105 
106 	return 0;
107 }
108 
get_timer(ulong base)109 ulong get_timer(ulong base)
110 {
111 	return (timestamp - base);
112 }
113 
114 #endif				/* CONFIG_MCFTMR */
115 
116 /*
117  * This function is derived from PowerPC code (read timebase as long long).
118  * On M68K it just returns the timer value.
119  */
get_ticks(void)120 unsigned long long get_ticks(void)
121 {
122 	return get_timer(0);
123 }
124 
usec2ticks(unsigned long usec)125 unsigned long usec2ticks(unsigned long usec)
126 {
127 	return get_timer(usec);
128 }
129 
130 /*
131  * This function is derived from PowerPC code (timebase clock frequency).
132  * On M68K it returns the number of timer ticks per second.
133  */
get_tbclk(void)134 ulong get_tbclk(void)
135 {
136 	return CONFIG_SYS_HZ;
137 }
138