xref: /openbmc/u-boot/arch/m68k/lib/time.c (revision 87a62bce)
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 
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