xref: /OK3568_Linux_fs/u-boot/board/armltd/integrator/timer.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2002
3*4882a593Smuzhiyun  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
4*4882a593Smuzhiyun  * Marius Groeger <mgroeger@sysgo.de>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * (C) Copyright 2002
7*4882a593Smuzhiyun  * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch>
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * (C) Copyright 2003
10*4882a593Smuzhiyun  * Texas Instruments, <www.ti.com>
11*4882a593Smuzhiyun  * Kshitij Gupta <Kshitij@ti.com>
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  * (C) Copyright 2004
14*4882a593Smuzhiyun  * ARM Ltd.
15*4882a593Smuzhiyun  * Philippe Robin, <philippe.robin@arm.com>
16*4882a593Smuzhiyun  *
17*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
18*4882a593Smuzhiyun  */
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <common.h>
21*4882a593Smuzhiyun #include <div64.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #ifdef CONFIG_ARCH_CINTEGRATOR
24*4882a593Smuzhiyun #define DIV_CLOCK_INIT	1
25*4882a593Smuzhiyun #define TIMER_LOAD_VAL	0xFFFFFFFFL
26*4882a593Smuzhiyun #else
27*4882a593Smuzhiyun #define DIV_CLOCK_INIT	256
28*4882a593Smuzhiyun #define TIMER_LOAD_VAL	0x0000FFFFL
29*4882a593Smuzhiyun #endif
30*4882a593Smuzhiyun /* The Integrator/CP timer1 is clocked at 1MHz
31*4882a593Smuzhiyun  * can be divided by 16 or 256
32*4882a593Smuzhiyun  * and can be set up as a 32-bit timer
33*4882a593Smuzhiyun  */
34*4882a593Smuzhiyun /* U-Boot expects a 32 bit timer, running at CONFIG_SYS_HZ */
35*4882a593Smuzhiyun /* Keep total timer count to avoid losing decrements < div_timer */
36*4882a593Smuzhiyun static unsigned long long total_count = 0;
37*4882a593Smuzhiyun static unsigned long long lastdec;	 /* Timer reading at last call	   */
38*4882a593Smuzhiyun /* Divisor applied to timer clock */
39*4882a593Smuzhiyun static unsigned long long div_clock = DIV_CLOCK_INIT;
40*4882a593Smuzhiyun static unsigned long long div_timer = 1; /* Divisor to convert timer reading
41*4882a593Smuzhiyun 					  * change to U-Boot ticks
42*4882a593Smuzhiyun 					  */
43*4882a593Smuzhiyun /* CONFIG_SYS_HZ = CONFIG_SYS_HZ_CLOCK/(div_clock * div_timer) */
44*4882a593Smuzhiyun static ulong timestamp;		/* U-Boot ticks since startup */
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun #define READ_TIMER (*(volatile ulong *)(CONFIG_SYS_TIMERBASE+4))
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun /* all function return values in U-Boot ticks i.e. (1/CONFIG_SYS_HZ) sec
49*4882a593Smuzhiyun  *  - unless otherwise stated
50*4882a593Smuzhiyun  */
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun /* starts up a counter
53*4882a593Smuzhiyun  * - the Integrator/CP timer can be set up to issue an interrupt */
timer_init(void)54*4882a593Smuzhiyun int timer_init (void)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun 	/* Load timer with initial value */
57*4882a593Smuzhiyun 	*(volatile ulong *)(CONFIG_SYS_TIMERBASE + 0) = TIMER_LOAD_VAL;
58*4882a593Smuzhiyun #ifdef CONFIG_ARCH_CINTEGRATOR
59*4882a593Smuzhiyun 	/* Set timer to be
60*4882a593Smuzhiyun 	 *	enabled		 1
61*4882a593Smuzhiyun 	 *	periodic	 1
62*4882a593Smuzhiyun 	 *	no interrupts	 0
63*4882a593Smuzhiyun 	 *	X		 0
64*4882a593Smuzhiyun 	 *	divider 1	00 == less rounding error
65*4882a593Smuzhiyun 	 *	32 bit		 1
66*4882a593Smuzhiyun 	 *	wrapping	 0
67*4882a593Smuzhiyun 	 */
68*4882a593Smuzhiyun 	*(volatile ulong *)(CONFIG_SYS_TIMERBASE + 8) = 0x000000C2;
69*4882a593Smuzhiyun #else
70*4882a593Smuzhiyun 	/* Set timer to be
71*4882a593Smuzhiyun 	 *	enabled		 1
72*4882a593Smuzhiyun 	 *	free-running	 0
73*4882a593Smuzhiyun 	 *	XX		00
74*4882a593Smuzhiyun 	 *	divider 256	10
75*4882a593Smuzhiyun 	 *	XX		00
76*4882a593Smuzhiyun 	 */
77*4882a593Smuzhiyun 	*(volatile ulong *)(CONFIG_SYS_TIMERBASE + 8) = 0x00000088;
78*4882a593Smuzhiyun #endif
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	/* init the timestamp */
81*4882a593Smuzhiyun 	total_count = 0ULL;
82*4882a593Smuzhiyun 	/* capure current decrementer value    */
83*4882a593Smuzhiyun 	lastdec	  = READ_TIMER;
84*4882a593Smuzhiyun 	/* start "advancing" time stamp from 0 */
85*4882a593Smuzhiyun 	timestamp = 0L;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	div_timer = CONFIG_SYS_HZ_CLOCK;
88*4882a593Smuzhiyun 	do_div(div_timer, CONFIG_SYS_HZ);
89*4882a593Smuzhiyun 	do_div(div_timer, div_clock);
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	return (0);
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun /*
95*4882a593Smuzhiyun  * timer without interrupts
96*4882a593Smuzhiyun  */
get_timer(ulong base_ticks)97*4882a593Smuzhiyun ulong get_timer (ulong base_ticks)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun 	return get_timer_masked () - base_ticks;
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun /* delay usec useconds */
__udelay(unsigned long usec)103*4882a593Smuzhiyun void __udelay (unsigned long usec)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun 	ulong tmo, tmp;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	/* Convert to U-Boot ticks */
108*4882a593Smuzhiyun 	tmo  = usec * CONFIG_SYS_HZ;
109*4882a593Smuzhiyun 	tmo /= (1000000L);
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	tmp  = get_timer_masked();	/* get current timestamp */
112*4882a593Smuzhiyun 	tmo += tmp;			/* form target timestamp */
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	while (get_timer_masked () < tmo) {/* loop till event */
115*4882a593Smuzhiyun 		/*NOP*/;
116*4882a593Smuzhiyun 	}
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun /* converts the timer reading to U-Boot ticks	       */
120*4882a593Smuzhiyun /* the timestamp is the number of ticks since reset    */
get_timer_masked(void)121*4882a593Smuzhiyun ulong get_timer_masked (void)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun 	/* get current count */
124*4882a593Smuzhiyun 	unsigned long long now = READ_TIMER;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	if(now > lastdec) {
127*4882a593Smuzhiyun 		/* Must have wrapped */
128*4882a593Smuzhiyun 		total_count += lastdec + TIMER_LOAD_VAL + 1 - now;
129*4882a593Smuzhiyun 	} else {
130*4882a593Smuzhiyun 		total_count += lastdec - now;
131*4882a593Smuzhiyun 	}
132*4882a593Smuzhiyun 	lastdec	= now;
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	/* Reuse "now" */
135*4882a593Smuzhiyun 	now = total_count;
136*4882a593Smuzhiyun 	do_div(now, div_timer);
137*4882a593Smuzhiyun 	timestamp = now;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	return timestamp;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun /* waits specified delay value and resets timestamp */
udelay_masked(unsigned long usec)143*4882a593Smuzhiyun void udelay_masked (unsigned long usec)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun 	udelay(usec);
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun /*
149*4882a593Smuzhiyun  * This function is derived from PowerPC code (read timebase as long long).
150*4882a593Smuzhiyun  * On ARM it just returns the timer value.
151*4882a593Smuzhiyun  */
get_ticks(void)152*4882a593Smuzhiyun unsigned long long get_ticks(void)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun 	return get_timer(0);
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun /*
158*4882a593Smuzhiyun  * Return the timebase clock frequency
159*4882a593Smuzhiyun  * i.e. how often the timer decrements
160*4882a593Smuzhiyun  */
get_tbclk(void)161*4882a593Smuzhiyun ulong get_tbclk (void)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun 	unsigned long long tmp = CONFIG_SYS_HZ_CLOCK;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	do_div(tmp, div_clock);
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	return tmp;
168*4882a593Smuzhiyun }
169