Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/arm/mach-bcmring/csp/tmr/tmrHw.c
10820 views
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
/****************************************************************************/
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
/****************************************************************************/
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
/****************************************************************************/
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
/****************************************************************************/
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
/****************************************************************************/
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
/****************************************************************************/
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
/****************************************************************************/
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
/****************************************************************************/
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
/****************************************************************************/
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
/****************************************************************************/
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
/****************************************************************************/
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
/****************************************************************************/
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
/****************************************************************************/
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
/****************************************************************************/
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
/****************************************************************************/
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
/****************************************************************************/
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
/****************************************************************************/
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
/****************************************************************************/
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
/****************************************************************************/
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
578