/*++ Copyright (c) 2016 Minoca Corp. All Rights Reserved Module Name: gt.c Abstract: This module implements timer support for the ARM Generic Timer. Author: Chris Stevens 9-Jun-2016 Environment: Firmware --*/ // // ------------------------------------------------------------------- Includes // #include #include "dev/gt.h" // // ---------------------------------------------------------------- Definitions // // // Define the bits for a generic timer control register. // #define GT_CONTROL_INTERRUPT_STATUS_ASSERTED 0x00000004 #define GT_CONTROL_INTERRUPT_MASKED 0x00000002 #define GT_CONTROL_TIMER_ENABLE 0x00000001 // // --------------------------------------------------------------------- Macros // // // ----------------------------------------------- Internal Function Prototypes // VOID EfipGtSetVirtualTimerControl ( UINT32 Control ); UINT64 EfipGtGetVirtualCount ( VOID ); VOID EfipGtSetVirtualTimerCompare ( UINT64 CompareValue ); // // ------------------------------------------------------ Data Type Definitions // // // -------------------------------------------------------------------- Globals // // // ------------------------------------------------------------------ Functions // EFI_STATUS EfipGtInitialize ( PGT_CONTEXT Context ) /*++ Routine Description: This routine initializes an ARM Generic Timer. Arguments: Context - Supplies a pointer to the timer context. Return Value: EFI Status code. --*/ { // // The timer is already running, just make sure interrupts are off. // Context->Period = 0; EfipGtSetVirtualTimerControl(0); return EFI_SUCCESS; } UINT64 EfipGtRead ( PGT_CONTEXT Context ) /*++ Routine Description: This routine returns the hardware counter's raw value. Arguments: Context - Supplies a pointer to the timer context. Return Value: Returns the timer's current count. --*/ { return EfipGtGetVirtualCount(); } EFI_STATUS EfipGtArm ( PGT_CONTEXT Context, BOOLEAN Periodic, UINT64 TickCount ) /*++ Routine Description: This routine arms the timer to fire an interrupt after the specified number of ticks. Arguments: Context - Supplies a pointer to the timer context. Periodic - Supplies a boolean indicating whether or not the timer should interrupt periodically or just once. TickCount - Supplies the number of timer ticks from now for the timer to fire in. Return Value: EFI Status code. --*/ { UINT64 DueTime; BOOLEAN Enabled; // // In order to synchronize with the rearming of the timer during // acknowledge interrupt, perform the arm with interrupts disabled. // Enabled = EfiDisableInterrupts(); // // The tick count is relative in both modes, but the GT can only be // armed with an absolute time. Add the current time. // DueTime = TickCount + EfipGtGetVirtualCount(); if (Periodic != FALSE) { Context->Period = TickCount; Context->DueTime = DueTime; } else { Context->Period = 0; } EfipGtSetVirtualTimerCompare(DueTime); EfipGtSetVirtualTimerControl(GT_CONTROL_TIMER_ENABLE); if (Enabled != FALSE) { EfiEnableInterrupts(); } return EFI_SUCCESS; } VOID EfipGtDisarm ( PGT_CONTEXT Context ) /*++ Routine Description: This routine disarms the timer, stopping interrupts from firing. Arguments: Context - Supplies a pointer to the timer context. Return Value: None. --*/ { BOOLEAN Enabled; // // In order to synchronize with the rearming of the timer during // acknowledge interrupt, perform the disarm with interrupts disabled. // Enabled = EfiDisableInterrupts(); Context->Period = 0; EfipGtSetVirtualTimerControl(0); if (Enabled != FALSE) { EfiEnableInterrupts(); } return; } VOID EfipGtAcknowledgeInterrupt ( PGT_CONTEXT Context ) /*++ Routine Description: This routine performs any actions necessary upon reciept of a timer's interrupt. This may involve writing to an acknowledge register to re-enable the timer to fire again, or other hardware specific actions. Arguments: Context - Supplies a pointer to the timer context. Return Value: None. --*/ { UINT64 DueTime; // // The only way to stop an interrupt from continuing to fire is to either // reprogram the compare register or to disable the interrupt. As the timer // must await further instruction, disable the interrupt. // EfipGtSetVirtualTimerControl(0); if (Context->Period != 0) { DueTime = Context->DueTime + Context->Period; Context->DueTime = DueTime; EfipGtSetVirtualTimerCompare(DueTime); EfipGtSetVirtualTimerControl(GT_CONTROL_TIMER_ENABLE); } return; } // // --------------------------------------------------------- Internal Functions //