1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  Timer routines				File: cfe_timer.c
5    *
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)
11    *
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.
15    *
16    *  It is *not* a time-of-year clock.  The timer is only used
17    *  for timing I/O events.
18    *
19    *  Internally, time is maintained in units of "CLOCKSPERTICK",
20    *  which should be about tenths of seconds.
21    *
22    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
23    *
24    *********************************************************************
25    *
26    *  Copyright 2000,2001,2002,2003
27    *  Broadcom Corporation. All rights reserved.
28    *
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.
35    *
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.
39    *
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.
45    *
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    ********************************************************************* */
60
61
62#include "lib_types.h"
63#include "lib_printf.h"
64
65#include "cfe_timer.h"
66
67#include "cfe.h"
68
69#include "bsp_config.h"
70#include "cpu_config.h"
71
72#ifndef CFG_CPU_SPEED
73#define CFG_CPU_SPEED	500000		/* CPU speed in Hz */
74#endif
75
76#ifndef CPUCFG_CYCLESPERCPUTICK
77#define CPUCFG_CYCLESPERCPUTICK 1	/* CPU clock ticks per CP0 COUNT */
78#endif
79
80/*  *********************************************************************
81    *  Externs
82    ********************************************************************* */
83
84extern int32_t _getticks(void);		/* return value of CP0 COUNT */
85
86/*  *********************************************************************
87    *  Data
88    ********************************************************************* */
89
90volatile int64_t cfe_ticks;		/* current system time */
91
92int cfe_cpu_speed;			/* CPU speed in clocks/second */
93
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. */
98
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. */
102static unsigned int cfe_clocks_per_Kns;
103static unsigned int cfe_clocks_per_usec;
104static unsigned int cfe_clocks_per_tick;
105
106static int32_t cfe_oldcount;		/* For keeping track of ticks */
107static int32_t cfe_remticks;
108static int cfe_timer_initflg = 0;
109
110/*
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))
116
117
118/*  *********************************************************************
119    *  cfe_timer_task()
120    *
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
125    *
126    *  Input parameters:
127    *  	   nothing
128    *
129    *  Return value:
130    *  	   nothing
131    ********************************************************************* */
132
133
134static void cfe_timer_task(void *arg)
135{
136    int32_t count;
137    int32_t deltaticks;
138    int32_t clockspertick;
139
140    clockspertick = CFE_CLOCKSPERTICK;
141
142    count = _getticks();
143
144    if (count >= cfe_oldcount) {
145	deltaticks    = (count - cfe_oldcount) / clockspertick;
146	cfe_remticks += (count - cfe_oldcount) % clockspertick;
147	}
148    else {
149	deltaticks    = (cfe_oldcount - count) / clockspertick;
150	cfe_remticks += (cfe_oldcount - count) % clockspertick;
151	}
152
153    cfe_ticks += deltaticks + (cfe_remticks / clockspertick);
154    cfe_remticks %= clockspertick;
155    cfe_oldcount = count;
156}
157
158
159/*  *********************************************************************
160    *  cfe_timer_init()
161    *
162    *  Initialize the timer module.
163    *
164    *  Input parameters:
165    *  	   nothing
166    *
167    *  Return value:
168    *  	   nothing
169    ********************************************************************* */
170
171void cfe_timer_init(void)
172{
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 */
180
181    cfe_oldcount = _getticks();		/* get current COUNT register */
182    cfe_ticks = 0;
183
184    if (!cfe_timer_initflg) {
185	cfe_bg_add(cfe_timer_task,NULL); /* add task for background polling */
186	cfe_timer_initflg = 1;
187	}
188}
189
190
191/*  *********************************************************************
192    *  cfe_sleep(ticks)
193    *
194    *  Sleep for 'ticks' ticks.  Background tasks are processed while
195    *  we wait.
196    *
197    *  Input parameters:
198    *  	   ticks - number of ticks to sleep (note: *not* clocks!)
199    *
200    *  Return value:
201    *  	   nothing
202    ********************************************************************* */
203
204void cfe_sleep(int ticks)
205{
206    int64_t timer;
207
208    TIMER_SET(timer,ticks);
209    while (!TIMER_EXPIRED(timer)) {
210	POLL();
211	}
212}
213
214
215
216/*  *********************************************************************
217    *  cfe_usleep(usec)
218    *
219    *  Sleep for approximately the specified number of microseconds.
220    *
221    *  Input parameters:
222    *  	   usec - number of microseconds to wait
223    *
224    *  Return value:
225    *  	   nothing
226    ********************************************************************* */
227
228void cfe_usleep(int usec)
229{
230    uint32_t newcount;
231    uint32_t now;
232
233
234    now = _getticks();
235    newcount = now + usec*cfe_clocks_per_usec;
236
237    if (newcount < now)  	/* wait for wraparound */
238        while (_getticks() > now)
239	    ;
240
241
242    while (_getticks() < newcount)
243	;
244}
245
246
247/*  *********************************************************************
248    *  cfe_nsleep(nsec)
249    *
250    *  Sleep for approximately the specified number of nanoseconds.
251    *
252    *  Input parameters:
253    *  	   nsec - number of nanoseconds to wait
254    *
255    *  Return value:
256    *  	   nothing
257    ********************************************************************* */
258
259void cfe_nsleep(int nsec)
260{
261    uint32_t newcount;
262    uint32_t now;
263
264
265    now = _getticks();
266    newcount = now + ((nsec*cfe_clocks_per_Kns + 512) >> 10);
267
268    if (newcount < now)  	/* wait for wraparound */
269        while (_getticks() > now)
270	    ;
271
272    while (_getticks() < newcount)
273	;
274}
275