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