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