1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
4 * Timer routines File: cfe_timer.c
6 * This module contains routines to keep track of the system time,.
7 * Since we don't have any interrupts in the firmware, even the
8 * timer is polled. The timer must be called often enough
9 * to prevent missing the overflow of the CP0 COUNT
10 * register, approximately 2 billion cycles (half the count)
12 * Be sure to use the POLL() macro each time you enter a loop
13 * where you are waiting for some I/O event to occur or
14 * are waiting for time to elapse.
16 * It is *not* a time-of-year clock. The timer is only used
17 * for timing I/O events.
19 * Internally, time is maintained in units of "CLOCKSPERTICK",
20 * which should be about tenths of seconds.
22 * Author: Mitch Lichtenberg (mpl@broadcom.com)
24 *********************************************************************
26 * Copyright 2000,2001,2002,2003
27 * Broadcom Corporation. All rights reserved.
29 * This software is furnished under license and may be used and
30 * copied only in accordance with the following terms and
31 * conditions. Subject to these conditions, you may download,
32 * copy, install, use, modify and distribute modified or unmodified
33 * copies of this software in source and/or binary form. No title
34 * or ownership is transferred hereby.
36 * 1) Any source code used, modified or distributed must reproduce
37 * and retain this copyright notice and list of conditions
38 * as they appear in the source file.
40 * 2) No right is granted to use any trade name, trademark, or
41 * logo of Broadcom Corporation. The "Broadcom Corporation"
42 * name may not be used to endorse or promote products derived
43 * from this software without the prior written permission of
44 * Broadcom Corporation.
46 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
47 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
48 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
49 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
50 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
51 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
52 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
53 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
54 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
55 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
56 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
57 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
58 * THE POSSIBILITY OF SUCH DAMAGE.
59 ********************************************************************* */
62 #include "lib_types.h"
63 #include "lib_printf.h"
65 #include "cfe_timer.h"
69 #include "bsp_config.h"
70 #include "cpu_config.h"
73 #define CFG_CPU_SPEED 500000 /* CPU speed in Hz */
76 #ifndef CPUCFG_CYCLESPERCPUTICK
77 #define CPUCFG_CYCLESPERCPUTICK 1 /* CPU clock ticks per CP0 COUNT */
80 /* *********************************************************************
82 ********************************************************************* */
84 extern int32_t _getticks(void); /* return value of CP0 COUNT */
86 /* *********************************************************************
88 ********************************************************************* */
90 volatile int64_t cfe_ticks
; /* current system time */
92 int cfe_cpu_speed
; /* CPU speed in clocks/second */
94 /* With current technology, we would like to accomodate
95 sub-microsecond delays, but clocks per nanosecond may be a small
96 number. For more precision, we convert in terms of Kns, where
97 one Kns = 1024 nsec, and scale by shifting. */
99 /* We assume that cfe_cpu_speed gets updated before cfe_timer_init is
100 called. Currently, it's done in console_init. It would be better
101 as an argument of cfe_timer_init, but that's a lot of editing. */
102 static unsigned int cfe_clocks_per_Kns
;
103 static unsigned int cfe_clocks_per_usec
;
104 static unsigned int cfe_clocks_per_tick
;
106 static int32_t cfe_oldcount
; /* For keeping track of ticks */
107 static int32_t cfe_remticks
;
108 static int cfe_timer_initflg
= 0;
111 * C0_COUNT clocks per microsecond and per tick. Some CPUs tick CP0
112 * every 'n' cycles, that's what CPUCFG_CYCLESPERCPUTICK is for. */
113 #define CFE_CLOCKSPERUSEC (cfe_cpu_speed/1000000/(CPUCFG_CYCLESPERCPUTICK))
114 #define CFE_CLOCKSPERKNS (cfe_cpu_speed/976563/(CPUCFG_CYCLESPERCPUTICK))
115 #define CFE_CLOCKSPERTICK (cfe_cpu_speed/(CFE_HZ)/(CPUCFG_CYCLESPERCPUTICK))
118 /* *********************************************************************
121 * This routine is called as part of normal device polling to
122 * update the system time. We read the CP0 COUNT register,
123 * add the delta into our current time, convert to ticks,
124 * and keep track of the COUNT register overflow
131 ********************************************************************* */
134 static void cfe_timer_task(void *arg
)
138 int32_t clockspertick
;
140 clockspertick
= CFE_CLOCKSPERTICK
;
144 if (count
>= cfe_oldcount
) {
145 deltaticks
= (count
- cfe_oldcount
) / clockspertick
;
146 cfe_remticks
+= (count
- cfe_oldcount
) % clockspertick
;
149 deltaticks
= (cfe_oldcount
- count
) / clockspertick
;
150 cfe_remticks
+= (cfe_oldcount
- count
) % clockspertick
;
153 cfe_ticks
+= deltaticks
+ (cfe_remticks
/ clockspertick
);
154 cfe_remticks
%= clockspertick
;
155 cfe_oldcount
= count
;
159 /* *********************************************************************
162 * Initialize the timer module.
169 ********************************************************************* */
171 void cfe_timer_init(void)
173 cfe_clocks_per_tick
= CFE_CLOCKSPERTICK
;
174 cfe_clocks_per_Kns
= CFE_CLOCKSPERKNS
;
175 if (cfe_clocks_per_Kns
== 0)
176 cfe_clocks_per_Kns
= 1; /* for the simulator */
177 cfe_clocks_per_usec
= CFE_CLOCKSPERUSEC
;
178 if (cfe_clocks_per_usec
== 0)
179 cfe_clocks_per_usec
= 1; /* for the simulator */
181 cfe_oldcount
= _getticks(); /* get current COUNT register */
184 if (!cfe_timer_initflg
) {
185 cfe_bg_add(cfe_timer_task
,NULL
); /* add task for background polling */
186 cfe_timer_initflg
= 1;
191 /* *********************************************************************
194 * Sleep for 'ticks' ticks. Background tasks are processed while
198 * ticks - number of ticks to sleep (note: *not* clocks!)
202 ********************************************************************* */
204 void cfe_sleep(int ticks
)
208 TIMER_SET(timer
,ticks
);
209 while (!TIMER_EXPIRED(timer
)) {
216 /* *********************************************************************
219 * Sleep for approximately the specified number of microseconds.
222 * usec - number of microseconds to wait
226 ********************************************************************* */
228 void cfe_usleep(int usec
)
235 newcount
= now
+ usec
*cfe_clocks_per_usec
;
237 if (newcount
< now
) /* wait for wraparound */
238 while (_getticks() > now
)
242 while (_getticks() < newcount
)
247 /* *********************************************************************
250 * Sleep for approximately the specified number of nanoseconds.
253 * nsec - number of nanoseconds to wait
257 ********************************************************************* */
259 void cfe_nsleep(int nsec
)
266 newcount
= now
+ ((nsec
*cfe_clocks_per_Kns
+ 512) >> 10);
268 if (newcount
< now
) /* wait for wraparound */
269 while (_getticks() > now
)
272 while (_getticks() < newcount
)