timer.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. /*++
  2. Copyright (c) 2015 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. timer.c
  9. Abstract:
  10. This module implements support for the BCM2709 timer services.
  11. Author:
  12. Chris Stevens 18-Mar-2015
  13. Environment:
  14. Firmware
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include <uefifw.h>
  20. #include <dev/bcm2709.h>
  21. //
  22. // --------------------------------------------------------------------- Macros
  23. //
  24. //
  25. // This macro reads from a BCM2709 ARM timer.
  26. //
  27. #define READ_ARM_TIMER_REGISTER(_Register) \
  28. EfiReadRegister32(BCM2709_ARM_TIMER_BASE + (_Register))
  29. //
  30. // This macro writes to a BCM2709 ARM timer.
  31. //
  32. #define WRITE_ARM_TIMER_REGISTER(_Register, _Value) \
  33. EfiWriteRegister32(BCM2709_ARM_TIMER_BASE + (_Register), (_Value))
  34. //
  35. // This macro reads from a BCM2709 System timer.
  36. //
  37. #define READ_SYSTEM_TIMER_REGISTER(_Register) \
  38. EfiReadRegister32(BCM2709_SYSTEM_TIMER_BASE + (_Register))
  39. //
  40. // This macro writes to a BCM2709 System timer.
  41. //
  42. #define WRITE_SYSTEM_TIMER_REGISTER(_Register, _Value) \
  43. EfiWriteRegister32(BCM2709_SYSTEM_TIMER_BASE + (_Register), (_Value))
  44. //
  45. // ---------------------------------------------------------------- Definitions
  46. //
  47. //
  48. // ------------------------------------------------------ Data Type Definitions
  49. //
  50. //
  51. // ----------------------------------------------- Internal Function Prototypes
  52. //
  53. //
  54. // -------------------------------------------------------------------- Globals
  55. //
  56. //
  57. // ------------------------------------------------------------------ Functions
  58. //
  59. EFI_STATUS
  60. EfipBcm2709TimerInitialize (
  61. PBCM2709_TIMER Timer
  62. )
  63. /*++
  64. Routine Description:
  65. This routine initializes a BCM2709 timer.
  66. Arguments:
  67. Timer - Supplies the pointer to the timer data.
  68. Return Value:
  69. Status code.
  70. --*/
  71. {
  72. UINT32 ControlValue;
  73. //
  74. // The BCM2709 device library must be initialized first.
  75. //
  76. if (EfiBcm2709Initialized == FALSE) {
  77. return EFI_NOT_READY;
  78. }
  79. //
  80. // Program the default timer with no interrupt generation. There is nothing
  81. // to be done for the System Timer's free-running counter. It is already
  82. // enabled.
  83. //
  84. if (Timer->ClockTimer != FALSE) {
  85. WRITE_ARM_TIMER_REGISTER(Bcm2709ArmTimerPredivider, Timer->Predivider);
  86. ControlValue = READ_ARM_TIMER_REGISTER(Bcm2709ArmTimerControl);
  87. ControlValue &= ~BCM2709_ARM_TIMER_CONTROL_INTERRUPT_ENABLE;
  88. ControlValue |= (BCM2709_ARM_TIMER_CONTROL_ENABLED |
  89. BCM2709_ARM_TIMER_CONTROL_DIVIDE_BY_1 |
  90. BCM2709_ARM_TIMER_CONTROL_32_BIT);
  91. WRITE_ARM_TIMER_REGISTER(Bcm2709ArmTimerControl, ControlValue);
  92. WRITE_ARM_TIMER_REGISTER(Bcm2709ArmTimerInterruptClear, 1);
  93. }
  94. return EFI_SUCCESS;
  95. }
  96. UINT64
  97. EfipBcm2709TimerRead (
  98. PBCM2709_TIMER Timer
  99. )
  100. /*++
  101. Routine Description:
  102. This routine returns the hardware counter's raw value.
  103. Arguments:
  104. Timer - Supplies the pointer to the timer data.
  105. Return Value:
  106. Returns the timer's current count.
  107. --*/
  108. {
  109. UINT32 Value;
  110. if (Timer->ClockTimer != FALSE) {
  111. Value = 0xFFFFFFFF;
  112. Value -= READ_ARM_TIMER_REGISTER(Bcm2709ArmTimerCurrentValue);
  113. } else {
  114. Value = READ_SYSTEM_TIMER_REGISTER(Bcm2709SystemTimerCounterLow);
  115. }
  116. return Value;
  117. }
  118. VOID
  119. EfipBcm2709TimerArm (
  120. PBCM2709_TIMER Timer,
  121. UINT64 TickCount
  122. )
  123. /*++
  124. Routine Description:
  125. This routine arms the timer to fire an interrupt after the specified number
  126. of ticks.
  127. Arguments:
  128. Timer - Supplies the pointer to the timer data.
  129. Periodic - Supplies a boolean indicating if the timer should be armed
  130. periodically or one-shot.
  131. TickCount - Supplies the interval, in ticks, from now for the timer to fire
  132. in.
  133. Return Value:
  134. None.
  135. --*/
  136. {
  137. UINT32 ControlValue;
  138. if (Timer->ClockTimer == FALSE) {
  139. return;
  140. }
  141. //
  142. // Set up the control value to program.
  143. //
  144. ControlValue = READ_ARM_TIMER_REGISTER(Bcm2709ArmTimerControl);
  145. ControlValue |= (BCM2709_ARM_TIMER_CONTROL_ENABLED |
  146. BCM2709_ARM_TIMER_CONTROL_DIVIDE_BY_1 |
  147. BCM2709_ARM_TIMER_CONTROL_32_BIT |
  148. BCM2709_ARM_TIMER_CONTROL_INTERRUPT_ENABLE);
  149. //
  150. // Set the timer to its maximum value, set the configuration, clear the
  151. // interrupt, then set the value.
  152. //
  153. WRITE_ARM_TIMER_REGISTER(Bcm2709ArmTimerLoadValue, 0xFFFFFFFF);
  154. WRITE_ARM_TIMER_REGISTER(Bcm2709ArmTimerControl, ControlValue);
  155. WRITE_ARM_TIMER_REGISTER(Bcm2709ArmTimerInterruptClear, 1);
  156. WRITE_ARM_TIMER_REGISTER(Bcm2709ArmTimerLoadValue, TickCount);
  157. return;
  158. }
  159. VOID
  160. EfipBcm2709TimerDisarm (
  161. PBCM2709_TIMER Timer
  162. )
  163. /*++
  164. Routine Description:
  165. This routine disarms the timer, stopping interrupts from firing.
  166. Arguments:
  167. Timer - Supplies the pointer to the timer data.
  168. Return Value:
  169. None.
  170. --*/
  171. {
  172. UINT32 ControlValue;
  173. if (Timer->ClockTimer == FALSE) {
  174. return;
  175. }
  176. //
  177. // Disable the timer by programming it with no interrupt generation.
  178. //
  179. ControlValue = READ_ARM_TIMER_REGISTER(Bcm2709ArmTimerControl);
  180. ControlValue &= ~BCM2709_ARM_TIMER_CONTROL_INTERRUPT_ENABLE;
  181. ControlValue |= (BCM2709_ARM_TIMER_CONTROL_ENABLED |
  182. BCM2709_ARM_TIMER_CONTROL_DIVIDE_BY_1 |
  183. BCM2709_ARM_TIMER_CONTROL_32_BIT);
  184. WRITE_ARM_TIMER_REGISTER(Bcm2709ArmTimerControl, ControlValue);
  185. WRITE_ARM_TIMER_REGISTER(Bcm2709ArmTimerInterruptClear, 1);
  186. return;
  187. }
  188. VOID
  189. EfipBcm2709TimerAcknowledgeInterrupt (
  190. PBCM2709_TIMER Timer
  191. )
  192. /*++
  193. Routine Description:
  194. This routine performs any actions necessary upon reciept of a timer's
  195. interrupt. This may involve writing to an acknowledge register to re-enable
  196. the timer to fire again, or other hardware specific actions.
  197. Arguments:
  198. Timer - Supplies the pointer to the timer data.
  199. Return Value:
  200. None.
  201. --*/
  202. {
  203. if (Timer->ClockTimer == FALSE) {
  204. return;
  205. }
  206. WRITE_ARM_TIMER_REGISTER(Bcm2709ArmTimerInterruptClear, 1);
  207. return;
  208. }
  209. //
  210. // --------------------------------------------------------- Internal Functions
  211. //