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