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