timer.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /*++
  2. Copyright (c) 2015 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. timer.c
  5. Abstract:
  6. This module implements platform timer services for the Raspberry Pi 2.
  7. Author:
  8. Chris Stevens 19-Mar-2015
  9. Environment:
  10. Firmware
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <uefifw.h>
  16. #include "rpi2fw.h"
  17. //
  18. // --------------------------------------------------------------------- Macros
  19. //
  20. //
  21. // ---------------------------------------------------------------- Definitions
  22. //
  23. //
  24. // ------------------------------------------------------ Data Type Definitions
  25. //
  26. //
  27. // ----------------------------------------------- Internal Function Prototypes
  28. //
  29. VOID
  30. EfipPlatformServiceTimerInterrupt (
  31. UINT32 InterruptNumber
  32. );
  33. UINT64
  34. EfipPlatformReadTimer (
  35. VOID
  36. );
  37. //
  38. // -------------------------------------------------------------------- Globals
  39. //
  40. BCM2709_TIMER EfiBcm2709ClockTimer;
  41. BCM2709_TIMER EfiBcm2709TimeCounter;
  42. //
  43. // ------------------------------------------------------------------ Functions
  44. //
  45. EFIAPI
  46. EFI_STATUS
  47. EfiPlatformSetWatchdogTimer (
  48. UINTN Timeout,
  49. UINT64 WatchdogCode,
  50. UINTN DataSize,
  51. CHAR16 *WatchdogData
  52. )
  53. /*++
  54. Routine Description:
  55. This routine sets the system's watchdog timer.
  56. Arguments:
  57. Timeout - Supplies the number of seconds to set the timer for.
  58. WatchdogCode - Supplies a numeric code to log on a watchdog timeout event.
  59. DataSize - Supplies the size of the watchdog data.
  60. WatchdogData - Supplies an optional buffer that includes a null-terminated
  61. string, optionally followed by additional binary data.
  62. Return Value:
  63. EFI_SUCCESS on success.
  64. EFI_INVALID_PARAMETER if the supplied watchdog code is invalid.
  65. EFI_UNSUPPORTED if there is no watchdog timer.
  66. EFI_DEVICE_ERROR if an error occurred accessing the device hardware.
  67. --*/
  68. {
  69. return EFI_UNSUPPORTED;
  70. }
  71. EFI_STATUS
  72. EfiPlatformInitializeTimers (
  73. UINT32 *ClockTimerInterruptNumber,
  74. EFI_PLATFORM_SERVICE_TIMER_INTERRUPT *ClockTimerServiceRoutine,
  75. EFI_PLATFORM_READ_TIMER *ReadTimerRoutine,
  76. UINT64 *ReadTimerFrequency,
  77. UINT32 *ReadTimerWidth
  78. )
  79. /*++
  80. Routine Description:
  81. This routine initializes platform timer services. There are actually two
  82. different timer services returned in this routine. The periodic timer tick
  83. provides a periodic interrupt. The read timer provides a free running
  84. counter value. These are likely serviced by different timers. For the
  85. periodic timer tick, this routine should start the periodic interrupts
  86. coming in. The periodic rate of the timer can be anything reasonable, as
  87. the time counter will be used to count actual duration. The rate should be
  88. greater than twice the rollover rate of the time counter to ensure proper
  89. time accounting. Interrupts are disabled at the processor core for the
  90. duration of this routine.
  91. Arguments:
  92. ClockTimerInterruptNumber - Supplies a pointer where the interrupt line
  93. number of the periodic timer tick will be returned.
  94. ClockTimerServiceRoutine - Supplies a pointer where a pointer to a routine
  95. called when the periodic timer tick interrupt occurs will be returned.
  96. ReadTimerRoutine - Supplies a pointer where a pointer to a routine
  97. called to read the current timer value will be returned.
  98. ReadTimerFrequency - Supplies the frequency of the counter.
  99. ReadTimerWidth - Supplies a pointer where the read timer bit width will be
  100. returned.
  101. Return Value:
  102. EFI Status code.
  103. --*/
  104. {
  105. UINT32 Predivider;
  106. EFI_STATUS Status;
  107. //
  108. // Determine the frequency based on the APB clock frequency. The formula
  109. // is "ARM Timer Frequency" = ("APB Clock Frequency") / (Predivider + 1).
  110. // The Raspberry Pi 2's APB clock frequency is fixed and can achieve the
  111. // desired frequency of 1MHz given the defined predivider.
  112. //
  113. *ClockTimerInterruptNumber = BCM2709_CLOCK_TIMER_INTERRUPT;
  114. *ClockTimerServiceRoutine = EfipPlatformServiceTimerInterrupt;
  115. Predivider = RASPBERRY_PI_2_BCM2836_TIMER_PREDIVIDER_VALUE;
  116. //
  117. // The read timer uses the BCM2709's System Timer that runs at 1MHz.
  118. //
  119. *ReadTimerRoutine = EfipPlatformReadTimer;
  120. *ReadTimerFrequency = BCM2709_SYSTEM_TIMER_FREQUENCY;
  121. *ReadTimerWidth = 32;
  122. //
  123. // Use the two timers that run at a known frequency for the clock and
  124. // time counter.
  125. //
  126. EfiBcm2709ClockTimer.ClockTimer = TRUE;
  127. EfiBcm2709ClockTimer.Predivider = Predivider;
  128. EfiBcm2709TimeCounter.ClockTimer = FALSE;
  129. EfiBcm2709TimeCounter.Predivider = 0;
  130. //
  131. // Initialize the clock timer for periodic use.
  132. //
  133. Status = EfipBcm2709TimerInitialize(&EfiBcm2709ClockTimer);
  134. if (EFI_ERROR(Status)) {
  135. return Status;
  136. }
  137. EfipBcm2709TimerArm(&EfiBcm2709ClockTimer, BCM2709_CLOCK_TICK_COUNT);
  138. Status = EfipBcm2709TimerInitialize(&EfiBcm2709TimeCounter);
  139. if (EFI_ERROR(Status)) {
  140. return Status;
  141. }
  142. Status = EfipPlatformSetInterruptLineState(*ClockTimerInterruptNumber,
  143. TRUE,
  144. FALSE);
  145. return Status;
  146. }
  147. VOID
  148. EfiPlatformTerminateTimers (
  149. VOID
  150. )
  151. /*++
  152. Routine Description:
  153. This routine terminates timer services in preparation for the termination
  154. of boot services.
  155. Arguments:
  156. None.
  157. Return Value:
  158. None.
  159. --*/
  160. {
  161. EfipBcm2709TimerDisarm(&EfiBcm2709ClockTimer);
  162. return;
  163. }
  164. //
  165. // --------------------------------------------------------- Internal Functions
  166. //
  167. VOID
  168. EfipPlatformServiceTimerInterrupt (
  169. UINT32 InterruptNumber
  170. )
  171. /*++
  172. Routine Description:
  173. This routine is called to acknowledge a platform timer interrupt. This
  174. routine is responsible for quiescing the interrupt.
  175. Arguments:
  176. InterruptNumber - Supplies the interrupt number that occurred.
  177. Return Value:
  178. None.
  179. --*/
  180. {
  181. EfipBcm2709TimerAcknowledgeInterrupt(&EfiBcm2709ClockTimer);
  182. return;
  183. }
  184. UINT64
  185. EfipPlatformReadTimer (
  186. VOID
  187. )
  188. /*++
  189. Routine Description:
  190. This routine is called to read the current platform time value. The timer
  191. is assumed to be free running at a constant frequency, and should have a
  192. bit width as reported in the initialize function. The UEFI core will
  193. manage software bit extension out to 64 bits, this routine should just
  194. reporte the hardware timer value.
  195. Arguments:
  196. None.
  197. Return Value:
  198. Returns the hardware timer value.
  199. --*/
  200. {
  201. return EfipBcm2709TimerRead(&EfiBcm2709TimeCounter);
  202. }