1 /*--------------------------------------------------------------------
\r
2 Copyright(c) 2015 Intel Corporation. All rights reserved.
\r
4 Redistribution and use in source and binary forms, with or without
\r
5 modification, are permitted provided that the following conditions
\r
8 * Redistributions of source code must retain the above copyright
\r
9 notice, this list of conditions and the following disclaimer.
\r
10 * Redistributions in binary form must reproduce the above copyright
\r
11 notice, this list of conditions and the following disclaimer in
\r
12 the documentation and/or other materials provided with the
\r
14 * Neither the name of Intel Corporation nor the names of its
\r
15 contributors may be used to endorse or promote products derived
\r
16 from this software without specific prior written permission.
\r
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
\r
19 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
\r
20 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
\r
21 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
\r
22 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
\r
23 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
\r
24 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
\r
25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
\r
26 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
\r
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
\r
28 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
29 --------------------------------------------------------------------*/
\r
31 /*-----------------------------------------------------------------------
\r
32 * Any required includes
\r
33 *------------------------------------------------------------------------
\r
35 #include "FreeRTOS.h"
\r
37 #include "portmacro.h"
\r
38 #include "galileo_support.h"
\r
40 /*-----------------------------------------------------------------------
\r
41 * Function prototypes
\r
42 *------------------------------------------------------------------------
\r
44 #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )
\r
45 static void vHPETIRQHandler0(void);
\r
47 #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )
\r
48 void vHPETIRQHandler1(void);
\r
50 #if( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )
\r
51 static void vHPETIRQHandler2(void);
\r
54 /*-----------------------------------------------------------------------
\r
55 * Always inline HPET ISR related routines (even with no optimization),
\r
56 * This is done for speed reasons to keep the ISR as fast as possible.
\r
57 *------------------------------------------------------------------------
\r
59 #if (hpetHPET_TIMER_IN_USE)
\r
60 static inline void vSetTVS( uint32_t ) __attribute__((always_inline));
\r
61 static inline void vSetHPETComparator( uint32_t, uint64_t ) __attribute__((always_inline));
\r
62 static inline uint64_t ullReadHPETCounters( void ) __attribute__((always_inline));
\r
63 static inline void vHPET_ISR (uint32_t) __attribute__((always_inline));
\r
66 /*-----------------------------------------------------------------------
\r
68 *------------------------------------------------------------------------
\r
70 volatile uint32_t hpet_general_status;
\r
71 volatile uint32_t ulHPETTimerNumber [3] = {0, 1, 2};
\r
72 volatile uint32_t ulHPETTotalInterrupts [3] = {0, 0, 0};
\r
73 volatile uint32_t ulHPETElapsedSeconds [3] = {0, 0, 0};
\r
74 volatile uint32_t ulHPETInterruptFrequency [3] = {0, 0, 0};
\r
75 volatile uint32_t ulHPETTicksToInterrupt [3] = {0, 0, 0};
\r
76 struct hpet_info PrintInfo[3] =
\r
78 {0, 0, 0, 0, 0, 0, 0},
\r
79 {1, 0, 0, 0, 0, 0, 0},
\r
80 {2, 0, 0, 0, 0, 0, 0},
\r
83 /*-----------------------------------------------------------------------
\r
85 *------------------------------------------------------------------------
\r
87 #if (hpetHPET_TIMER_IN_USE)
\r
88 static uint32_t hpet_general_id;
\r
89 static uint32_t hpet_counter_tick_period;
\r
92 /*-----------------------------------------------------------------------
\r
93 * General HPET functions
\r
94 *------------------------------------------------------------------------
\r
96 #if (hpetHPET_TIMER_IN_USE)
\r
97 static void vClearHPETCounters( void )
\r
99 hpetHPET_MAIN_CTR_LOW = 0UL;
\r
100 hpetHPET_MAIN_CTR_HIGH = 0UL;
\r
103 /*-----------------------------------------------------------*/
\r
105 #if (hpetHPET_TIMER_IN_USE)
\r
106 void vClearHPETElapsedSeconds( void )
\r
108 #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )
\r
110 ulHPETElapsedSeconds[0] = 0UL;
\r
111 ulHPETTotalInterrupts [0] = 0UL;
\r
114 #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )
\r
116 ulHPETElapsedSeconds[1] = 0UL;
\r
117 ulHPETTotalInterrupts [1] = 0UL;
\r
120 #if( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )
\r
122 ulHPETElapsedSeconds[2] = 0UL;
\r
123 ulHPETTotalInterrupts [2] = 0UL;
\r
128 /*-----------------------------------------------------------*/
\r
130 #if (hpetHPET_TIMER_IN_USE)
\r
131 static inline void vSetTVS( uint32_t TimerNumber )
\r
133 volatile uint32_t hpet_cfg = 0UL;
\r
134 const uint32_t uiTVS = (1UL << 6UL);
\r
136 #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )
\r
138 if (TimerNumber == 0)
\r
140 hpet_cfg = hpetHPET_TMR0_CONFIG_LOW | uiTVS;
\r
141 hpetHPET_TMR0_CONFIG_LOW = hpet_cfg;
\r
145 #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )
\r
147 if (TimerNumber == 1)
\r
149 hpet_cfg = hpetHPET_TMR1_CONFIG_LOW | uiTVS;
\r
150 hpetHPET_TMR1_CONFIG_LOW = hpet_cfg;
\r
154 #if( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )
\r
156 if (TimerNumber == 2)
\r
158 hpet_cfg = hpetHPET_TMR2_CONFIG_LOW | uiTVS;
\r
159 hpetHPET_TMR2_CONFIG_LOW = hpet_cfg;
\r
165 /*-----------------------------------------------------------*/
\r
167 #if (hpetHPET_TIMER_IN_USE)
\r
168 static inline void vSetHPETComparator( uint32_t TimerNumber, uint64_t Value )
\r
170 #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )
\r
172 if (TimerNumber == 0)
\r
174 vSetTVS(TimerNumber);
\r
175 hpetHPET_TMR0_COMPARATOR_LOW = (uint32_t)(Value & 0xFFFFFFFFULL);
\r
176 vSetTVS(TimerNumber);
\r
177 hpetHPET_TMR0_COMPARATOR_HIGH = (uint32_t)((Value >> 32UL) & 0xFFFFFFFFULL);
\r
181 #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )
\r
183 if (TimerNumber == 1)
\r
185 vSetTVS(TimerNumber);
\r
186 hpetHPET_TMR1_COMPARATOR_LOW = (uint32_t)(Value & 0xFFFFFFFFULL);
\r
187 vSetTVS(TimerNumber);
\r
188 hpetHPET_TMR1_COMPARATOR_HIGH = (uint32_t)((Value >> 32UL) & 0xFFFFFFFFULL);
\r
192 #if( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )
\r
194 if (TimerNumber == 2)
\r
196 vSetTVS(TimerNumber);
\r
197 hpetHPET_TMR2_COMPARATOR_LOW = (uint32_t)(Value & 0xFFFFFFFFULL);
\r
198 vSetTVS(TimerNumber);
\r
199 hpetHPET_TMR2_COMPARATOR_HIGH = (uint32_t)((Value >> 32UL) & 0xFFFFFFFFULL);
\r
205 /*-----------------------------------------------------------*/
\r
207 #if (hpetHPET_TIMER_IN_USE)
\r
208 static inline uint64_t ullReadHPETCounters( void )
\r
210 volatile uint64_t Counters = (uint64_t)
\r
211 (((uint64_t)hpetHPET_MAIN_CTR_HIGH << 32UL) |
\r
212 (uint64_t)hpetHPET_MAIN_CTR_LOW);
\r
216 /*-----------------------------------------------------------*/
\r
218 #if (hpetHPET_TIMER_IN_USE)
\r
219 static void vStopHPETTimer( uint32_t ClearCounters )
\r
221 uint32_t hpet_cfg = 0UL;
\r
223 /* Clear configuration enable bit */
\r
224 hpet_cfg = hpetHPET_GENERAL_CONFIGURATION;
\r
225 hpet_cfg &= ~hpetHPET_CFG_ENABLE;
\r
226 hpetHPET_GENERAL_CONFIGURATION = hpet_cfg;
\r
228 /* Clear counters */
\r
230 vClearHPETCounters();
\r
233 /*-----------------------------------------------------------*/
\r
235 #if (hpetHPET_TIMER_IN_USE)
\r
236 static void vStartHPETTimer( void )
\r
238 uint32_t hpet_cfg = 0UL;
\r
239 uint8_t LegacyMode = TRUE; // See table in doc # 329676 page 867
\r
241 hpet_general_status = hpetHPET_GENERAL_STATUS;
\r
243 if (hpet_general_status != 0x0UL)
\r
244 hpetHPET_GENERAL_STATUS = hpet_general_status;
\r
246 hpet_cfg = hpetHPET_GENERAL_CONFIGURATION;
\r
247 hpet_cfg |= hpetHPET_CFG_ENABLE;
\r
249 if(LegacyMode != FALSE)
\r
250 hpet_cfg |= hpetHPET_CFG_LEGACY;
\r
252 hpet_cfg &= ~hpetHPET_CFG_LEGACY;
\r
254 hpetHPET_GENERAL_CONFIGURATION = hpet_cfg;
\r
257 /*-----------------------------------------------------------*/
\r
259 #if (hpetHPET_TIMER_IN_USE)
\r
260 static void vConfigureHPETTimer( uint32_t TimerNumber, uint32_t PeriodicMode )
\r
262 uint32_t hpet_cfg = 0UL; // Configuration data
\r
263 uint8_t IRQNumber = 0; // Hardware ISR number
\r
264 uint8_t Triggering = 0; // Level or Edge sensitive
\r
266 #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )
\r
268 if (TimerNumber == 0)
\r
270 IRQNumber = TIMER0_IRQ;
\r
271 Triggering = TIMER0_TRIGGERING;
\r
272 hpet_cfg = hpetHPET_TMR0_CONFIG_LOW;
\r
276 #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )
\r
278 if (TimerNumber == 1)
\r
280 IRQNumber = TIMER1_IRQ;
\r
281 Triggering = TIMER1_TRIGGERING;
\r
282 hpet_cfg = hpetHPET_TMR1_CONFIG_LOW;
\r
286 #if( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )
\r
288 if (TimerNumber == 2)
\r
290 IRQNumber = TIMER2_IRQ;
\r
291 Triggering = TIMER2_TRIGGERING;
\r
292 hpet_cfg = hpetHPET_TMR2_CONFIG_LOW;
\r
297 /* Modify configuration */
\r
298 if (PeriodicMode != FALSE)
\r
300 hpet_cfg |= hpetHPET_TN_ENABLE | hpetHPET_TN_PERIODIC | hpetHPET_TN_SETVAL |
\r
301 hpetHPET_TN_32BIT | ((IRQNumber & 0x1F) << 9UL);
\r
305 hpet_cfg |= hpetHPET_TN_ENABLE | hpetHPET_TN_SETVAL |
\r
306 hpetHPET_TN_32BIT | ((IRQNumber & 0x1F) << 9UL);
\r
309 /* Setup triggering bit */
\r
310 if (Triggering != hpetHPET_INT_EDGE)
\r
311 hpet_cfg |= (1UL << 1UL);
\r
313 hpet_cfg &= ~(1UL << 1UL);
\r
315 /* write-out configuration */
\r
316 #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )
\r
317 if (TimerNumber == 0)
\r
319 hpetHPET_TMR0_CONFIG_LOW = hpet_cfg;
\r
322 #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )
\r
323 if (TimerNumber == 1)
\r
325 hpetHPET_TMR1_CONFIG_LOW = hpet_cfg;
\r
328 #if( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )
\r
329 if (TimerNumber == 2)
\r
331 hpetHPET_TMR2_CONFIG_LOW = hpet_cfg;
\r
336 /*-----------------------------------------------------------*/
\r
338 #if (hpetHPET_TIMER_IN_USE)
\r
339 static void vGetHPETCapabilitiesAndStatus( void )
\r
341 /* Get HPET capabilities and ID */
\r
342 hpet_general_id = hpetHPET_GENERAL_ID;
\r
344 /* Invalid vendor ID - Should be Intel (0x8086") */
\r
345 if ((hpet_general_id >> 16) != 0x8086UL)
\r
350 /* Get number of ns/tick - default is 69.841279 */
\r
351 hpet_counter_tick_period = hpetHPET_COUNTER_TICK_PERIOD;
\r
353 /* General status of HPET - bit 0 = T0, bit 1 = T1 and bit 2 = T2.
\r
354 * In level triggered mode 1 means interrupt is active */
\r
355 hpet_general_status = hpetHPET_GENERAL_STATUS;
\r
358 /*-----------------------------------------------------------*/
\r
360 #if (hpetHPET_TIMER_IN_USE)
\r
361 static void vCheckHPETIRQCapabilities( uint32_t TimerNumber)
\r
363 uint32_t hpet_cfg_h = 0UL;
\r
364 uint32_t hpet_cfg_l = 0UL;
\r
365 uint32_t IRQNumber = 0UL;
\r
366 uint32_t Triggering = hpetHPET_INT_EDGE;
\r
368 #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )
\r
370 if (TimerNumber == 0)
\r
372 IRQNumber = TIMER0_IRQ;
\r
373 Triggering = TIMER0_TRIGGERING;
\r
374 hpet_cfg_h = hpetHPET_TMR0_CONFIG_HIGH;
\r
375 hpet_cfg_l = hpetHPET_TMR0_CONFIG_LOW;
\r
379 #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )
\r
381 if (TimerNumber == 1)
\r
383 IRQNumber = TIMER1_IRQ;
\r
384 Triggering = TIMER1_TRIGGERING;
\r
385 hpet_cfg_h = hpetHPET_TMR1_CONFIG_HIGH;
\r
386 hpet_cfg_l = hpetHPET_TMR1_CONFIG_LOW;
\r
390 #if( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )
\r
392 if (TimerNumber == 2)
\r
394 IRQNumber = TIMER2_IRQ;
\r
395 Triggering = TIMER2_TRIGGERING;
\r
396 hpet_cfg_h = hpetHPET_TMR2_CONFIG_HIGH;
\r
397 hpet_cfg_l = hpetHPET_TMR2_CONFIG_LOW;
\r
402 /* Setup configuration register */
\r
403 hpet_cfg_l |= hpetHPET_TN_ENABLE | hpetHPET_TN_PERIODIC |
\r
404 hpetHPET_TN_32BIT | ((IRQNumber & 0x1F) << 9UL);
\r
406 /* Setup triggering bit */
\r
407 if (Triggering != hpetHPET_INT_EDGE)
\r
408 hpet_cfg_l |= (1UL << 1UL);
\r
410 hpet_cfg_l &= ~(1UL << 1UL);
\r
412 /* Write then read back configuration */
\r
413 #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )
\r
415 if (TimerNumber == 0)
\r
417 hpetHPET_TMR0_CONFIG_HIGH = hpet_cfg_h;
\r
418 hpetHPET_TMR0_CONFIG_LOW = hpet_cfg_l;
\r
419 hpet_cfg_l = hpetHPET_TMR0_CONFIG_LOW;
\r
423 #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )
\r
425 if (TimerNumber == 1)
\r
427 hpetHPET_TMR1_CONFIG_HIGH = hpet_cfg_h;
\r
428 hpetHPET_TMR1_CONFIG_LOW = hpet_cfg_l;
\r
429 hpet_cfg_l = hpetHPET_TMR1_CONFIG_LOW;
\r
433 #if( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )
\r
435 if (TimerNumber == 2)
\r
437 hpetHPET_TMR2_CONFIG_HIGH = hpet_cfg_h;
\r
438 hpetHPET_TMR2_CONFIG_LOW = hpet_cfg_l;
\r
439 hpet_cfg_l = hpetHPET_TMR2_CONFIG_LOW;
\r
445 /*-----------------------------------------------------------*/
\r
447 #if (hpetHPET_TIMER_IN_USE)
\r
448 static uint32_t uiCalibrateHPETTimer(uint32_t TimerNumber, uint32_t Calibrate)
\r
450 uint32_t ticks_per_ms = 15422; // 1e-3/64.84127e-9 (denominator is hpet_counter_tick_period)
\r
453 uint32_t uiRunningTotal = 0UL;
\r
455 for (i = 0; i < 5; i++)
\r
456 uiRunningTotal += uiCalibrateTimer(TimerNumber, hpetHPETIMER);
\r
457 ticks_per_ms = (uiRunningTotal / 5);
\r
459 return ticks_per_ms;
\r
462 /*-----------------------------------------------------------*/
\r
464 #if (hpetHPET_TIMER_IN_USE)
\r
465 static void vSetupIOApic( uint32_t TimerNumber )
\r
467 uint8_t DeliveryMode = 1; // 0 means fixed (use ISR Vector)
\r
468 uint8_t DestinationMode = 0; // Used by local APIC for MSI
\r
469 uint8_t IRQPolarity = 1; // 0 means active high, 1 = active low
\r
470 uint8_t InterruptMask = 0; // 0 means allow interrupts
\r
471 uint8_t Triggering = hpetHPET_INT_EDGE; // Level or Edge sensitive
\r
472 uint8_t IRQNumber = 0; // Hardware IRQ number
\r
473 uint8_t ISRVector = 0; // Desired ISR vector
\r
475 /* Select polarity and triggering */
\r
476 #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )
\r
478 if (TimerNumber == 0)
\r
480 IRQNumber = TIMER0_IRQ;
\r
481 ISRVector = hpetHPET_TIMER0_ISR_VECTOR;
\r
482 IRQPolarity = TIMER0_POLARITY;
\r
483 Triggering = TIMER0_TRIGGERING;
\r
487 #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )
\r
489 if (TimerNumber == 1)
\r
491 IRQNumber = TIMER1_IRQ;
\r
492 ISRVector = hpetHPET_TIMER1_ISR_VECTOR;
\r
493 IRQPolarity = TIMER1_POLARITY;
\r
494 Triggering = TIMER1_TRIGGERING;
\r
498 #if( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )
\r
500 if (TimerNumber == 2)
\r
502 IRQNumber = TIMER2_IRQ;
\r
503 ISRVector = hpetHPET_TIMER2_ISR_VECTOR;
\r
504 IRQPolarity = TIMER2_POLARITY;
\r
505 Triggering = TIMER2_TRIGGERING;
\r
510 /* Data to write to RTE register Lower DW */
\r
511 uint32_t ConfigDataLDW = (uint32_t)(ISRVector | ((DeliveryMode & 0x07) << 8UL));
\r
513 /* Set or clear bits in configuration data */
\r
514 if (DestinationMode == 0)
\r
515 ConfigDataLDW &= ~(1UL << 11UL);
\r
517 ConfigDataLDW |= (1UL << 11UL);
\r
519 if (IRQPolarity == 0)
\r
520 ConfigDataLDW &= ~(1UL << 13UL);
\r
522 ConfigDataLDW |= (1UL << 13UL);
\r
524 if (Triggering != FALSE)
\r
525 ConfigDataLDW |= (1UL << 15UL);
\r
527 ConfigDataLDW &= ~(1UL << 15UL);
\r
529 if (InterruptMask == 0)
\r
530 ConfigDataLDW &= ~(1UL << 16UL);
\r
532 ConfigDataLDW |= (1UL << 16UL);
\r
534 /* Data to write to RTE register Upper DW */
\r
535 uint32_t LocalAPIC_DID = ((portAPIC_ID_REGISTER & 0xFF000000UL) >> 24UL); // get local APIC DID
\r
536 uint32_t LocalAPIC_EDID = ((portAPIC_ID_REGISTER & 0x00FF0000UL) >> 16UL); // get local APIC Extended DID
\r
537 uint32_t ConfigDataUDW = (uint32_t)(((LocalAPIC_DID << 24UL) & 0xFF000000UL) |
\r
538 ((LocalAPIC_EDID << 16UL) & 0x00FF0000UL));
\r
540 /* Setup IDX and WDW register to write RTE data */
\r
541 hpetIO_APIC_IDX = hpetIO_APIC_RTE_OFFSET + ((2 * IRQNumber) + 1);
\r
542 hpetIO_APIC_WDW = ConfigDataUDW;
\r
543 hpetIO_APIC_IDX = hpetIO_APIC_RTE_OFFSET + ((2 * IRQNumber) + 0);
\r
544 hpetIO_APIC_WDW = ConfigDataLDW;
\r
547 /*-----------------------------------------------------------*/
\r
549 #if (hpetHPET_TIMER_IN_USE)
\r
550 static void vInitilizeHPETInterrupt( uint32_t TimerNumber )
\r
552 /* NOTE: In non-legacy mode interrupts are sent as MSI messages to LAPIC */
\r
554 uint32_t ticks_per_ms = 0UL; // Get # ticks per ms
\r
555 uint32_t InterruptFrequency = 0UL; // Get times per second to interrupt
\r
557 /* Stop the timers and reset the main counter */
\r
558 vStopHPETTimer(true);
\r
560 /* Initialise hardware */
\r
561 vSetupIOApic(TimerNumber);
\r
563 /* Register ISRs. Purely for demonstration purposes, timer 0 and timer 2
\r
564 use the central interrupt entry code, so are installed using
\r
565 xPortRegisterCInterruptHandler(), while timer 1 uses its own interrupt
\r
566 entry code, so is installed using xPortInstallInterruptHandler(). For
\r
567 convenience the entry code for timer 1 is implemented at the bottom of
\r
569 http://www.freertos.org/RTOS_Intel_Quark_Galileo_GCC.html#interrupts for
\r
570 more information. */
\r
571 #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )
\r
573 if (TimerNumber == 0)
\r
575 InterruptFrequency = hpetHPET_TIMER0_INTERRUPT_RATE;
\r
576 xPortRegisterCInterruptHandler( vHPETIRQHandler0, hpetHPET_TIMER0_ISR_VECTOR );
\r
580 #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )
\r
582 if (TimerNumber == 1)
\r
584 extern void vApplicationHPETTimer1Wrapper( void );
\r
586 InterruptFrequency = hpetHPET_TIMER1_INTERRUPT_RATE;
\r
587 xPortInstallInterruptHandler( vApplicationHPETTimer1Wrapper, hpetHPET_TIMER1_ISR_VECTOR );
\r
591 #if ( hpetUSE_HPET_TIMER_NUMBER_2 == 1)
\r
593 if (TimerNumber == 2)
\r
595 configASSERT(TimerNumber == 2)
\r
596 InterruptFrequency = hpetHPET_TIMER2_INTERRUPT_RATE;
\r
597 xPortRegisterCInterruptHandler( vHPETIRQHandler2, hpetHPET_TIMER2_ISR_VECTOR );
\r
602 /* Get calibrated ticks per millisecond before initialization. */
\r
603 ticks_per_ms = uiCalibrateHPETTimer(TimerNumber, TRUE);
\r
605 /* Check IRQ compatibility - will assert here if there is a problem. */
\r
606 vCheckHPETIRQCapabilities(TimerNumber);
\r
608 /* Get HPET capabilities and ID and status */
\r
609 vGetHPETCapabilitiesAndStatus();
\r
611 /* Sanity check for frequency */
\r
612 if ( InterruptFrequency < 1 )
\r
613 InterruptFrequency = 20; // default is 50 ms interrupt rate
\r
615 /* Save interrupt frequency */
\r
616 ulHPETInterruptFrequency[TimerNumber] = InterruptFrequency;
\r
618 /* Calculate required number of ticks */
\r
619 uint32_t ticks = ( ticks_per_ms * 1000UL ) / ulHPETInterruptFrequency[TimerNumber];
\r
621 /* Save the number of ticks to interrupt */
\r
622 ulHPETTicksToInterrupt[TimerNumber] = ticks;
\r
624 /* Make sure counters are zeroed */
\r
625 vClearHPETCounters();
\r
627 /* Write out comparator value */
\r
628 vSetHPETComparator(TimerNumber, ticks);
\r
630 /* Set target timer non-periodic mode with first interrupt at tick */
\r
631 vConfigureHPETTimer(TimerNumber, FALSE);
\r
633 /* Start the timer */
\r
637 /*-----------------------------------------------------------*/
\r
639 #if (hpetHPET_TIMER_IN_USE)
\r
640 void vInitializeAllHPETInterrupts( void )
\r
642 #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )
\r
643 vInitilizeHPETInterrupt( 0 );
\r
645 #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )
\r
646 vInitilizeHPETInterrupt( 1 );
\r
648 #if( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )
\r
649 vInitilizeHPETInterrupt( 2 );
\r
653 /*-----------------------------------------------------------*/
\r
655 uint32_t uiCalibrateTimer( uint32_t TimerNumber, uint32_t TimerType)
\r
657 /*---------------------------------------------------------------------*/
\r
658 /* NOTE: If TimerType = LVTIMER then TimerNumber is ignored (PIT # 2 */
\r
659 /* is always used) */
\r
660 /*---------------------------------------------------------------------*/
\r
661 /*---------------------------------------------------------------------*/
\r
662 /* PIT (programmable interval timer) mode register Bit definitions */
\r
663 /*----------------------------------------------------------------------
\r
664 Mode register is at address 0x43:
\r
666 6 and 7 Select channel :
\r
670 1 1 = Read-back command (8254 only)
\r
671 4 and 5 Access mode :
\r
672 0 0 = Latch count value command
\r
673 0 1 = Access mode: lobyte only
\r
674 1 0 = Access mode: hibyte only
\r
675 1 1 = Access mode: lobyte/hibyte
\r
676 1 to 3 Operating mode :
\r
677 0 0 0 = Mode 0 (interrupt on terminal count)
\r
678 0 0 1 = Mode 1 (hardware re-triggerable one-shot)
\r
679 0 1 0 = Mode 2 (rate generator)
\r
680 0 1 1 = Mode 3 (square wave generator)
\r
681 1 0 0 = Mode 4 (software triggered strobe)
\r
682 1 0 1 = Mode 5 (hardware triggered strobe)
\r
683 1 1 0 = Mode 2 (rate generator, same as 010b)
\r
684 1 1 1 = Mode 3 (square wave generator, same as 011b)
\r
685 0 BCD/Binary mode: 0 = 16-bit binary, 1 = four-digit BCD
\r
686 ----------------------------------------------------------------------*/
\r
688 /* Used to calculate LVT ticks */
\r
689 const uint32_t uiLargeNumber = 0x7fffffffUL;
\r
691 /* Default return value */
\r
692 uint32_t ticks = 0;
\r
694 /* Check timer type */
\r
705 /* Set timeout counter to a very large value */
\r
706 uint64_t timeout_counter = (uint64_t) (uiLargeNumber * 4);
\r
708 /* Set PIT Ch2 to one-shot mode */
\r
709 uint32_t gate_register = ((inw(GATE_CONTROL) & 0xfd) | 0x01);
\r
710 outw(GATE_CONTROL, gate_register);
\r
711 outw(MODE_REGISTER, ONESHOT_MODE);
\r
713 /* Set counter for 10 ms - 1193180/100 Hz ~ 11932 */
\r
714 uint16_t pit_counter = 11932;
\r
715 outb(CHANNEL2_DATA, (char) (pit_counter & 0xff));
\r
716 outb(CHANNEL2_DATA, (char) ((pit_counter >> 8) & 0xff));
\r
718 /* Start target timer */
\r
719 if (TimerType == hpetLVTIMER)
\r
721 portAPIC_LVT_TIMER = portAPIC_TIMER_INT_VECTOR;
\r
722 portAPIC_TMRDIV = portAPIC_DIV_16;
\r
724 else if (TimerType == hpetHPETIMER)
\r
726 #if (hpetHPET_TIMER_IN_USE)
\r
727 // Initialize HPE timer
\r
728 vStopHPETTimer(TRUE);
\r
729 /* Write out comparator value - we don't want it to interrupt */
\r
730 vSetHPETComparator(TimerNumber, 0xFFFFFFFFUL);
\r
731 // Configure HPE timer for non-periodic mode
\r
732 vConfigureHPETTimer(TimerNumber, FALSE);
\r
734 ( void ) TimerNumber;
\r
738 /* Reset PIT one-shot counter */
\r
739 gate_register = (inw(GATE_CONTROL) & 0xfe);
\r
740 outw(GATE_CONTROL, gate_register);
\r
741 gate_register |= 0x01;
\r
742 outw(GATE_CONTROL, gate_register);
\r
744 /* Setup target timer initial counts */
\r
745 if (TimerType == hpetLVTIMER)
\r
747 portAPIC_TIMER_INITIAL_COUNT = uiLargeNumber;
\r
749 else if (TimerType == hpetHPETIMER)
\r
751 #if (hpetHPET_TIMER_IN_USE)
\r
756 /* Wait for PIT counter to expire */
\r
759 gate_register = inw(GATE_CONTROL);
\r
760 if ((gate_register & 0x20) || (--timeout_counter == 0))
\r
762 /* Stop target timer and exit loop */
\r
763 if (TimerType == hpetLVTIMER)
\r
765 portAPIC_LVT_TIMER = portAPIC_DISABLE;
\r
768 else if (TimerType == hpetHPETIMER)
\r
770 #if (hpetHPET_TIMER_IN_USE)
\r
771 vStopHPETTimer(FALSE);
\r
778 /* Check for timeout */
\r
779 if (timeout_counter != 0)
\r
781 if (TimerType == hpetLVTIMER)
\r
783 /* Counter started at a large number so subtract counts */
\r
784 ticks = (uiLargeNumber - portAPIC_TIMER_CURRENT_COUNT);
\r
785 /* adjust ticks for 1 ms and divider ratio */
\r
786 ticks = ((((ticks << 4UL) * 100) / 1000) >> 4UL);
\r
788 else if (TimerType == hpetHPETIMER)
\r
790 #if (hpetHPET_TIMER_IN_USE)
\r
791 /* Read timer counter - we only need the low counter */
\r
792 ticks = (uint32_t)(ullReadHPETCounters() & 0xFFFFFFFFULL);
\r
793 /* Clear timer counter */
\r
794 vClearHPETCounters();
\r
795 /* Return 1 ms tick counts. Timed for 10 ms so just divide by 10 */
\r
801 /* Return adjusted counts for a 1 ms interrupt rate.
\r
802 * Should be approximately 25000 for LV Timer.
\r
803 * Should be approximately 15000 for HPE Timers */
\r
807 /*-----------------------------------------------------------------------
\r
808 * Interrupt service functions
\r
809 *------------------------------------------------------------------------
\r
811 #if (hpetHPET_TIMER_IN_USE)
\r
812 static inline void vHPET_ISR( uint32_t TimerNumber )
\r
814 /*-----------------------------------------------------------------*/
\r
815 /* Notes: In edge triggered mode, no need to clear int status bits.*/
\r
817 /* In non-periodic mode, comparator is added to current counts, */
\r
818 /* do not clear main counters. */
\r
819 /*-----------------------------------------------------------------*/
\r
820 __asm volatile( "cli" );
\r
822 /* Bump HPE timer interrupt count - available in a global variable */
\r
823 ulHPETTotalInterrupts[TimerNumber] += 1UL;
\r
825 /* Bump HPE timer elapsed seconds count - available in a global variable */
\r
826 if ((ulHPETTotalInterrupts[TimerNumber] %
\r
827 (ulHPETInterruptFrequency[TimerNumber] + 0UL)) == 0UL)
\r
828 ulHPETElapsedSeconds[TimerNumber] += 1UL;
\r
830 /* Reload comparators - a must do in non-periodic mode */
\r
831 uint64_t ullNewValue = (uint64_t)
\r
832 (ullReadHPETCounters() + (uint64_t)ulHPETTicksToInterrupt[TimerNumber]);
\r
833 vSetHPETComparator(TimerNumber, ullNewValue);
\r
835 __asm volatile( "sti" );
\r
838 /*-----------------------------------------------------------*/
\r
840 #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )
\r
841 extern void vApplicationHPETTimer0Handler( void );
\r
842 static void vHPETIRQHandler0( void )
\r
845 vApplicationHPETTimer0Handler();
\r
846 hpetIO_APIC_EOI = hpetHPET_TIMER0_ISR_VECTOR;
\r
849 /*-----------------------------------------------------------*/
\r
851 #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )
\r
852 extern void vApplicationHPETTimer1Handler( void );
\r
853 void vHPETIRQHandler1( void )
\r
856 vApplicationHPETTimer1Handler();
\r
857 hpetIO_APIC_EOI = hpetHPET_TIMER1_ISR_VECTOR;
\r
860 /*-----------------------------------------------------------*/
\r
862 #if( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )
\r
863 extern void vApplicationHPETTimer2Handler( void );
\r
864 static void vHPETIRQHandler2( void )
\r
867 vApplicationHPETTimer2Handler();
\r
868 hpetIO_APIC_EOI = hpetHPET_TIMER2_ISR_VECTOR;
\r
872 /*-----------------------------------------------------------------------
\r
873 * Print HPET information functions
\r
874 *------------------------------------------------------------------------
\r
876 #if ((hpetHPET_PRINT_INFO == 1 ) && (hpetHPET_TIMER_IN_USE))
\r
877 static void prvUpdateHPETInfoTask( void *pvParameters )
\r
879 TickType_t xNextWakeTime, xBlockTime;
\r
880 uint32_t TimerNumber;
\r
881 uint8_t row, col, execute;
\r
882 struct hpet_info *pi;
\r
884 /* Remove compiler warning about unused parameter. */
\r
885 ( void ) pvParameters;
\r
887 /* Initialise xNextWakeTime - this only needs to be done once. */
\r
888 xNextWakeTime = xTaskGetTickCount();
\r
890 /* Set task blocking period. */
\r
891 xBlockTime = pdMS_TO_TICKS( 500 );
\r
895 /* Place this task in the blocked state until it is time to run again. */
\r
896 vTaskDelayUntil( &xNextWakeTime, xBlockTime );
\r
898 /* Print all information */
\r
899 for (TimerNumber = 0; TimerNumber <= 2; TimerNumber++)
\r
902 pi = &PrintInfo[TimerNumber];
\r
903 pi->timer_number = TimerNumber;
\r
904 pi->main_counter_h = hpetHPET_MAIN_CTR_HIGH;
\r
905 pi->main_counter_l = hpetHPET_MAIN_CTR_LOW;
\r
906 pi->total_interrupts = ulHPETTotalInterrupts[TimerNumber];
\r
907 pi->elapsed_seconds = ulHPETElapsedSeconds[TimerNumber];
\r
908 #if (hpetUSE_HPET_TIMER_NUMBER_0 == 1 )
\r
909 if(TimerNumber == 0)
\r
912 pi->comparator_h = hpetHPET_TMR0_COMPARATOR_HIGH;
\r
913 pi->comparator_l = hpetHPET_TMR0_COMPARATOR_LOW;
\r
917 #if ( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )
\r
918 if(TimerNumber == 1)
\r
920 row = 13 ; col = 1;
\r
921 pi->comparator_h = hpetHPET_TMR1_COMPARATOR_HIGH;
\r
922 pi->comparator_l = hpetHPET_TMR1_COMPARATOR_LOW;
\r
926 #if ( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )
\r
927 if(TimerNumber == 2)
\r
929 row = 17 ; col = 1;
\r
930 pi->comparator_h = hpetHPET_TMR2_COMPARATOR_HIGH;
\r
931 pi->comparator_l = hpetHPET_TMR2_COMPARATOR_LOW;
\r
936 /* Print information on screen */
\r
937 if(execute == pdTRUE)
\r
939 g_printf_rcc(row, col, ANSI_COLOR_WHITE,
\r
940 " HPE Timer Number = %d", pi->timer_number);
\r
941 g_printf_rcc(row+1, col, ANSI_COLOR_WHITE,
\r
942 " Timer Counters = 0x%08x:%08x, Comparator = 0x%08x:%08x",
\r
943 pi->main_counter_h, pi->main_counter_l,
\r
944 pi->comparator_h, pi->comparator_l);
\r
945 g_printf_rcc(row+2, col, ANSI_COLOR_WHITE,
\r
946 " Total Interrupts = 0x%08x Elapsed Seconds = %u",
\r
947 pi->total_interrupts, pi->elapsed_seconds);
\r
948 g_printf_rcc(row+3, col, DEFAULT_SCREEN_COLOR , "\r");
\r
954 /*-----------------------------------------------------------*/
\r
956 void vCreateHPETInfoUpdateTask( void )
\r
958 #if ((hpetHPET_PRINT_INFO == 1 ) && (hpetHPET_TIMER_IN_USE))
\r
959 /* Create the task that displays HPE timer information. */
\r
960 xTaskCreate( prvUpdateHPETInfoTask, "HPETInfo", (configMINIMAL_STACK_SIZE << 1),
\r
961 NULL, (tskIDLE_PRIORITY), NULL );
\r
964 /*-----------------------------------------------------------*/
\r