1
0

omap3tmr.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. /*++
  2. Copyright (c) 2012 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. omap3tmr.c
  5. Abstract:
  6. This module implements support for the GP Timers on the TI OMAP3.
  7. Author:
  8. Evan Green 3-Sep-2012
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. //
  16. // Include kernel.h, but be cautious about which APIs are used. Most of the
  17. // system depends on the hardware modules. Limit use to HL, RTL and AR routines.
  18. //
  19. #include <minoca/kernel/kernel.h>
  20. #include "omap3.h"
  21. //
  22. // --------------------------------------------------------------------- Macros
  23. //
  24. //
  25. // This macro reads from an OMAP3 timer. _Base should be a pointer, and
  26. // _Register should be a GP_TIMER_REGISTER value.
  27. //
  28. #define READ_TIMER_REGISTER(_Base, _Register) \
  29. HlReadRegister32((PULONG)(_Base) + (_Register))
  30. //
  31. // This macro writes to an OMAP3 timer. _Base should be a pointer,
  32. // _Register should be GP_TIMER_REGISTER value, and _Value should be a ULONG.
  33. //
  34. #define WRITE_TIMER_REGISTER(_Base, _Register, _Value) \
  35. HlWriteRegister32((PULONG)(_Base) + (_Register), (_Value))
  36. //
  37. // ---------------------------------------------------------------- Definitions
  38. //
  39. #define GPTIMER_IDLEMODE_NOIDLE 0x00000080
  40. //
  41. // Mode bits.
  42. //
  43. #define GPTIMER_STARTED 0x00000001
  44. #define GPTIMER_OVERFLOW_TRIGGER 0x00000400
  45. #define GPTIMER_OVERFLOW_AND_MATCH_TRIGGER 0x00000800
  46. #define GPTIMER_COMPARE_ENABLED 0x00000040
  47. #define GPTIMER_AUTORELOAD 0x00000002
  48. //
  49. // Interrupt enable bits.
  50. //
  51. #define GPTIMER_MATCH_INTERRUPT 0x00000001
  52. #define GPTIMER_OVERFLOW_INTERRUPT 0x00000002
  53. //
  54. // ----------------------------------------------- Internal Function Prototypes
  55. //
  56. KSTATUS
  57. HlpOmap3TimerInitialize (
  58. PVOID Context
  59. );
  60. ULONGLONG
  61. HlpOmap3TimerRead (
  62. PVOID Context
  63. );
  64. VOID
  65. HlpOmap3TimerWrite (
  66. PVOID Context,
  67. ULONGLONG NewCount
  68. );
  69. KSTATUS
  70. HlpOmap3TimerArm (
  71. PVOID Context,
  72. TIMER_MODE Mode,
  73. ULONGLONG TickCount
  74. );
  75. VOID
  76. HlpOmap3TimerDisarm (
  77. PVOID Context
  78. );
  79. VOID
  80. HlpOmap3TimerAcknowledgeInterrupt (
  81. PVOID Context
  82. );
  83. //
  84. // ------------------------------------------------------ Data Type Definitions
  85. //
  86. //
  87. // Define the GP timer register set, with offsets in ULONGs.
  88. //
  89. typedef enum _GP_TIMER_REGISTER {
  90. GpTimerReserved0,
  91. GpTimerReserved1,
  92. GpTimerReserved2,
  93. GpTimerReserved3,
  94. GpTimerInterfaceConfiguration1, // TIOCP_CFG
  95. GpTimerStatus, // TISTAT
  96. GpTimerInterruptStatus, // TISR
  97. GpTimerInterruptEnable, // TIER
  98. GpTimerWakeup, // TWER
  99. GpTimerMode, // TCLR
  100. GpTimerCurrentCount, // TCRR
  101. GpTimerLoadCount, // TLDR
  102. GpTimerTriggerReload, // TTGR
  103. GpTimerWritePending, // TWPS
  104. GpTimerMatchCount, // TMAR
  105. GpTimerCapture1, // TCAR1
  106. GpTimerInterfaceConfiguration2, // TSICR
  107. GpTimerCapture2, // TCAR2
  108. GpTimerPositive1msIncrement, // TPIR
  109. GpTimerNegative1msIncrement, // TNIR
  110. GpTimerCurrentRounding1ms, // TCVR
  111. GpTimerOverflowValue, // TOCR
  112. GpTimerMaskedOverflowCount, // TOWR
  113. } GP_TIMER_REGISTER, *PGP_TIMER_REGISTER;
  114. /*++
  115. Structure Description:
  116. This structure stores the internal state associated with an OMAP3 GP
  117. timer.
  118. Members:
  119. Base - Stores the virtual address of the timer.
  120. PhysicalAddress - Stores the physical address of the timer.
  121. Index - Stores the zero-based index of this timer within the timer block.
  122. --*/
  123. typedef struct _GP_TIMER_DATA {
  124. PVOID Base;
  125. PHYSICAL_ADDRESS PhysicalAddress;
  126. ULONG Index;
  127. } GP_TIMER_DATA, *PGP_TIMER_DATA;
  128. //
  129. // -------------------------------------------------------------------- Globals
  130. //
  131. //
  132. // Store a pointer to the OMAP ACPI table.
  133. //
  134. POMAP3_TABLE HlOmap3Table = NULL;
  135. //
  136. // ------------------------------------------------------------------ Functions
  137. //
  138. VOID
  139. HlpOmap3TimerModuleEntry (
  140. VOID
  141. )
  142. /*++
  143. Routine Description:
  144. This routine is the entry point for the OMAP3 GP Timer hardware module.
  145. Its role is to detect and report the prescense of OMAP3 Timers.
  146. Arguments:
  147. Services - Supplies a pointer to the services/APIs made available by the
  148. kernel to the hardware module.
  149. Return Value:
  150. None.
  151. --*/
  152. {
  153. KSTATUS Status;
  154. TIMER_DESCRIPTION Timer;
  155. PGP_TIMER_DATA TimerData;
  156. ULONG TimerIndex;
  157. //
  158. // Interrupt controllers are always initialized before timers, so the
  159. // OMAP3 ACPI table should already be set up.
  160. //
  161. if (HlOmap3Table == NULL) {
  162. goto GpTimerModuleEntryEnd;
  163. }
  164. //
  165. // Fire up the timer's power.
  166. //
  167. Status = HlpOmap3InitializePowerAndClocks();
  168. if (!KSUCCESS(Status)) {
  169. goto GpTimerModuleEntryEnd;
  170. }
  171. //
  172. // Register each of the independent timers in the timer block.
  173. //
  174. for (TimerIndex = 0; TimerIndex < OMAP3_TIMER_COUNT; TimerIndex += 1) {
  175. //
  176. // Skip the timer if it has no address.
  177. //
  178. if (HlOmap3Table->TimerPhysicalAddress[TimerIndex] == (UINTN)NULL) {
  179. continue;
  180. }
  181. RtlZeroMemory(&Timer, sizeof(TIMER_DESCRIPTION));
  182. Timer.TableVersion = TIMER_DESCRIPTION_VERSION;
  183. Timer.FunctionTable.Initialize = HlpOmap3TimerInitialize;
  184. Timer.FunctionTable.ReadCounter = HlpOmap3TimerRead;
  185. Timer.FunctionTable.WriteCounter = HlpOmap3TimerWrite;
  186. Timer.FunctionTable.Arm = HlpOmap3TimerArm;
  187. Timer.FunctionTable.Disarm = HlpOmap3TimerDisarm;
  188. Timer.FunctionTable.AcknowledgeInterrupt =
  189. HlpOmap3TimerAcknowledgeInterrupt;
  190. TimerData = HlAllocateMemory(sizeof(GP_TIMER_DATA),
  191. OMAP3_ALLOCATION_TAG,
  192. FALSE,
  193. NULL);
  194. if (TimerData == NULL) {
  195. Status = STATUS_INSUFFICIENT_RESOURCES;
  196. goto GpTimerModuleEntryEnd;
  197. }
  198. RtlZeroMemory(TimerData, sizeof(GP_TIMER_DATA));
  199. TimerData->PhysicalAddress =
  200. HlOmap3Table->TimerPhysicalAddress[TimerIndex];
  201. TimerData->Index = TimerIndex;
  202. Timer.Context = TimerData;
  203. Timer.Features = TIMER_FEATURE_READABLE |
  204. TIMER_FEATURE_WRITABLE |
  205. TIMER_FEATURE_PERIODIC |
  206. TIMER_FEATURE_ONE_SHOT;
  207. Timer.CounterBitWidth = OMAP3_TIMER_BIT_WIDTH;
  208. //
  209. // The first timer runs at the bus clock speed, but the rest run at
  210. // a fixed frequency.
  211. //
  212. if (TimerIndex == 0) {
  213. Timer.CounterFrequency = 0;
  214. } else {
  215. Timer.CounterFrequency = OMAP3_TIMER_FIXED_FREQUENCY;
  216. }
  217. Timer.Interrupt.Line.Type = InterruptLineControllerSpecified;
  218. Timer.Interrupt.Line.U.Local.Controller = 0;
  219. Timer.Interrupt.Line.U.Local.Line = HlOmap3Table->TimerGsi[TimerIndex];
  220. Timer.Interrupt.TriggerMode = InterruptModeUnknown;
  221. Timer.Interrupt.ActiveLevel = InterruptActiveLevelUnknown;
  222. //
  223. // Register the timer with the system.
  224. //
  225. Status = HlRegisterHardware(HardwareModuleTimer, &Timer);
  226. if (!KSUCCESS(Status)) {
  227. goto GpTimerModuleEntryEnd;
  228. }
  229. }
  230. GpTimerModuleEntryEnd:
  231. return;
  232. }
  233. //
  234. // --------------------------------------------------------- Internal Functions
  235. //
  236. KSTATUS
  237. HlpOmap3TimerInitialize (
  238. PVOID Context
  239. )
  240. /*++
  241. Routine Description:
  242. This routine initializes an OMAP3 timer.
  243. Arguments:
  244. Context - Supplies the pointer to the timer's context, provided by the
  245. hardware module upon initialization.
  246. Return Value:
  247. Status code.
  248. --*/
  249. {
  250. KSTATUS Status;
  251. PGP_TIMER_DATA Timer;
  252. ULONG Value;
  253. Timer = (PGP_TIMER_DATA)Context;
  254. //
  255. // Map the hardware if that has not been done.
  256. //
  257. if (Timer->Base == NULL) {
  258. Timer->Base = HlMapPhysicalAddress(Timer->PhysicalAddress,
  259. OMAP3_TIMER_CONTROLLER_SIZE,
  260. TRUE);
  261. if (Timer->Base == NULL) {
  262. Status = STATUS_INSUFFICIENT_RESOURCES;
  263. goto GpTimerInitializeEnd;
  264. }
  265. }
  266. //
  267. // Program the timer in free running mode with no interrupt. Set the
  268. // interface configuration to a state that disables going idle.
  269. //
  270. WRITE_TIMER_REGISTER(Timer->Base,
  271. GpTimerInterfaceConfiguration1,
  272. GPTIMER_IDLEMODE_NOIDLE);
  273. //
  274. // Disable wakeup functionality.
  275. //
  276. WRITE_TIMER_REGISTER(Timer->Base, GpTimerWakeup, 0);
  277. //
  278. // Set the second interface configuration register to non-posted mode,
  279. // which means that writes don't return until they complete. Posted mode
  280. // is faster for writes but requires polling a bit for reads.
  281. //
  282. WRITE_TIMER_REGISTER(Timer->Base, GpTimerInterfaceConfiguration2, 0);
  283. //
  284. // Disable all interrupts for now.
  285. //
  286. WRITE_TIMER_REGISTER(Timer->Base, GpTimerInterruptEnable, 0);
  287. //
  288. // Set the load value to zero to create a free-running timer, and reset the
  289. // current counter now too.
  290. //
  291. WRITE_TIMER_REGISTER(Timer->Base, GpTimerLoadCount, 0x00000000);
  292. WRITE_TIMER_REGISTER(Timer->Base, GpTimerCurrentCount, 0x00000000);
  293. //
  294. // Set the mode register to auto-reload, and start the timer.
  295. //
  296. Value = GPTIMER_OVERFLOW_TRIGGER | GPTIMER_STARTED | GPTIMER_AUTORELOAD;
  297. WRITE_TIMER_REGISTER(Timer->Base, GpTimerMode, Value);
  298. //
  299. // Reset all interrupt-pending bits.
  300. //
  301. WRITE_TIMER_REGISTER(Timer->Base, GpTimerInterruptStatus, 0x7);
  302. Status = STATUS_SUCCESS;
  303. GpTimerInitializeEnd:
  304. return Status;
  305. }
  306. ULONGLONG
  307. HlpOmap3TimerRead (
  308. PVOID Context
  309. )
  310. /*++
  311. Routine Description:
  312. This routine returns the hardware counter's raw value.
  313. Arguments:
  314. Context - Supplies the pointer to the timer's context.
  315. Return Value:
  316. Returns the timer's current count.
  317. --*/
  318. {
  319. PGP_TIMER_DATA Timer;
  320. Timer = (PGP_TIMER_DATA)Context;
  321. return READ_TIMER_REGISTER(Timer->Base, GpTimerCurrentCount);
  322. }
  323. VOID
  324. HlpOmap3TimerWrite (
  325. PVOID Context,
  326. ULONGLONG NewCount
  327. )
  328. /*++
  329. Routine Description:
  330. This routine writes to the timer's hardware counter. This routine will
  331. only be called for timers that have the writable counter feature bit set.
  332. Arguments:
  333. Context - Supplies the pointer to the timer's context, provided by the
  334. hardware module upon initialization.
  335. NewCount - Supplies the value to write into the counter. It is expected that
  336. the counter will not stop after the write.
  337. Return Value:
  338. None.
  339. --*/
  340. {
  341. PGP_TIMER_DATA Timer;
  342. Timer = (PGP_TIMER_DATA)Context;
  343. WRITE_TIMER_REGISTER(Timer->Base, GpTimerCurrentCount, (ULONG)NewCount);
  344. return;
  345. }
  346. KSTATUS
  347. HlpOmap3TimerArm (
  348. PVOID Context,
  349. TIMER_MODE Mode,
  350. ULONGLONG TickCount
  351. )
  352. /*++
  353. Routine Description:
  354. This routine arms the timer to fire an interrupt after the specified number
  355. of ticks.
  356. Arguments:
  357. Context - Supplies the pointer to the timer's context, provided by the
  358. hardware module upon initialization.
  359. Mode - Supplies the mode to arm the timer in. The system will never request
  360. a mode not supported by the timer's feature bits. The mode dictates
  361. how the tick count argument is interpreted.
  362. TickCount - Supplies the number of timer ticks from now for the timer to
  363. fire in. In absolute mode, this supplies the time in timer ticks at
  364. which to fire an interrupt.
  365. Return Value:
  366. STATUS_SUCCESS always.
  367. --*/
  368. {
  369. PGP_TIMER_DATA Timer;
  370. ULONG Value;
  371. Timer = (PGP_TIMER_DATA)Context;
  372. if (TickCount >= MAX_ULONG) {
  373. TickCount = MAX_ULONG - 1;
  374. }
  375. //
  376. // Start the timer ticking.
  377. //
  378. WRITE_TIMER_REGISTER(Timer->Base, GpTimerMode, 0);
  379. WRITE_TIMER_REGISTER(Timer->Base,
  380. GpTimerLoadCount,
  381. 0xFFFFFFFF - (ULONG)TickCount);
  382. WRITE_TIMER_REGISTER(Timer->Base,
  383. GpTimerCurrentCount,
  384. 0xFFFFFFFF - (ULONG)TickCount);
  385. Value = GPTIMER_STARTED;
  386. if (Mode == TimerModePeriodic) {
  387. Value |= GPTIMER_AUTORELOAD;
  388. }
  389. WRITE_TIMER_REGISTER(Timer->Base, GpTimerMode, Value);
  390. WRITE_TIMER_REGISTER(Timer->Base,
  391. GpTimerInterruptEnable,
  392. GPTIMER_OVERFLOW_INTERRUPT);
  393. return STATUS_SUCCESS;
  394. }
  395. VOID
  396. HlpOmap3TimerDisarm (
  397. PVOID Context
  398. )
  399. /*++
  400. Routine Description:
  401. This routine disarms the timer, stopping interrupts from firing.
  402. Arguments:
  403. Context - Supplies the pointer to the timer's context, provided by the
  404. hardware module upon initialization.
  405. Return Value:
  406. None.
  407. --*/
  408. {
  409. PGP_TIMER_DATA Timer;
  410. //
  411. // Disable all interrupts on this timer.
  412. //
  413. Timer = (PGP_TIMER_DATA)Context;
  414. WRITE_TIMER_REGISTER(Timer->Base, GpTimerInterruptEnable, 0);
  415. //
  416. // Reset all interrupt-pending bits.
  417. //
  418. WRITE_TIMER_REGISTER(Timer->Base, GpTimerInterruptStatus, 0x7);
  419. return;
  420. }
  421. VOID
  422. HlpOmap3TimerAcknowledgeInterrupt (
  423. PVOID Context
  424. )
  425. /*++
  426. Routine Description:
  427. This routine performs any actions necessary upon reciept of a timer's
  428. interrupt. This may involve writing to an acknowledge register to re-enable
  429. the timer to fire again, or other hardware specific actions.
  430. Arguments:
  431. Context - Supplies the pointer to the timer's context, provided by the
  432. hardware module upon initialization.
  433. Return Value:
  434. None.
  435. --*/
  436. {
  437. PGP_TIMER_DATA Timer;
  438. Timer = (PGP_TIMER_DATA)Context;
  439. //
  440. // Clear the overflow interrupt by writing a 1 to the status bit.
  441. //
  442. WRITE_TIMER_REGISTER(Timer->Base,
  443. GpTimerInterruptStatus,
  444. GPTIMER_OVERFLOW_INTERRUPT);
  445. return;
  446. }