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 
52 static void ResetTimer(tmrHw_ID_t timerId)
53     __attribute__ ((section(".aramtext")));
54 static 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 /****************************************************************************/
tmrHw_getTimerCapability(tmrHw_ID_t timerId,tmrHw_CAPABILITY_e capability)67 uint32_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 /****************************************************************************/
ResetTimer(tmrHw_ID_t timerId)93 static 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 /****************************************************************************/
SetTimerPeriod(tmrHw_ID_t timerId,tmrHw_INTERVAL_t msec)117 static 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 /****************************************************************************/
tmrHw_setPeriodicTimerRate(tmrHw_ID_t timerId,tmrHw_RATE_t rate)176 tmrHw_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 /****************************************************************************/
tmrHw_setPeriodicTimerInterval(tmrHw_ID_t timerId,tmrHw_INTERVAL_t msec)225 tmrHw_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 /****************************************************************************/
tmrHw_setOneshotTimerInterval(tmrHw_ID_t timerId,tmrHw_INTERVAL_t msec)250 tmrHw_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 /****************************************************************************/
tmrHw_setFreeRunningTimer(tmrHw_ID_t timerId,uint32_t divider)272 tmrHw_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 /****************************************************************************/
tmrHw_startTimer(tmrHw_ID_t timerId)313 int 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 /****************************************************************************/
tmrHw_stopTimer(tmrHw_ID_t timerId)330 int 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 /****************************************************************************/
tmrHw_GetCurrentCount(tmrHw_ID_t timerId)346 uint32_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 /****************************************************************************/
tmrHw_getCountRate(tmrHw_ID_t timerId)373 tmrHw_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 /****************************************************************************/
tmrHw_enableInterrupt(tmrHw_ID_t timerId)409 void 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 /****************************************************************************/
tmrHw_disableInterrupt(tmrHw_ID_t timerId)424 void 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 /****************************************************************************/
tmrHw_clearInterrupt(tmrHw_ID_t timerId)441 void 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 /****************************************************************************/
tmrHw_getInterruptStatus(tmrHw_ID_t timerId)455 tmrHw_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 /****************************************************************************/
tmrHw_getInterruptSource(void)476 tmrHw_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 /****************************************************************************/
tmrHw_printDebugInfo(tmrHw_ID_t timerId,int (* fpPrint)(const char *,...))498 void 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 /****************************************************************************/
tmrHw_udelay(tmrHw_ID_t timerId,unsigned long usecs)523 void 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 /****************************************************************************/
tmrHw_divide(int num,int denom)549 static 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 	/* Initialize 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