1/***************************************************************************** 2* Copyright 2003 - 2008 Broadcom Corporation. All rights reserved. 3* 4* Unless you and Broadcom execute a separate written software license 5* agreement governing use of this software, this software is licensed to you 6* under the terms of the GNU General Public License version 2, available at 7* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). 8* 9* Notwithstanding the above, under no circumstances may you combine this 10* software in any way with any other Broadcom software provided under a 11* license other than the GPL, without Broadcom's express prior written 12* consent. 13*****************************************************************************/ 14 15/****************************************************************************/ 16/** 17* @file tmrHw.c 18* 19* @brief Low level Timer driver routines 20* 21* @note 22* 23* These routines provide basic timer functionality only. 24*/ 25/****************************************************************************/ 26 27/* ---- Include Files ---------------------------------------------------- */ 28 29#include <csp/errno.h> 30#include <csp/stdint.h> 31 32#include <csp/tmrHw.h> 33#include <mach/csp/tmrHw_reg.h> 34 35#define tmrHw_ASSERT(a) if (!(a)) *(char *)0 = 0 36#define tmrHw_MILLISEC_PER_SEC (1000) 37 38#define tmrHw_LOW_1_RESOLUTION_COUNT (tmrHw_LOW_RESOLUTION_CLOCK / tmrHw_MILLISEC_PER_SEC) 39#define tmrHw_LOW_1_MAX_MILLISEC (0xFFFFFFFF / tmrHw_LOW_1_RESOLUTION_COUNT) 40#define tmrHw_LOW_16_RESOLUTION_COUNT (tmrHw_LOW_1_RESOLUTION_COUNT / 16) 41#define tmrHw_LOW_16_MAX_MILLISEC (0xFFFFFFFF / tmrHw_LOW_16_RESOLUTION_COUNT) 42#define tmrHw_LOW_256_RESOLUTION_COUNT (tmrHw_LOW_1_RESOLUTION_COUNT / 256) 43#define tmrHw_LOW_256_MAX_MILLISEC (0xFFFFFFFF / tmrHw_LOW_256_RESOLUTION_COUNT) 44 45#define tmrHw_HIGH_1_RESOLUTION_COUNT (tmrHw_HIGH_RESOLUTION_CLOCK / tmrHw_MILLISEC_PER_SEC) 46#define tmrHw_HIGH_1_MAX_MILLISEC (0xFFFFFFFF / tmrHw_HIGH_1_RESOLUTION_COUNT) 47#define tmrHw_HIGH_16_RESOLUTION_COUNT (tmrHw_HIGH_1_RESOLUTION_COUNT / 16) 48#define tmrHw_HIGH_16_MAX_MILLISEC (0xFFFFFFFF / tmrHw_HIGH_16_RESOLUTION_COUNT) 49#define tmrHw_HIGH_256_RESOLUTION_COUNT (tmrHw_HIGH_1_RESOLUTION_COUNT / 256) 50#define tmrHw_HIGH_256_MAX_MILLISEC (0xFFFFFFFF / tmrHw_HIGH_256_RESOLUTION_COUNT) 51 52static void ResetTimer(tmrHw_ID_t timerId) 53 __attribute__ ((section(".aramtext"))); 54static int tmrHw_divide(int num, int denom) 55 __attribute__ ((section(".aramtext"))); 56 57/****************************************************************************/ 58/** 59* @brief Get timer capability 60* 61* This function returns various capabilities/attributes of a timer 62* 63* @return Capability 64* 65*/ 66/****************************************************************************/ 67uint32_t tmrHw_getTimerCapability(tmrHw_ID_t timerId, /* [ IN ] Timer Id */ 68 tmrHw_CAPABILITY_e capability /* [ IN ] Timer capability */ 69) { 70 switch (capability) { 71 case tmrHw_CAPABILITY_CLOCK: 72 return (timerId <= 73 1) ? tmrHw_LOW_RESOLUTION_CLOCK : 74 tmrHw_HIGH_RESOLUTION_CLOCK; 75 case tmrHw_CAPABILITY_RESOLUTION: 76 return 32; 77 default: 78 return 0; 79 } 80 return 0; 81} 82 83/****************************************************************************/ 84/** 85* @brief Resets a timer 86* 87* This function initializes timer 88* 89* @return void 90* 91*/ 92/****************************************************************************/ 93static void ResetTimer(tmrHw_ID_t timerId /* [ IN ] Timer Id */ 94) { 95 /* Reset timer */ 96 pTmrHw[timerId].LoadValue = 0; 97 pTmrHw[timerId].CurrentValue = 0xFFFFFFFF; 98 pTmrHw[timerId].Control = 0; 99 pTmrHw[timerId].BackgroundLoad = 0; 100 /* Always configure as a 32 bit timer */ 101 pTmrHw[timerId].Control |= tmrHw_CONTROL_32BIT; 102 /* Clear interrupt only if raw status interrupt is set */ 103 if (pTmrHw[timerId].RawInterruptStatus) { 104 pTmrHw[timerId].InterruptClear = 0xFFFFFFFF; 105 } 106} 107 108/****************************************************************************/ 109/** 110* @brief Sets counter value for an interval in ms 111* 112* @return On success: Effective counter value set 113* On failure: 0 114* 115*/ 116/****************************************************************************/ 117static tmrHw_INTERVAL_t SetTimerPeriod(tmrHw_ID_t timerId, /* [ IN ] Timer Id */ 118 tmrHw_INTERVAL_t msec /* [ IN ] Interval in milli-second */ 119) { 120 uint32_t scale = 0; 121 uint32_t count = 0; 122 123 if (timerId == 0 || timerId == 1) { 124 if (msec <= tmrHw_LOW_1_MAX_MILLISEC) { 125 pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1; 126 scale = tmrHw_LOW_1_RESOLUTION_COUNT; 127 } else if (msec <= tmrHw_LOW_16_MAX_MILLISEC) { 128 pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_16; 129 scale = tmrHw_LOW_16_RESOLUTION_COUNT; 130 } else if (msec <= tmrHw_LOW_256_MAX_MILLISEC) { 131 pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_256; 132 scale = tmrHw_LOW_256_RESOLUTION_COUNT; 133 } else { 134 return 0; 135 } 136 137 count = msec * scale; 138 /* Set counter value */ 139 pTmrHw[timerId].LoadValue = count; 140 pTmrHw[timerId].BackgroundLoad = count; 141 142 } else if (timerId == 2 || timerId == 3) { 143 if (msec <= tmrHw_HIGH_1_MAX_MILLISEC) { 144 pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1; 145 scale = tmrHw_HIGH_1_RESOLUTION_COUNT; 146 } else if (msec <= tmrHw_HIGH_16_MAX_MILLISEC) { 147 pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_16; 148 scale = tmrHw_HIGH_16_RESOLUTION_COUNT; 149 } else if (msec <= tmrHw_HIGH_256_MAX_MILLISEC) { 150 pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_256; 151 scale = tmrHw_HIGH_256_RESOLUTION_COUNT; 152 } else { 153 return 0; 154 } 155 156 count = msec * scale; 157 /* Set counter value */ 158 pTmrHw[timerId].LoadValue = count; 159 pTmrHw[timerId].BackgroundLoad = count; 160 } 161 return count / scale; 162} 163 164/****************************************************************************/ 165/** 166* @brief Configures a periodic timer in terms of timer interrupt rate 167* 168* This function initializes a periodic timer to generate specific number of 169* timer interrupt per second 170* 171* @return On success: Effective timer frequency 172* On failure: 0 173* 174*/ 175/****************************************************************************/ 176tmrHw_RATE_t tmrHw_setPeriodicTimerRate(tmrHw_ID_t timerId, /* [ IN ] Timer Id */ 177 tmrHw_RATE_t rate /* [ IN ] Number of timer interrupt per second */ 178) { 179 uint32_t resolution = 0; 180 uint32_t count = 0; 181 ResetTimer(timerId); 182 183 /* Set timer mode periodic */ 184 pTmrHw[timerId].Control |= tmrHw_CONTROL_PERIODIC; 185 pTmrHw[timerId].Control &= ~tmrHw_CONTROL_ONESHOT; 186 /* Set timer in highest resolution */ 187 pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1; 188 189 if (rate && (timerId == 0 || timerId == 1)) { 190 if (rate > tmrHw_LOW_RESOLUTION_CLOCK) { 191 return 0; 192 } 193 resolution = tmrHw_LOW_RESOLUTION_CLOCK; 194 } else if (rate && (timerId == 2 || timerId == 3)) { 195 if (rate > tmrHw_HIGH_RESOLUTION_CLOCK) { 196 return 0; 197 } else { 198 resolution = tmrHw_HIGH_RESOLUTION_CLOCK; 199 } 200 } else { 201 return 0; 202 } 203 /* Find the counter value */ 204 count = resolution / rate; 205 /* Set counter value */ 206 pTmrHw[timerId].LoadValue = count; 207 pTmrHw[timerId].BackgroundLoad = count; 208 209 return resolution / count; 210} 211 212/****************************************************************************/ 213/** 214* @brief Configures a periodic timer to generate timer interrupt after 215* certain time interval 216* 217* This function initializes a periodic timer to generate timer interrupt 218* after every time interval in millisecond 219* 220* @return On success: Effective interval set in milli-second 221* On failure: 0 222* 223*/ 224/****************************************************************************/ 225tmrHw_INTERVAL_t tmrHw_setPeriodicTimerInterval(tmrHw_ID_t timerId, /* [ IN ] Timer Id */ 226 tmrHw_INTERVAL_t msec /* [ IN ] Interval in milli-second */ 227) { 228 ResetTimer(timerId); 229 230 /* Set timer mode periodic */ 231 pTmrHw[timerId].Control |= tmrHw_CONTROL_PERIODIC; 232 pTmrHw[timerId].Control &= ~tmrHw_CONTROL_ONESHOT; 233 234 return SetTimerPeriod(timerId, msec); 235} 236 237/****************************************************************************/ 238/** 239* @brief Configures a periodic timer to generate timer interrupt just once 240* after certain time interval 241* 242* This function initializes a periodic timer to generate a single ticks after 243* certain time interval in millisecond 244* 245* @return On success: Effective interval set in milli-second 246* On failure: 0 247* 248*/ 249/****************************************************************************/ 250tmrHw_INTERVAL_t tmrHw_setOneshotTimerInterval(tmrHw_ID_t timerId, /* [ IN ] Timer Id */ 251 tmrHw_INTERVAL_t msec /* [ IN ] Interval in milli-second */ 252) { 253 ResetTimer(timerId); 254 255 /* Set timer mode oneshot */ 256 pTmrHw[timerId].Control |= tmrHw_CONTROL_PERIODIC; 257 pTmrHw[timerId].Control |= tmrHw_CONTROL_ONESHOT; 258 259 return SetTimerPeriod(timerId, msec); 260} 261 262/****************************************************************************/ 263/** 264* @brief Configures a timer to run as a free running timer 265* 266* This function initializes a timer to run as a free running timer 267* 268* @return Timer resolution (count / sec) 269* 270*/ 271/****************************************************************************/ 272tmrHw_RATE_t tmrHw_setFreeRunningTimer(tmrHw_ID_t timerId, /* [ IN ] Timer Id */ 273 uint32_t divider /* [ IN ] Dividing the clock frequency */ 274) { 275 uint32_t scale = 0; 276 277 ResetTimer(timerId); 278 /* Set timer as free running mode */ 279 pTmrHw[timerId].Control &= ~tmrHw_CONTROL_PERIODIC; 280 pTmrHw[timerId].Control &= ~tmrHw_CONTROL_ONESHOT; 281 282 if (divider >= 64) { 283 pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_256; 284 scale = 256; 285 } else if (divider >= 8) { 286 pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_16; 287 scale = 16; 288 } else { 289 pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1; 290 scale = 1; 291 } 292 293 if (timerId == 0 || timerId == 1) { 294 return tmrHw_divide(tmrHw_LOW_RESOLUTION_CLOCK, scale); 295 } else if (timerId == 2 || timerId == 3) { 296 return tmrHw_divide(tmrHw_HIGH_RESOLUTION_CLOCK, scale); 297 } 298 299 return 0; 300} 301 302/****************************************************************************/ 303/** 304* @brief Starts a timer 305* 306* This function starts a preconfigured timer 307* 308* @return -1 - On Failure 309* 0 - On Success 310* 311*/ 312/****************************************************************************/ 313int tmrHw_startTimer(tmrHw_ID_t timerId /* [ IN ] Timer id */ 314) { 315 pTmrHw[timerId].Control |= tmrHw_CONTROL_TIMER_ENABLE; 316 return 0; 317} 318 319/****************************************************************************/ 320/** 321* @brief Stops a timer 322* 323* This function stops a running timer 324* 325* @return -1 - On Failure 326* 0 - On Success 327* 328*/ 329/****************************************************************************/ 330int tmrHw_stopTimer(tmrHw_ID_t timerId /* [ IN ] Timer id */ 331) { 332 pTmrHw[timerId].Control &= ~tmrHw_CONTROL_TIMER_ENABLE; 333 return 0; 334} 335 336/****************************************************************************/ 337/** 338* @brief Gets current timer count 339* 340* This function returns the current timer value 341* 342* @return Current downcounting timer value 343* 344*/ 345/****************************************************************************/ 346uint32_t tmrHw_GetCurrentCount(tmrHw_ID_t timerId /* [ IN ] Timer id */ 347) { 348 /* return 32 bit timer value */ 349 switch (pTmrHw[timerId].Control & tmrHw_CONTROL_MODE_MASK) { 350 case tmrHw_CONTROL_FREE_RUNNING: 351 if (pTmrHw[timerId].CurrentValue) { 352 return tmrHw_MAX_COUNT - pTmrHw[timerId].CurrentValue; 353 } 354 break; 355 case tmrHw_CONTROL_PERIODIC: 356 case tmrHw_CONTROL_ONESHOT: 357 return pTmrHw[timerId].BackgroundLoad - 358 pTmrHw[timerId].CurrentValue; 359 } 360 return 0; 361} 362 363/****************************************************************************/ 364/** 365* @brief Gets timer count rate 366* 367* This function returns the number of counts per second 368* 369* @return Count rate 370* 371*/ 372/****************************************************************************/ 373tmrHw_RATE_t tmrHw_getCountRate(tmrHw_ID_t timerId /* [ IN ] Timer id */ 374) { 375 uint32_t divider = 0; 376 377 switch (pTmrHw[timerId].Control & tmrHw_CONTROL_PRESCALE_MASK) { 378 case tmrHw_CONTROL_PRESCALE_1: 379 divider = 1; 380 break; 381 case tmrHw_CONTROL_PRESCALE_16: 382 divider = 16; 383 break; 384 case tmrHw_CONTROL_PRESCALE_256: 385 divider = 256; 386 break; 387 default: 388 tmrHw_ASSERT(0); 389 } 390 391 if (timerId == 0 || timerId == 1) { 392 return tmrHw_divide(tmrHw_LOW_RESOLUTION_CLOCK, divider); 393 } else { 394 return tmrHw_divide(tmrHw_HIGH_RESOLUTION_CLOCK, divider); 395 } 396 return 0; 397} 398 399/****************************************************************************/ 400/** 401* @brief Enables timer interrupt 402* 403* This function enables the timer interrupt 404* 405* @return N/A 406* 407*/ 408/****************************************************************************/ 409void tmrHw_enableInterrupt(tmrHw_ID_t timerId /* [ IN ] Timer id */ 410) { 411 pTmrHw[timerId].Control |= tmrHw_CONTROL_INTERRUPT_ENABLE; 412} 413 414/****************************************************************************/ 415/** 416* @brief Disables timer interrupt 417* 418* This function disable the timer interrupt 419* 420* @return N/A 421* 422*/ 423/****************************************************************************/ 424void tmrHw_disableInterrupt(tmrHw_ID_t timerId /* [ IN ] Timer id */ 425) { 426 pTmrHw[timerId].Control &= ~tmrHw_CONTROL_INTERRUPT_ENABLE; 427} 428 429/****************************************************************************/ 430/** 431* @brief Clears the interrupt 432* 433* This function clears the timer interrupt 434* 435* @return N/A 436* 437* @note 438* Must be called under the context of ISR 439*/ 440/****************************************************************************/ 441void tmrHw_clearInterrupt(tmrHw_ID_t timerId /* [ IN ] Timer id */ 442) { 443 pTmrHw[timerId].InterruptClear = 0x1; 444} 445 446/****************************************************************************/ 447/** 448* @brief Gets the interrupt status 449* 450* This function returns timer interrupt status 451* 452* @return Interrupt status 453*/ 454/****************************************************************************/ 455tmrHw_INTERRUPT_STATUS_e tmrHw_getInterruptStatus(tmrHw_ID_t timerId /* [ IN ] Timer id */ 456) { 457 if (pTmrHw[timerId].InterruptStatus) { 458 return tmrHw_INTERRUPT_STATUS_SET; 459 } else { 460 return tmrHw_INTERRUPT_STATUS_UNSET; 461 } 462} 463 464/****************************************************************************/ 465/** 466* @brief Indentifies a timer causing interrupt 467* 468* This functions returns a timer causing interrupt 469* 470* @return 0xFFFFFFFF : No timer causing an interrupt 471* ! 0xFFFFFFFF : timer causing an interrupt 472* @note 473* tmrHw_clearIntrrupt() must be called with a valid timer id after calling this function 474*/ 475/****************************************************************************/ 476tmrHw_ID_t tmrHw_getInterruptSource(void /* void */ 477) { 478 int i; 479 480 for (i = 0; i < tmrHw_TIMER_NUM_COUNT; i++) { 481 if (pTmrHw[i].InterruptStatus) { 482 return i; 483 } 484 } 485 486 return 0xFFFFFFFF; 487} 488 489/****************************************************************************/ 490/** 491* @brief Displays specific timer registers 492* 493* 494* @return void 495* 496*/ 497/****************************************************************************/ 498void tmrHw_printDebugInfo(tmrHw_ID_t timerId, /* [ IN ] Timer id */ 499 int (*fpPrint) (const char *, ...) /* [ IN ] Print callback function */ 500) { 501 (*fpPrint) ("Displaying register contents \n\n"); 502 (*fpPrint) ("Timer %d: Load value 0x%X\n", timerId, 503 pTmrHw[timerId].LoadValue); 504 (*fpPrint) ("Timer %d: Background load value 0x%X\n", timerId, 505 pTmrHw[timerId].BackgroundLoad); 506 (*fpPrint) ("Timer %d: Control 0x%X\n", timerId, 507 pTmrHw[timerId].Control); 508 (*fpPrint) ("Timer %d: Interrupt clear 0x%X\n", timerId, 509 pTmrHw[timerId].InterruptClear); 510 (*fpPrint) ("Timer %d: Interrupt raw interrupt 0x%X\n", timerId, 511 pTmrHw[timerId].RawInterruptStatus); 512 (*fpPrint) ("Timer %d: Interrupt status 0x%X\n", timerId, 513 pTmrHw[timerId].InterruptStatus); 514} 515 516/****************************************************************************/ 517/** 518* @brief Use a timer to perform a busy wait delay for a number of usecs. 519* 520* @return N/A 521*/ 522/****************************************************************************/ 523void tmrHw_udelay(tmrHw_ID_t timerId, /* [ IN ] Timer id */ 524 unsigned long usecs /* [ IN ] usec to delay */ 525) { 526 tmrHw_RATE_t usec_tick_rate; 527 tmrHw_COUNT_t start_time; 528 tmrHw_COUNT_t delta_time; 529 530 start_time = tmrHw_GetCurrentCount(timerId); 531 usec_tick_rate = tmrHw_divide(tmrHw_getCountRate(timerId), 1000000); 532 delta_time = usecs * usec_tick_rate; 533 534 /* Busy wait */ 535 while (delta_time > (tmrHw_GetCurrentCount(timerId) - start_time)) 536 ; 537} 538 539/****************************************************************************/ 540/** 541* @brief Local Divide function 542* 543* This function does the divide 544* 545* @return divide value 546* 547*/ 548/****************************************************************************/ 549static int tmrHw_divide(int num, int denom) 550{ 551 int r; 552 int t = 1; 553 554 /* Shift denom and t up to the largest value to optimize algorithm */ 555 /* t contains the units of each divide */ 556 while ((denom & 0x40000000) == 0) { /* fails if denom=0 */ 557 denom = denom << 1; 558 t = t << 1; 559 } 560 561 /* Intialize the result */ 562 r = 0; 563 564 do { 565 /* Determine if there exists a positive remainder */ 566 if ((num - denom) >= 0) { 567 /* Accumlate t to the result and calculate a new remainder */ 568 num = num - denom; 569 r = r + t; 570 } 571 /* Continue to shift denom and shift t down to 0 */ 572 denom = denom >> 1; 573 t = t >> 1; 574 } while (t != 0); 575 return r; 576} 577