xref: /rk3399_rockchip-uboot/arch/m68k/lib/time.c (revision ea0364f1bbfed1e3ea711147420875cf338fe77a)
1*ea0364f1SPeter Tyser /*
2*ea0364f1SPeter Tyser  * (C) Copyright 2003 Josef Baumgartner <josef.baumgartner@telex.de>
3*ea0364f1SPeter Tyser  *
4*ea0364f1SPeter Tyser  * (C) Copyright 2000
5*ea0364f1SPeter Tyser  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
6*ea0364f1SPeter Tyser  *
7*ea0364f1SPeter Tyser  * See file CREDITS for list of people who contributed to this
8*ea0364f1SPeter Tyser  * project.
9*ea0364f1SPeter Tyser  *
10*ea0364f1SPeter Tyser  * This program is free software; you can redistribute it and/or
11*ea0364f1SPeter Tyser  * modify it under the terms of the GNU General Public License as
12*ea0364f1SPeter Tyser  * published by the Free Software Foundation; either version 2 of
13*ea0364f1SPeter Tyser  * the License, or (at your option) any later version.
14*ea0364f1SPeter Tyser  *
15*ea0364f1SPeter Tyser  * This program is distributed in the hope that it will be useful,
16*ea0364f1SPeter Tyser  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*ea0364f1SPeter Tyser  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
18*ea0364f1SPeter Tyser  * GNU General Public License for more details.
19*ea0364f1SPeter Tyser  *
20*ea0364f1SPeter Tyser  * You should have received a copy of the GNU General Public License
21*ea0364f1SPeter Tyser  * along with this program; if not, write to the Free Software
22*ea0364f1SPeter Tyser  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23*ea0364f1SPeter Tyser  * MA 02111-1307 USA
24*ea0364f1SPeter Tyser  */
25*ea0364f1SPeter Tyser 
26*ea0364f1SPeter Tyser #include <common.h>
27*ea0364f1SPeter Tyser 
28*ea0364f1SPeter Tyser #include <asm/timer.h>
29*ea0364f1SPeter Tyser #include <asm/immap.h>
30*ea0364f1SPeter Tyser #include <watchdog.h>
31*ea0364f1SPeter Tyser 
32*ea0364f1SPeter Tyser DECLARE_GLOBAL_DATA_PTR;
33*ea0364f1SPeter Tyser 
34*ea0364f1SPeter Tyser static volatile ulong timestamp = 0;
35*ea0364f1SPeter Tyser 
36*ea0364f1SPeter Tyser #ifndef CONFIG_SYS_WATCHDOG_FREQ
37*ea0364f1SPeter Tyser #define CONFIG_SYS_WATCHDOG_FREQ (CONFIG_SYS_HZ / 2)
38*ea0364f1SPeter Tyser #endif
39*ea0364f1SPeter Tyser 
40*ea0364f1SPeter Tyser #if defined(CONFIG_MCFTMR)
41*ea0364f1SPeter Tyser #ifndef CONFIG_SYS_UDELAY_BASE
42*ea0364f1SPeter Tyser #	error	"uDelay base not defined!"
43*ea0364f1SPeter Tyser #endif
44*ea0364f1SPeter Tyser 
45*ea0364f1SPeter Tyser #if !defined(CONFIG_SYS_TMR_BASE) || !defined(CONFIG_SYS_INTR_BASE) || !defined(CONFIG_SYS_TMRINTR_NO) || !defined(CONFIG_SYS_TMRINTR_MASK)
46*ea0364f1SPeter Tyser #	error	"TMR_BASE, INTR_BASE, TMRINTR_NO or TMRINTR_MASk not defined!"
47*ea0364f1SPeter Tyser #endif
48*ea0364f1SPeter Tyser extern void dtimer_intr_setup(void);
49*ea0364f1SPeter Tyser 
50*ea0364f1SPeter Tyser void __udelay(unsigned long usec)
51*ea0364f1SPeter Tyser {
52*ea0364f1SPeter Tyser 	volatile dtmr_t *timerp = (dtmr_t *) (CONFIG_SYS_UDELAY_BASE);
53*ea0364f1SPeter Tyser 	uint start, now, tmp;
54*ea0364f1SPeter Tyser 
55*ea0364f1SPeter Tyser 	while (usec > 0) {
56*ea0364f1SPeter Tyser 		if (usec > 65000)
57*ea0364f1SPeter Tyser 			tmp = 65000;
58*ea0364f1SPeter Tyser 		else
59*ea0364f1SPeter Tyser 			tmp = usec;
60*ea0364f1SPeter Tyser 		usec = usec - tmp;
61*ea0364f1SPeter Tyser 
62*ea0364f1SPeter Tyser 		/* Set up TIMER 3 as timebase clock */
63*ea0364f1SPeter Tyser 		timerp->tmr = DTIM_DTMR_RST_RST;
64*ea0364f1SPeter Tyser 		timerp->tcn = 0;
65*ea0364f1SPeter Tyser 		/* set period to 1 us */
66*ea0364f1SPeter Tyser 		timerp->tmr =
67*ea0364f1SPeter Tyser 		    CONFIG_SYS_TIMER_PRESCALER | DTIM_DTMR_CLK_DIV1 | DTIM_DTMR_FRR |
68*ea0364f1SPeter Tyser 		    DTIM_DTMR_RST_EN;
69*ea0364f1SPeter Tyser 
70*ea0364f1SPeter Tyser 		start = now = timerp->tcn;
71*ea0364f1SPeter Tyser 		while (now < start + tmp)
72*ea0364f1SPeter Tyser 			now = timerp->tcn;
73*ea0364f1SPeter Tyser 	}
74*ea0364f1SPeter Tyser }
75*ea0364f1SPeter Tyser 
76*ea0364f1SPeter Tyser void dtimer_interrupt(void *not_used)
77*ea0364f1SPeter Tyser {
78*ea0364f1SPeter Tyser 	volatile dtmr_t *timerp = (dtmr_t *) (CONFIG_SYS_TMR_BASE);
79*ea0364f1SPeter Tyser 
80*ea0364f1SPeter Tyser 	/* check for timer interrupt asserted */
81*ea0364f1SPeter Tyser 	if ((CONFIG_SYS_TMRPND_REG & CONFIG_SYS_TMRINTR_MASK) == CONFIG_SYS_TMRINTR_PEND) {
82*ea0364f1SPeter Tyser 		timerp->ter = (DTIM_DTER_CAP | DTIM_DTER_REF);
83*ea0364f1SPeter Tyser 		timestamp++;
84*ea0364f1SPeter Tyser 
85*ea0364f1SPeter Tyser 		#if defined(CONFIG_WATCHDOG) || defined (CONFIG_HW_WATCHDOG)
86*ea0364f1SPeter Tyser 		if ((timestamp % (CONFIG_SYS_WATCHDOG_FREQ)) == 0) {
87*ea0364f1SPeter Tyser 			WATCHDOG_RESET ();
88*ea0364f1SPeter Tyser 		}
89*ea0364f1SPeter Tyser 		#endif    /* CONFIG_WATCHDOG || CONFIG_HW_WATCHDOG */
90*ea0364f1SPeter Tyser 		return;
91*ea0364f1SPeter Tyser 	}
92*ea0364f1SPeter Tyser }
93*ea0364f1SPeter Tyser 
94*ea0364f1SPeter Tyser void timer_init(void)
95*ea0364f1SPeter Tyser {
96*ea0364f1SPeter Tyser 	volatile dtmr_t *timerp = (dtmr_t *) (CONFIG_SYS_TMR_BASE);
97*ea0364f1SPeter Tyser 
98*ea0364f1SPeter Tyser 	timestamp = 0;
99*ea0364f1SPeter Tyser 
100*ea0364f1SPeter Tyser 	timerp->tcn = 0;
101*ea0364f1SPeter Tyser 	timerp->trr = 0;
102*ea0364f1SPeter Tyser 
103*ea0364f1SPeter Tyser 	/* Set up TIMER 4 as clock */
104*ea0364f1SPeter Tyser 	timerp->tmr = DTIM_DTMR_RST_RST;
105*ea0364f1SPeter Tyser 
106*ea0364f1SPeter Tyser 	/* initialize and enable timer interrupt */
107*ea0364f1SPeter Tyser 	irq_install_handler(CONFIG_SYS_TMRINTR_NO, dtimer_interrupt, 0);
108*ea0364f1SPeter Tyser 
109*ea0364f1SPeter Tyser 	timerp->tcn = 0;
110*ea0364f1SPeter Tyser 	timerp->trr = 1000;	/* Interrupt every ms */
111*ea0364f1SPeter Tyser 
112*ea0364f1SPeter Tyser 	dtimer_intr_setup();
113*ea0364f1SPeter Tyser 
114*ea0364f1SPeter Tyser 	/* set a period of 1us, set timer mode to restart and enable timer and interrupt */
115*ea0364f1SPeter Tyser 	timerp->tmr = CONFIG_SYS_TIMER_PRESCALER | DTIM_DTMR_CLK_DIV1 |
116*ea0364f1SPeter Tyser 	    DTIM_DTMR_FRR | DTIM_DTMR_ORRI | DTIM_DTMR_RST_EN;
117*ea0364f1SPeter Tyser }
118*ea0364f1SPeter Tyser 
119*ea0364f1SPeter Tyser void reset_timer(void)
120*ea0364f1SPeter Tyser {
121*ea0364f1SPeter Tyser 	timestamp = 0;
122*ea0364f1SPeter Tyser }
123*ea0364f1SPeter Tyser 
124*ea0364f1SPeter Tyser ulong get_timer(ulong base)
125*ea0364f1SPeter Tyser {
126*ea0364f1SPeter Tyser 	return (timestamp - base);
127*ea0364f1SPeter Tyser }
128*ea0364f1SPeter Tyser 
129*ea0364f1SPeter Tyser void set_timer(ulong t)
130*ea0364f1SPeter Tyser {
131*ea0364f1SPeter Tyser 	timestamp = t;
132*ea0364f1SPeter Tyser }
133*ea0364f1SPeter Tyser #endif				/* CONFIG_MCFTMR */
134*ea0364f1SPeter Tyser 
135*ea0364f1SPeter Tyser #if defined(CONFIG_MCFPIT)
136*ea0364f1SPeter Tyser #if !defined(CONFIG_SYS_PIT_BASE)
137*ea0364f1SPeter Tyser #	error	"CONFIG_SYS_PIT_BASE not defined!"
138*ea0364f1SPeter Tyser #endif
139*ea0364f1SPeter Tyser 
140*ea0364f1SPeter Tyser static unsigned short lastinc;
141*ea0364f1SPeter Tyser 
142*ea0364f1SPeter Tyser void __udelay(unsigned long usec)
143*ea0364f1SPeter Tyser {
144*ea0364f1SPeter Tyser 	volatile pit_t *timerp = (pit_t *) (CONFIG_SYS_UDELAY_BASE);
145*ea0364f1SPeter Tyser 	uint tmp;
146*ea0364f1SPeter Tyser 
147*ea0364f1SPeter Tyser 	while (usec > 0) {
148*ea0364f1SPeter Tyser 		if (usec > 65000)
149*ea0364f1SPeter Tyser 			tmp = 65000;
150*ea0364f1SPeter Tyser 		else
151*ea0364f1SPeter Tyser 			tmp = usec;
152*ea0364f1SPeter Tyser 		usec = usec - tmp;
153*ea0364f1SPeter Tyser 
154*ea0364f1SPeter Tyser 		/* Set up TIMER 3 as timebase clock */
155*ea0364f1SPeter Tyser 		timerp->pcsr = PIT_PCSR_OVW;
156*ea0364f1SPeter Tyser 		timerp->pmr = 0;
157*ea0364f1SPeter Tyser 		/* set period to 1 us */
158*ea0364f1SPeter Tyser 		timerp->pcsr |= PIT_PCSR_PRE(CONFIG_SYS_PIT_PRESCALE) | PIT_PCSR_EN;
159*ea0364f1SPeter Tyser 
160*ea0364f1SPeter Tyser 		timerp->pmr = tmp;
161*ea0364f1SPeter Tyser 		while (timerp->pcntr > 0) ;
162*ea0364f1SPeter Tyser 	}
163*ea0364f1SPeter Tyser }
164*ea0364f1SPeter Tyser 
165*ea0364f1SPeter Tyser void timer_init(void)
166*ea0364f1SPeter Tyser {
167*ea0364f1SPeter Tyser 	volatile pit_t *timerp = (pit_t *) (CONFIG_SYS_PIT_BASE);
168*ea0364f1SPeter Tyser 	timestamp = 0;
169*ea0364f1SPeter Tyser 
170*ea0364f1SPeter Tyser 	/* Set up TIMER 4 as poll clock */
171*ea0364f1SPeter Tyser 	timerp->pcsr = PIT_PCSR_OVW;
172*ea0364f1SPeter Tyser 	timerp->pmr = lastinc = 0;
173*ea0364f1SPeter Tyser 	timerp->pcsr |= PIT_PCSR_PRE(CONFIG_SYS_PIT_PRESCALE) | PIT_PCSR_EN;
174*ea0364f1SPeter Tyser }
175*ea0364f1SPeter Tyser 
176*ea0364f1SPeter Tyser void set_timer(ulong t)
177*ea0364f1SPeter Tyser {
178*ea0364f1SPeter Tyser 	volatile pit_t *timerp = (pit_t *) (CONFIG_SYS_PIT_BASE);
179*ea0364f1SPeter Tyser 
180*ea0364f1SPeter Tyser 	timestamp = 0;
181*ea0364f1SPeter Tyser 	timerp->pmr = lastinc = 0;
182*ea0364f1SPeter Tyser }
183*ea0364f1SPeter Tyser 
184*ea0364f1SPeter Tyser ulong get_timer(ulong base)
185*ea0364f1SPeter Tyser {
186*ea0364f1SPeter Tyser 	unsigned short now, diff;
187*ea0364f1SPeter Tyser 	volatile pit_t *timerp = (pit_t *) (CONFIG_SYS_PIT_BASE);
188*ea0364f1SPeter Tyser 
189*ea0364f1SPeter Tyser 	now = timerp->pcntr;
190*ea0364f1SPeter Tyser 	diff = -(now - lastinc);
191*ea0364f1SPeter Tyser 
192*ea0364f1SPeter Tyser 	timestamp += diff;
193*ea0364f1SPeter Tyser 	lastinc = now;
194*ea0364f1SPeter Tyser 	return timestamp - base;
195*ea0364f1SPeter Tyser }
196*ea0364f1SPeter Tyser 
197*ea0364f1SPeter Tyser void wait_ticks(unsigned long ticks)
198*ea0364f1SPeter Tyser {
199*ea0364f1SPeter Tyser 	set_timer(0);
200*ea0364f1SPeter Tyser 	while (get_timer(0) < ticks) ;
201*ea0364f1SPeter Tyser }
202*ea0364f1SPeter Tyser #endif				/* CONFIG_MCFPIT */
203*ea0364f1SPeter Tyser 
204*ea0364f1SPeter Tyser /*
205*ea0364f1SPeter Tyser  * This function is derived from PowerPC code (read timebase as long long).
206*ea0364f1SPeter Tyser  * On M68K it just returns the timer value.
207*ea0364f1SPeter Tyser  */
208*ea0364f1SPeter Tyser unsigned long long get_ticks(void)
209*ea0364f1SPeter Tyser {
210*ea0364f1SPeter Tyser 	return get_timer(0);
211*ea0364f1SPeter Tyser }
212*ea0364f1SPeter Tyser 
213*ea0364f1SPeter Tyser unsigned long usec2ticks(unsigned long usec)
214*ea0364f1SPeter Tyser {
215*ea0364f1SPeter Tyser 	return get_timer(usec);
216*ea0364f1SPeter Tyser }
217*ea0364f1SPeter Tyser 
218*ea0364f1SPeter Tyser /*
219*ea0364f1SPeter Tyser  * This function is derived from PowerPC code (timebase clock frequency).
220*ea0364f1SPeter Tyser  * On M68K it returns the number of timer ticks per second.
221*ea0364f1SPeter Tyser  */
222*ea0364f1SPeter Tyser ulong get_tbclk(void)
223*ea0364f1SPeter Tyser {
224*ea0364f1SPeter Tyser 	ulong tbclk;
225*ea0364f1SPeter Tyser 	tbclk = CONFIG_SYS_HZ;
226*ea0364f1SPeter Tyser 	return tbclk;
227*ea0364f1SPeter Tyser }
228