]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/IA32_flat_GCC_Galileo_Gen_2/Support_Files/HPET.c
Update version number in preparation for maintenance release.
[freertos] / FreeRTOS / Demo / IA32_flat_GCC_Galileo_Gen_2 / Support_Files / HPET.c
1 /*--------------------------------------------------------------------\r
2  Copyright(c) 2015 Intel Corporation. All rights reserved.\r
3 \r
4  Redistribution and use in source and binary forms, with or without\r
5  modification, are permitted provided that the following conditions\r
6  are met:\r
7 \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
13  distribution.\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
17 \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
30 \r
31 /*-----------------------------------------------------------------------\r
32  * Any required includes\r
33  *------------------------------------------------------------------------\r
34  */\r
35 #include "FreeRTOS.h"\r
36 #include "task.h"\r
37 #include "portmacro.h"\r
38 #include "galileo_support.h"\r
39 \r
40 /*-----------------------------------------------------------------------\r
41  * Function prototypes\r
42  *------------------------------------------------------------------------\r
43  */\r
44 #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )\r
45         static void vHPETIRQHandler0(void);\r
46 #endif\r
47 #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )\r
48         void vHPETIRQHandler1(void);\r
49 #endif\r
50 #if( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )\r
51         static void vHPETIRQHandler2(void);\r
52 #endif\r
53 \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
58  */\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
64 #endif\r
65 \r
66 /*-----------------------------------------------------------------------\r
67  * Global variables\r
68  *------------------------------------------------------------------------\r
69  */\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
77 {\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
81 };\r
82 \r
83 /*-----------------------------------------------------------------------\r
84  * Static variables\r
85  *------------------------------------------------------------------------\r
86  */\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
90 #endif\r
91 \r
92 /*-----------------------------------------------------------------------\r
93  * General HPET functions\r
94  *------------------------------------------------------------------------\r
95  */\r
96 #if (hpetHPET_TIMER_IN_USE)\r
97 static void vClearHPETCounters( void )\r
98 {\r
99         hpetHPET_MAIN_CTR_LOW = 0UL;\r
100         hpetHPET_MAIN_CTR_HIGH = 0UL;\r
101 }\r
102 #endif\r
103 /*-----------------------------------------------------------*/\r
104 \r
105 #if (hpetHPET_TIMER_IN_USE)\r
106 void vClearHPETElapsedSeconds( void )\r
107 {\r
108         #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )\r
109         {\r
110                 ulHPETElapsedSeconds[0] = 0UL;\r
111                 ulHPETTotalInterrupts [0] = 0UL;\r
112         }\r
113         #endif\r
114         #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )\r
115         {\r
116                 ulHPETElapsedSeconds[1] = 0UL;\r
117                 ulHPETTotalInterrupts [1] = 0UL;\r
118         }\r
119         #endif\r
120         #if( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )\r
121         {\r
122                 ulHPETElapsedSeconds[2] = 0UL;\r
123                 ulHPETTotalInterrupts [2] = 0UL;\r
124         }\r
125         #endif\r
126 }\r
127 #endif\r
128 /*-----------------------------------------------------------*/\r
129 \r
130 #if (hpetHPET_TIMER_IN_USE)\r
131 static inline void vSetTVS( uint32_t TimerNumber )\r
132 {\r
133         volatile uint32_t hpet_cfg = 0UL;\r
134         const uint32_t uiTVS = (1UL << 6UL);\r
135 \r
136         #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )\r
137         {\r
138                 if (TimerNumber == 0)\r
139                 {\r
140                         hpet_cfg = hpetHPET_TMR0_CONFIG_LOW | uiTVS;\r
141                         hpetHPET_TMR0_CONFIG_LOW = hpet_cfg;\r
142                 }\r
143         }\r
144         #endif\r
145         #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )\r
146         {\r
147                 if (TimerNumber == 1)\r
148                 {\r
149                         hpet_cfg = hpetHPET_TMR1_CONFIG_LOW | uiTVS;\r
150                         hpetHPET_TMR1_CONFIG_LOW = hpet_cfg;\r
151                 }\r
152         }\r
153         #endif\r
154         #if( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )\r
155         {\r
156                 if (TimerNumber == 2)\r
157                 {\r
158                         hpet_cfg = hpetHPET_TMR2_CONFIG_LOW | uiTVS;\r
159                         hpetHPET_TMR2_CONFIG_LOW = hpet_cfg;\r
160                 }\r
161         }\r
162         #endif\r
163 }\r
164 #endif\r
165 /*-----------------------------------------------------------*/\r
166 \r
167 #if (hpetHPET_TIMER_IN_USE)\r
168 static inline void vSetHPETComparator( uint32_t TimerNumber, uint64_t Value )\r
169 {\r
170         #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )\r
171         {\r
172                 if (TimerNumber == 0)\r
173                 {\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
178                 }\r
179         }\r
180         #endif\r
181         #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )\r
182         {\r
183                 if (TimerNumber == 1)\r
184                 {\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
189                 }\r
190         }\r
191         #endif\r
192         #if( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )\r
193         {\r
194                 if (TimerNumber == 2)\r
195                 {\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
200                 }\r
201         }\r
202         #endif\r
203 }\r
204 #endif\r
205 /*-----------------------------------------------------------*/\r
206 \r
207 #if (hpetHPET_TIMER_IN_USE)\r
208 static inline uint64_t ullReadHPETCounters( void )\r
209 {\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
213         return Counters;\r
214 }\r
215 #endif\r
216 /*-----------------------------------------------------------*/\r
217 \r
218 #if (hpetHPET_TIMER_IN_USE)\r
219 static void vStopHPETTimer( uint32_t ClearCounters )\r
220 {\r
221         uint32_t hpet_cfg = 0UL;\r
222 \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
227 \r
228         /* Clear counters */\r
229         if (ClearCounters)\r
230                 vClearHPETCounters();\r
231 }\r
232 #endif\r
233 /*-----------------------------------------------------------*/\r
234 \r
235 #if (hpetHPET_TIMER_IN_USE)\r
236 static void vStartHPETTimer( void )\r
237 {\r
238         uint32_t hpet_cfg = 0UL;\r
239         uint8_t  LegacyMode = TRUE; // See table in doc # 329676 page 867\r
240 \r
241         hpet_general_status = hpetHPET_GENERAL_STATUS;\r
242 \r
243         if (hpet_general_status != 0x0UL)\r
244                 hpetHPET_GENERAL_STATUS = hpet_general_status;\r
245 \r
246         hpet_cfg = hpetHPET_GENERAL_CONFIGURATION;\r
247         hpet_cfg |= hpetHPET_CFG_ENABLE;\r
248 \r
249         if(LegacyMode != FALSE)\r
250                 hpet_cfg |= hpetHPET_CFG_LEGACY;\r
251         else\r
252                 hpet_cfg &= ~hpetHPET_CFG_LEGACY;\r
253 \r
254         hpetHPET_GENERAL_CONFIGURATION = hpet_cfg;\r
255 }\r
256 #endif\r
257 /*-----------------------------------------------------------*/\r
258 \r
259 #if (hpetHPET_TIMER_IN_USE)\r
260 static void vConfigureHPETTimer( uint32_t TimerNumber, uint32_t PeriodicMode  )\r
261 {\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
265 \r
266         #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )\r
267         {\r
268                 if (TimerNumber == 0)\r
269                 {\r
270                         IRQNumber = TIMER0_IRQ;\r
271                         Triggering = TIMER0_TRIGGERING;\r
272                         hpet_cfg = hpetHPET_TMR0_CONFIG_LOW;\r
273                 }\r
274         }\r
275         #endif\r
276         #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )\r
277         {\r
278                 if (TimerNumber == 1)\r
279                 {\r
280                         IRQNumber = TIMER1_IRQ;\r
281                         Triggering = TIMER1_TRIGGERING;\r
282                         hpet_cfg = hpetHPET_TMR1_CONFIG_LOW;\r
283                 }\r
284         }\r
285         #endif\r
286         #if( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )\r
287         {\r
288                 if (TimerNumber == 2)\r
289                 {\r
290                         IRQNumber = TIMER2_IRQ;\r
291                         Triggering = TIMER2_TRIGGERING;\r
292                         hpet_cfg = hpetHPET_TMR2_CONFIG_LOW;\r
293                 }\r
294         }\r
295         #endif\r
296 \r
297         /* Modify configuration */\r
298         if (PeriodicMode != FALSE)\r
299         {\r
300                 hpet_cfg |= hpetHPET_TN_ENABLE | hpetHPET_TN_PERIODIC | hpetHPET_TN_SETVAL |\r
301                 hpetHPET_TN_32BIT | ((IRQNumber & 0x1F) << 9UL);\r
302         }\r
303         else\r
304         {\r
305                 hpet_cfg |= hpetHPET_TN_ENABLE | hpetHPET_TN_SETVAL |\r
306                 hpetHPET_TN_32BIT | ((IRQNumber & 0x1F) << 9UL);\r
307         }\r
308 \r
309         /* Setup triggering bit */\r
310         if (Triggering != hpetHPET_INT_EDGE)\r
311                 hpet_cfg |= (1UL << 1UL);\r
312         else\r
313                 hpet_cfg &= ~(1UL << 1UL);\r
314 \r
315         /* write-out configuration */\r
316         #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )\r
317                 if (TimerNumber == 0)\r
318                 {\r
319                         hpetHPET_TMR0_CONFIG_LOW = hpet_cfg;\r
320                 }\r
321         #endif\r
322         #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )\r
323                 if (TimerNumber == 1)\r
324                 {\r
325                         hpetHPET_TMR1_CONFIG_LOW = hpet_cfg;\r
326                 }\r
327         #endif\r
328         #if( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )\r
329                 if (TimerNumber == 2)\r
330                 {\r
331                         hpetHPET_TMR2_CONFIG_LOW = hpet_cfg;\r
332                 }\r
333         #endif\r
334 }\r
335 #endif\r
336 /*-----------------------------------------------------------*/\r
337 \r
338 #if (hpetHPET_TIMER_IN_USE)\r
339 static void vGetHPETCapabilitiesAndStatus( void )\r
340 {\r
341         /* Get HPET capabilities and ID */\r
342         hpet_general_id = hpetHPET_GENERAL_ID;\r
343 \r
344         /* Invalid vendor ID - Should be Intel (0x8086") */\r
345         if ((hpet_general_id >> 16) != 0x8086UL)\r
346         {\r
347                 configASSERT( 0 );\r
348         }\r
349 \r
350         /* Get number of ns/tick - default is 69.841279 */\r
351         hpet_counter_tick_period = hpetHPET_COUNTER_TICK_PERIOD;\r
352 \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
356 }\r
357 #endif\r
358 /*-----------------------------------------------------------*/\r
359 \r
360 #if (hpetHPET_TIMER_IN_USE)\r
361 static void vCheckHPETIRQCapabilities( uint32_t TimerNumber)\r
362 {\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
367 \r
368         #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )\r
369         {\r
370                 if (TimerNumber == 0)\r
371                 {\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
376                 }\r
377         }\r
378         #endif\r
379         #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )\r
380         {\r
381                 if (TimerNumber == 1)\r
382                 {\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
387                 }\r
388         }\r
389         #endif\r
390         #if( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )\r
391         {\r
392                 if (TimerNumber == 2)\r
393                 {\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
398                 }\r
399         }\r
400         #endif\r
401 \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
405 \r
406         /* Setup triggering bit */\r
407         if (Triggering != hpetHPET_INT_EDGE)\r
408                 hpet_cfg_l |= (1UL << 1UL);\r
409         else\r
410                 hpet_cfg_l &= ~(1UL << 1UL);\r
411 \r
412         /* Write then read back configuration */\r
413         #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )\r
414         {\r
415                 if (TimerNumber == 0)\r
416                 {\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
420                 }\r
421         }\r
422         #endif\r
423         #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )\r
424         {\r
425                 if (TimerNumber == 1)\r
426                 {\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
430                 }\r
431         }\r
432         #endif\r
433         #if( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )\r
434         {\r
435                 if (TimerNumber == 2)\r
436                 {\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
440                 }\r
441         }\r
442         #endif\r
443 }\r
444 #endif\r
445 /*-----------------------------------------------------------*/\r
446 \r
447 #if (hpetHPET_TIMER_IN_USE)\r
448 static uint32_t uiCalibrateHPETTimer(uint32_t TimerNumber, uint32_t Calibrate)\r
449 {\r
450         uint32_t ticks_per_ms = 15422; // 1e-3/64.84127e-9 (denominator is hpet_counter_tick_period)\r
451         if (Calibrate)\r
452         {\r
453                 uint32_t uiRunningTotal = 0UL;\r
454                 uint32_t i = 0UL;\r
455                 for (i = 0; i < 5; i++)\r
456                         uiRunningTotal += uiCalibrateTimer(TimerNumber, hpetHPETIMER);\r
457                 ticks_per_ms = (uiRunningTotal / 5);\r
458         }\r
459         return ticks_per_ms;\r
460 }\r
461 #endif\r
462 /*-----------------------------------------------------------*/\r
463 \r
464 #if (hpetHPET_TIMER_IN_USE)\r
465 static void vSetupIOApic( uint32_t TimerNumber )\r
466 {\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
474 \r
475         /* Select polarity and triggering */\r
476         #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )\r
477         {\r
478                 if (TimerNumber == 0)\r
479                 {\r
480                         IRQNumber = TIMER0_IRQ;\r
481                         ISRVector = hpetHPET_TIMER0_ISR_VECTOR;\r
482                         IRQPolarity = TIMER0_POLARITY;\r
483                         Triggering = TIMER0_TRIGGERING;\r
484                 }\r
485         }\r
486         #endif\r
487         #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )\r
488         {\r
489                 if (TimerNumber == 1)\r
490                 {\r
491                         IRQNumber = TIMER1_IRQ;\r
492                         ISRVector = hpetHPET_TIMER1_ISR_VECTOR;\r
493                         IRQPolarity = TIMER1_POLARITY;\r
494                         Triggering = TIMER1_TRIGGERING;\r
495                 }\r
496         }\r
497         #endif\r
498         #if( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )\r
499         {\r
500                 if (TimerNumber == 2)\r
501                 {\r
502                         IRQNumber = TIMER2_IRQ;\r
503                         ISRVector = hpetHPET_TIMER2_ISR_VECTOR;\r
504                         IRQPolarity = TIMER2_POLARITY;\r
505                         Triggering = TIMER2_TRIGGERING;\r
506                 }\r
507         }\r
508         #endif\r
509 \r
510         /* Data to write to RTE register Lower DW */\r
511         uint32_t ConfigDataLDW = (uint32_t)(ISRVector | ((DeliveryMode & 0x07) << 8UL));\r
512 \r
513         /* Set or clear bits in configuration data */\r
514         if (DestinationMode == 0)\r
515                 ConfigDataLDW &= ~(1UL << 11UL);\r
516         else\r
517                 ConfigDataLDW |= (1UL << 11UL);\r
518 \r
519         if (IRQPolarity == 0)\r
520                 ConfigDataLDW &= ~(1UL << 13UL);\r
521         else\r
522                 ConfigDataLDW |= (1UL << 13UL);\r
523 \r
524         if (Triggering != FALSE)\r
525                 ConfigDataLDW |= (1UL << 15UL);\r
526         else\r
527                 ConfigDataLDW &= ~(1UL << 15UL);\r
528 \r
529         if (InterruptMask == 0)\r
530                 ConfigDataLDW &= ~(1UL << 16UL);\r
531         else\r
532                 ConfigDataLDW |= (1UL << 16UL);\r
533 \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
539 \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
545 }\r
546 #endif\r
547 /*-----------------------------------------------------------*/\r
548 \r
549 #if (hpetHPET_TIMER_IN_USE)\r
550 static void vInitilizeHPETInterrupt( uint32_t TimerNumber )\r
551 {\r
552         /* NOTE: In non-legacy mode interrupts are sent as MSI messages to LAPIC */\r
553 \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
556 \r
557         /* Stop the timers and reset the main counter */\r
558         vStopHPETTimer(true);\r
559 \r
560         /* Initialise hardware */\r
561         vSetupIOApic(TimerNumber);\r
562 \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
568         RegTest.S.See\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
572         {\r
573                 if (TimerNumber == 0)\r
574                 {\r
575                         InterruptFrequency = hpetHPET_TIMER0_INTERRUPT_RATE;\r
576                         xPortRegisterCInterruptHandler( vHPETIRQHandler0, hpetHPET_TIMER0_ISR_VECTOR );\r
577                 }\r
578         }\r
579         #endif\r
580         #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )\r
581         {\r
582                 if (TimerNumber == 1)\r
583                 {\r
584                 extern void vApplicationHPETTimer1Wrapper( void );\r
585 \r
586                         InterruptFrequency = hpetHPET_TIMER1_INTERRUPT_RATE;\r
587                         xPortInstallInterruptHandler( vApplicationHPETTimer1Wrapper, hpetHPET_TIMER1_ISR_VECTOR );\r
588                 }\r
589         }\r
590         #endif\r
591         #if ( hpetUSE_HPET_TIMER_NUMBER_2 == 1)\r
592         {\r
593                 if (TimerNumber == 2)\r
594                 {\r
595                         configASSERT(TimerNumber == 2)\r
596                         InterruptFrequency = hpetHPET_TIMER2_INTERRUPT_RATE;\r
597                         xPortRegisterCInterruptHandler( vHPETIRQHandler2, hpetHPET_TIMER2_ISR_VECTOR );\r
598                 }\r
599         }\r
600         #endif\r
601 \r
602         /* Get calibrated ticks per millisecond before initialization. */\r
603         ticks_per_ms = uiCalibrateHPETTimer(TimerNumber, TRUE);\r
604 \r
605         /* Check IRQ compatibility - will assert here if there is a problem. */\r
606         vCheckHPETIRQCapabilities(TimerNumber);\r
607 \r
608         /* Get HPET capabilities and ID and status */\r
609         vGetHPETCapabilitiesAndStatus();\r
610 \r
611         /* Sanity check for frequency */\r
612         if ( InterruptFrequency < 1 )\r
613                 InterruptFrequency = 20;        // default is 50 ms interrupt rate\r
614 \r
615         /* Save interrupt frequency */\r
616         ulHPETInterruptFrequency[TimerNumber] = InterruptFrequency;\r
617 \r
618         /* Calculate required number of ticks */\r
619         uint32_t ticks = ( ticks_per_ms * 1000UL ) / ulHPETInterruptFrequency[TimerNumber];\r
620 \r
621         /* Save the number of ticks to interrupt */\r
622         ulHPETTicksToInterrupt[TimerNumber] = ticks;\r
623 \r
624         /* Make sure counters are zeroed */\r
625         vClearHPETCounters();\r
626 \r
627         /* Write out comparator value */\r
628         vSetHPETComparator(TimerNumber, ticks);\r
629 \r
630         /* Set target timer non-periodic mode with first interrupt at tick */\r
631         vConfigureHPETTimer(TimerNumber, FALSE);\r
632 \r
633         /* Start the timer */\r
634         vStartHPETTimer();\r
635 }\r
636 #endif\r
637 /*-----------------------------------------------------------*/\r
638 \r
639 #if (hpetHPET_TIMER_IN_USE)\r
640 void vInitializeAllHPETInterrupts( void )\r
641 {\r
642         #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )\r
643                 vInitilizeHPETInterrupt( 0 );\r
644         #endif\r
645         #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )\r
646                 vInitilizeHPETInterrupt( 1 );\r
647         #endif\r
648         #if( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )\r
649                 vInitilizeHPETInterrupt( 2 );\r
650         #endif\r
651 }\r
652 #endif\r
653 /*-----------------------------------------------------------*/\r
654 \r
655 uint32_t uiCalibrateTimer( uint32_t TimerNumber, uint32_t TimerType)\r
656 {\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
665          Bits         Usage\r
666          6 and 7      Select channel :\r
667                          0 0 = Channel 0\r
668                          0 1 = Channel 1\r
669                          1 0 = Channel 2\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
687 \r
688         /* Used to calculate LVT ticks */\r
689         const uint32_t uiLargeNumber = 0x7fffffffUL;\r
690 \r
691         /* Default return value */\r
692         uint32_t ticks = 0;\r
693 \r
694         /* Check timer type */\r
695         switch (TimerType)\r
696         {\r
697                 case hpetLVTIMER:\r
698                 case hpetHPETIMER:\r
699                         break;\r
700                 default:\r
701                         return ticks;\r
702                         break;\r
703         }\r
704 \r
705         /* Set timeout counter to a very large value */\r
706         uint64_t timeout_counter = (uint64_t) (uiLargeNumber * 4);\r
707 \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
712 \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
717 \r
718         /* Start target timer  */\r
719         if (TimerType == hpetLVTIMER)\r
720         {\r
721                 portAPIC_LVT_TIMER = portAPIC_TIMER_INT_VECTOR;\r
722                 portAPIC_TMRDIV = portAPIC_DIV_16;\r
723         }\r
724         else if (TimerType == hpetHPETIMER)\r
725         {\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
733                 #else\r
734                         ( void ) TimerNumber;\r
735                 #endif\r
736         }\r
737 \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
743 \r
744         /* Setup target timer initial counts */\r
745         if (TimerType == hpetLVTIMER)\r
746         {\r
747                 portAPIC_TIMER_INITIAL_COUNT = uiLargeNumber;\r
748         }\r
749         else if (TimerType == hpetHPETIMER)\r
750         {\r
751                 #if (hpetHPET_TIMER_IN_USE)\r
752                         vStartHPETTimer();\r
753                 #endif\r
754         }\r
755 \r
756         /* Wait for PIT counter to expire */\r
757         for (;;)\r
758         {\r
759                 gate_register = inw(GATE_CONTROL);\r
760                 if ((gate_register & 0x20) || (--timeout_counter == 0))\r
761                 {\r
762                         /* Stop target timer and exit loop */\r
763                         if (TimerType == hpetLVTIMER)\r
764                         {\r
765                                 portAPIC_LVT_TIMER = portAPIC_DISABLE;\r
766                                 break;\r
767                         }\r
768                         else if (TimerType == hpetHPETIMER)\r
769                         {\r
770                                 #if (hpetHPET_TIMER_IN_USE)\r
771                                         vStopHPETTimer(FALSE);\r
772                                         break;\r
773                                 #endif\r
774                         }\r
775                 }\r
776         }\r
777 \r
778         /* Check for timeout */\r
779         if (timeout_counter != 0)\r
780         {\r
781                 if (TimerType == hpetLVTIMER)\r
782                 {\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
787                 }\r
788                 else if (TimerType == hpetHPETIMER)\r
789                 {\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
796                                 ticks /= 10;\r
797                         #endif\r
798                 }\r
799         }\r
800 \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
804         return ticks;\r
805 }\r
806 \r
807 /*-----------------------------------------------------------------------\r
808  * Interrupt service functions\r
809  *------------------------------------------------------------------------\r
810  */\r
811 #if (hpetHPET_TIMER_IN_USE)\r
812 static inline void vHPET_ISR( uint32_t TimerNumber )\r
813 {\r
814         /*-----------------------------------------------------------------*/\r
815         /* Notes: In edge triggered mode, no need to clear int status bits.*/\r
816         /*                                                                 */\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
821 \r
822         /* Bump HPE timer interrupt count - available in a global variable */\r
823         ulHPETTotalInterrupts[TimerNumber] += 1UL;\r
824 \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
829 \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
834 \r
835         __asm volatile( "sti" );\r
836 }\r
837 #endif\r
838 /*-----------------------------------------------------------*/\r
839 \r
840 #if( hpetUSE_HPET_TIMER_NUMBER_0 == 1 )\r
841         extern void vApplicationHPETTimer0Handler( void );\r
842         static void vHPETIRQHandler0( void )\r
843         {\r
844                 vHPET_ISR( 0 );\r
845                 vApplicationHPETTimer0Handler();\r
846                 hpetIO_APIC_EOI = hpetHPET_TIMER0_ISR_VECTOR;\r
847         }\r
848 #endif\r
849 /*-----------------------------------------------------------*/\r
850 \r
851 #if( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )\r
852         extern void vApplicationHPETTimer1Handler( void );\r
853         void vHPETIRQHandler1( void )\r
854         {\r
855                 vHPET_ISR( 1 );\r
856                 vApplicationHPETTimer1Handler();\r
857                 hpetIO_APIC_EOI = hpetHPET_TIMER1_ISR_VECTOR;\r
858         }\r
859 #endif\r
860 /*-----------------------------------------------------------*/\r
861 \r
862 #if( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )\r
863         extern void vApplicationHPETTimer2Handler( void );\r
864         static void vHPETIRQHandler2( void )\r
865         {\r
866                 vHPET_ISR( 2 );\r
867                 vApplicationHPETTimer2Handler();\r
868                 hpetIO_APIC_EOI = hpetHPET_TIMER2_ISR_VECTOR;\r
869         }\r
870 #endif\r
871 \r
872 /*-----------------------------------------------------------------------\r
873  * Print HPET information functions\r
874  *------------------------------------------------------------------------\r
875  */\r
876 #if ((hpetHPET_PRINT_INFO == 1 ) && (hpetHPET_TIMER_IN_USE))\r
877 static void prvUpdateHPETInfoTask( void *pvParameters )\r
878 {\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
883 \r
884         /* Remove compiler warning about unused parameter. */\r
885         ( void ) pvParameters;\r
886 \r
887         /* Initialise xNextWakeTime - this only needs to be done once. */\r
888         xNextWakeTime = xTaskGetTickCount();\r
889 \r
890         /* Set task blocking period. */\r
891         xBlockTime = pdMS_TO_TICKS( 500 );\r
892 \r
893         for( ;; )\r
894         {\r
895                 /* Place this task in the blocked state until it is time to run again. */\r
896                 vTaskDelayUntil( &xNextWakeTime, xBlockTime );\r
897 \r
898                 /* Print all information */\r
899                 for (TimerNumber = 0; TimerNumber <= 2; TimerNumber++)\r
900                 {\r
901                         execute = pdFALSE;\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
910                                 {\r
911                                         row = 9 ; col = 1;\r
912                                         pi->comparator_h = hpetHPET_TMR0_COMPARATOR_HIGH;\r
913                                         pi->comparator_l = hpetHPET_TMR0_COMPARATOR_LOW;\r
914                                         execute = pdTRUE;\r
915                                 }\r
916                         #endif\r
917                         #if ( hpetUSE_HPET_TIMER_NUMBER_1 == 1 )\r
918                                 if(TimerNumber == 1)\r
919                                 {\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
923                                         execute = pdTRUE;\r
924                                 }\r
925                         #endif\r
926                         #if ( hpetUSE_HPET_TIMER_NUMBER_2 == 1 )\r
927                                 if(TimerNumber == 2)\r
928                                 {\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
932                                         execute = pdTRUE;\r
933                                 }\r
934                         #endif\r
935 \r
936                         /* Print information on screen */\r
937                         if(execute == pdTRUE)\r
938                         {\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
949                         }\r
950                 }\r
951         }\r
952 }\r
953 #endif\r
954 /*-----------------------------------------------------------*/\r
955 \r
956 void vCreateHPETInfoUpdateTask( void  )\r
957 {\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
962 #endif\r
963 }\r
964 /*-----------------------------------------------------------*/\r
965 \r
966 \r
967 \r