123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798 |
- /*++
- Copyright (c) 2014 Minoca Corp. All Rights Reserved
- Module Name:
- timer.c
- Abstract:
- This module implements platform timer services for the TI PandaBoard.
- Author:
- Evan Green 3-Mar-2014
- Environment:
- Firmware
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <uefifw.h>
- #include "pandafw.h"
- //
- // --------------------------------------------------------------------- Macros
- //
- //
- // This macro reads from an OMAP4 timer. _Base should be a pointer, and
- // _Register should be a GP_TIMER_REGISTER value.
- //
- #define READ_TIMER_REGISTER(_Base, _Register) \
- EfiReadRegister32((UINT32 *)(_Base) + (_Register))
- //
- // This macro writes to an OMAP4 timer. _Base should be a pointer,
- // _Register should be GP_TIMER_REGISTER value, and _Value should be a ULONG.
- //
- #define WRITE_TIMER_REGISTER(_Base, _Register, _Value) \
- EfiWriteRegister32((UINT32 *)(_Base) + (_Register), (_Value))
- //
- // These macros read from and write to the watchdog timer.
- //
- #define OMAP4_READ_WATCHDOG(_Register) \
- EfiReadRegister32((VOID *)OMAP4430_WATCHDOG2_BASE + (_Register))
- #define OMAP4_WRITE_WATCHDOG(_Register, _Value) \
- EfiWriteRegister32((VOID *)OMAP4430_WATCHDOG2_BASE + (_Register), (_Value))
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define OMAP4_WATCHDOG_FREQUENCY 32768
- //
- // Define the number of 32kHz clock ticks per interrupt. A value of 512 creates
- // a timer rate of 15.625ms, or about 64 interrupts per second.
- //
- #define PANDA_BOARD_TIMER_TICK_COUNT 512
- //
- // Define the offset between the standard register offsets and the alternates.
- //
- #define OMAP4_TIMER_ALTERATE_REGISTER_OFFSET 5
- //
- // Idle bits.
- //
- #define GPTIMER_IDLEMODE_NOIDLE 0x00000080
- //
- // Mode bits.
- //
- #define GPTIMER_STARTED 0x00000001
- #define GPTIMER_OVERFLOW_TRIGGER 0x00000400
- #define GPTIMER_OVERFLOW_AND_MATCH_TRIGGER 0x00000800
- #define GPTIMER_COMPARE_ENABLED 0x00000040
- #define GPTIMER_AUTORELOAD 0x00000002
- //
- // Interrupt enable bits.
- //
- #define GPTIMER_MATCH_INTERRUPT 0x00000001
- #define GPTIMER_OVERFLOW_INTERRUPT 0x00000002
- //
- // Define the two step sequence needed for disabling or enabling the watchdog
- // timer.
- //
- #define OMAP4_WATCHDOG_DISABLE1 0x0000AAAA
- #define OMAP4_WATCHDOG_DISABLE2 0x00005555
- #define OMAP4_WATCHDOG_ENABLE1 0x0000BBBB
- #define OMAP4_WATCHDOG_ENABLE2 0x00004444
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // Define the GP timer register set, with offsets in UINT32s. This is a bit
- // confusing because on the OMAP4 there are two different (but very similar)
- // register sets depending on the timer. Starting with the Wakeup register
- // they're simply off by a fixed offset. Before then, they're slightly
- // different. The alternate registers (for GPTIMERs 3-9 and 11) are interleaved
- // here with the standard ones. The values here have also already taken into
- // account the fact that an offset is going to be added, so that alternate
- // ones are 5 ULONGs shy of their actual register offsets (the fixed offset
- // once things get back in sync).
- //
- typedef enum _GP_TIMER_REGISTER {
- GpTimerRevision = 0x00, // GPT_TIDR
- GpTimerInterfaceConfiguration1 = 0x04, // GPT1MS_TIOCP_CFG
- GpTimerRawInterruptStatus = 0x04, // GPT_IRQSTATUS_RAW
- GpTimerStatus = 0x05, // GPT_TISTAT
- GpTimerInterruptStatusAlternate = 0x05, // GPT_IRQSTATUS
- GpTimerInterruptStatus = 0x06, // GPT_TISR
- GpTimerInterruptEnableAlternate = 0x06, // GPT_IRQENABLE_SET
- GpTimerInterruptEnable = 0x07, // GPT_TIER
- GpTimerInterruptDisable = 0x07, // GPT_IRQENABLE_CLR
- GpTimerWakeup = 0x08, // GPT_TWER
- GpTimerMode = 0x09, // GPT_TCLR
- GpTimerCurrentCount = 0x0A, // GPT_TCRR
- GpTimerLoadCount = 0x0B, // GPT_TLDR
- GpTimerTriggerReload = 0x0C, // GPT_TTGR
- GpTimerWritePending = 0x0D, // GPT_TWPS
- GpTimerMatchCount = 0x0E, // GPT_TMAR
- GpTimerCapture1 = 0x0F, // GPT_TCAR1
- GpTimerInterfaceConfiguration2 = 0x10, // GPT_TSICR
- GpTimerCapture2 = 0x11, // GPT_TCAR2
- GpTimerPositive1msIncrement = 0x12, // GPT_TPIR
- GpTimerNegative1msIncrement = 0x13, // GPT_TNIR
- GpTimerCurrentRounding1ms = 0x14, // GPT_TCVR
- GpTimerOverflowValue = 0x16, // GPT_TOCR
- GpTimerMaskedOverflowCount = 0x17, // GPT_TOWR
- } GP_TIMER_REGISTER, *PGP_TIMER_REGISTER;
- //
- // Define the watchdog timer registers, offsets in bytes.
- //
- typedef enum _OMAP4_WATCHDOG_REGISTER {
- Omap4WatchdogRevision = 0x00,
- Omap4WatchdogInterfaceConfiguration = 0x10,
- Omap4WatchdogInterfaceStatus = 0x14,
- Omap4WatchdogInterruptStatus = 0x18,
- Omap4WatchdogInterruptEnable = 0x1C,
- Omap4WatchdogWakeEventEnable = 0x20,
- Omap4WatchdogPrescaler = 0x24,
- Omap4WatchdogCurrentCount = 0x28,
- Omap4WatchdogLoadCount = 0x2C,
- Omap4WatchdogWritePostControl = 0x34,
- Omap4WatchdogDelay = 0x44,
- Omap4WatchdogStartStop = 0x48,
- Omap4WatchdogRawInterruptStatus = 0x54,
- Omap4WatchdogInterruptEnableSet = 0x5C,
- Omap4WatchdogInterruptEnableClear = 0x60,
- Omap4WatchdogWakeEnable = 0x64
- } OMAP4_WATCHDOG_REGISTER, *POMAP4_WATCHDOG_REGISTER;
- /*++
- Structure Description:
- This structure stores the internal state associated with an OMAP4 GP
- timer.
- Members:
- Base - Stores the virtual address of the timer.
- Index - Stores the zero-based index of this timer within the timer block.
- Offset - Stores the offset, in ULONGs, that should be applied to every
- register access because the timer is using the alternate register
- definitions.
- --*/
- typedef struct _GP_TIMER_DATA {
- UINT32 *Base;
- UINT32 Index;
- UINT32 Offset;
- } GP_TIMER_DATA, *PGP_TIMER_DATA;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- VOID
- EfipPlatformServiceTimerInterrupt (
- UINT32 InterruptNumber
- );
- UINT64
- EfipPlatformReadTimer (
- VOID
- );
- VOID
- EfipOmap4TimerInitialize (
- PGP_TIMER_DATA Context
- );
- UINT64
- EfipOmap4TimerRead (
- PGP_TIMER_DATA Context
- );
- VOID
- EfipOmap4TimerArm (
- PGP_TIMER_DATA Context,
- BOOLEAN Periodic,
- UINT64 TickCount
- );
- VOID
- EfipOmap4TimerDisarm (
- PGP_TIMER_DATA Context
- );
- VOID
- EfipOmap4TimerAcknowledgeInterrupt (
- PGP_TIMER_DATA Context
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- GP_TIMER_DATA EfiPandaClockTimer;
- GP_TIMER_DATA EfiPandaTimeCounter;
- //
- // ------------------------------------------------------------------ Functions
- //
- EFIAPI
- EFI_STATUS
- EfiPlatformSetWatchdogTimer (
- UINTN Timeout,
- UINT64 WatchdogCode,
- UINTN DataSize,
- CHAR16 *WatchdogData
- )
- /*++
- Routine Description:
- This routine sets the system's watchdog timer.
- Arguments:
- Timeout - Supplies the number of seconds to set the timer for.
- WatchdogCode - Supplies a numeric code to log on a watchdog timeout event.
- DataSize - Supplies the size of the watchdog data.
- WatchdogData - Supplies an optional buffer that includes a null-terminated
- string, optionally followed by additional binary data.
- Return Value:
- EFI_SUCCESS on success.
- EFI_INVALID_PARAMETER if the supplied watchdog code is invalid.
- EFI_UNSUPPORTED if there is no watchdog timer.
- EFI_DEVICE_ERROR if an error occurred accessing the device hardware.
- --*/
- {
- UINT32 Count;
- Count = 0 - (Timeout * OMAP4_WATCHDOG_FREQUENCY);
- //
- // First, disable the watchdog timer.
- //
- OMAP4_WRITE_WATCHDOG(Omap4WatchdogStartStop, OMAP4_WATCHDOG_DISABLE1);
- EfiStall(1000);
- OMAP4_WRITE_WATCHDOG(Omap4WatchdogStartStop, OMAP4_WATCHDOG_DISABLE2);
- EfiStall(1000);
- //
- // If the watchdog timer is being enabled, set the count value and fire it
- // back up.
- //
- if ((Count != 0) && (EfiDisableWatchdog == FALSE)) {
- OMAP4_WRITE_WATCHDOG(Omap4WatchdogLoadCount, Count);
- EfiStall(1000);
- OMAP4_WRITE_WATCHDOG(Omap4WatchdogCurrentCount, Count);
- EfiStall(1000);
- OMAP4_WRITE_WATCHDOG(Omap4WatchdogStartStop, OMAP4_WATCHDOG_ENABLE1);
- EfiStall(1000);
- OMAP4_WRITE_WATCHDOG(Omap4WatchdogStartStop, OMAP4_WATCHDOG_ENABLE2);
- }
- return EFI_SUCCESS;
- }
- EFI_STATUS
- EfiPlatformInitializeTimers (
- UINT32 *ClockTimerInterruptNumber,
- EFI_PLATFORM_SERVICE_TIMER_INTERRUPT *ClockTimerServiceRoutine,
- EFI_PLATFORM_READ_TIMER *ReadTimerRoutine,
- UINT64 *ReadTimerFrequency,
- UINT32 *ReadTimerWidth
- )
- /*++
- Routine Description:
- This routine initializes platform timer services. There are actually two
- different timer services returned in this routine. The periodic timer tick
- provides a periodic interrupt. The read timer provides a free running
- counter value. These are likely serviced by different timers. For the
- periodic timer tick, this routine should start the periodic interrupts
- coming in. The periodic rate of the timer can be anything reasonable, as
- the time counter will be used to count actual duration. The rate should be
- greater than twice the rollover rate of the time counter to ensure proper
- time accounting. Interrupts are disabled at the processor core for the
- duration of this routine.
- Arguments:
- ClockTimerInterruptNumber - Supplies a pointer where the interrupt line
- number of the periodic timer tick will be returned.
- ClockTimerServiceRoutine - Supplies a pointer where a pointer to a routine
- called when the periodic timer tick interrupt occurs will be returned.
- ReadTimerRoutine - Supplies a pointer where a pointer to a routine
- called to read the current timer value will be returned.
- ReadTimerFrequency - Supplies the frequency of the counter.
- ReadTimerWidth - Supplies a pointer where the read timer bit width will be
- returned.
- Return Value:
- EFI Status code.
- --*/
- {
- EFI_STATUS Status;
- *ClockTimerInterruptNumber = OMAP4430_IRQ_GPTIMER2;
- *ClockTimerServiceRoutine = EfipPlatformServiceTimerInterrupt;
- *ReadTimerRoutine = EfipPlatformReadTimer;
- *ReadTimerFrequency = OMAP4430_32KHZ_FREQUENCY;
- *ReadTimerWidth = 32;
- //
- // Use GP timer 2 for the clock timer and GP timer 3 for the time counter.
- // Both run at 32kHz.
- //
- EfiPandaClockTimer.Base = (VOID *)OMAP4430_GPTIMER2_BASE;
- EfiPandaClockTimer.Index = 1;
- EfiPandaClockTimer.Offset = 0;
- EfiPandaTimeCounter.Base = (VOID *)OMAP4430_GPTIMER3_BASE;
- EfiPandaTimeCounter.Index = 2;
- EfiPandaTimeCounter.Offset = OMAP4_TIMER_ALTERATE_REGISTER_OFFSET;
- EfipOmap4TimerInitialize(&EfiPandaClockTimer);
- EfipOmap4TimerArm(&EfiPandaClockTimer, TRUE, PANDA_BOARD_TIMER_TICK_COUNT);
- EfipOmap4TimerInitialize(&EfiPandaTimeCounter);
- Status = EfipPlatformSetInterruptLineState(*ClockTimerInterruptNumber,
- TRUE,
- FALSE);
- return Status;
- }
- VOID
- EfiPlatformTerminateTimers (
- VOID
- )
- /*++
- Routine Description:
- This routine terminates timer services in preparation for the termination
- of boot services.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- EfipOmap4TimerDisarm(&EfiPandaClockTimer);
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- VOID
- EfipPlatformServiceTimerInterrupt (
- UINT32 InterruptNumber
- )
- /*++
- Routine Description:
- This routine is called to acknowledge a platform timer interrupt. This
- routine is responsible for quiescing the interrupt.
- Arguments:
- InterruptNumber - Supplies the interrupt number that occurred.
- Return Value:
- None.
- --*/
- {
- EfipOmap4TimerAcknowledgeInterrupt(&EfiPandaClockTimer);
- return;
- }
- UINT64
- EfipPlatformReadTimer (
- VOID
- )
- /*++
- Routine Description:
- This routine is called to read the current platform time value. The timer
- is assumed to be free running at a constant frequency, and should have a
- bit width as reported in the initialize function. The UEFI core will
- manage software bit extension out to 64 bits, this routine should just
- reporte the hardware timer value.
- Arguments:
- None.
- Return Value:
- Returns the hardware timer value.
- --*/
- {
- return EfipOmap4TimerRead(&EfiPandaTimeCounter);
- }
- VOID
- EfipOmap4TimerInitialize (
- PGP_TIMER_DATA Context
- )
- /*++
- Routine Description:
- This routine initializes an OMAP4 timer.
- Arguments:
- Context - Supplies the pointer to the timer's context.
- Return Value:
- None.
- --*/
- {
- UINT32 Value;
- if (Context->Base == NULL) {
- return;
- }
- //
- // Program the timer in free running mode with no interrupt. Set the
- // interface configuration to a state that disables going idle. This is
- // the only register that does not change at all between the standard
- // and alternate interface.
- //
- WRITE_TIMER_REGISTER(Context->Base,
- GpTimerInterfaceConfiguration1,
- GPTIMER_IDLEMODE_NOIDLE);
- //
- // Disable wakeup functionality.
- //
- WRITE_TIMER_REGISTER(Context->Base + Context->Offset, GpTimerWakeup, 0);
- //
- // Set the second interface configuration register to non-posted mode,
- // which means that writes don't return until they complete. Posted mode
- // is faster for writes but requires polling a bit for reads.
- //
- WRITE_TIMER_REGISTER(Context->Base + Context->Offset,
- GpTimerInterfaceConfiguration2,
- 0);
- //
- // Disable all interrupts for now. The alternate register interface uses a
- // set/clear style for the interrupt mask bits.
- //
- if (Context->Offset == 0) {
- WRITE_TIMER_REGISTER(Context->Base, GpTimerInterruptEnable, 0);
- } else {
- WRITE_TIMER_REGISTER(Context->Base + Context->Offset,
- GpTimerInterruptDisable,
- 0x7);
- }
- //
- // Set the load value to zero to create a free-running timer, and reset the
- // current counter now too.
- //
- WRITE_TIMER_REGISTER(Context->Base + Context->Offset,
- GpTimerLoadCount,
- 0x00000000);
- WRITE_TIMER_REGISTER(Context->Base + Context->Offset,
- GpTimerCurrentCount,
- 0x00000000);
- //
- // Set the mode register to auto-reload, and start the timer.
- //
- Value = GPTIMER_OVERFLOW_TRIGGER | GPTIMER_STARTED | GPTIMER_AUTORELOAD;
- WRITE_TIMER_REGISTER(Context->Base + Context->Offset, GpTimerMode, Value);
- //
- // Reset all interrupt-pending bits. This register has a unique offset
- // in the alternate interface.
- //
- if (Context->Offset == 0) {
- WRITE_TIMER_REGISTER(Context->Base, GpTimerInterruptStatus, 0x7);
- } else {
- WRITE_TIMER_REGISTER(Context->Base + Context->Offset,
- GpTimerInterruptStatusAlternate,
- 0x7);
- }
- return;
- }
- UINT64
- EfipOmap4TimerRead (
- PGP_TIMER_DATA Context
- )
- /*++
- Routine Description:
- This routine returns the hardware counter's raw value.
- Arguments:
- Context - Supplies the pointer to the timer's context.
- Return Value:
- Returns the timer's current count.
- --*/
- {
- UINT32 Value;
- Value = READ_TIMER_REGISTER(Context->Base + Context->Offset,
- GpTimerCurrentCount);
- return Value;
- }
- VOID
- EfipOmap4TimerArm (
- PGP_TIMER_DATA 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 the pointer to the timer's context.
- Periodic - Supplies a boolean indicating if the timer should be armed
- periodically or one-shot.
- TickCount - Supplies the interval, in ticks, from now for the timer to fire
- in.
- Return Value:
- None.
- --*/
- {
- UINT32 Value;
- if (TickCount >= 0xFFFFFFFF) {
- TickCount = 0xFFFFFFFF;
- }
- //
- // Start the timer ticking.
- //
- WRITE_TIMER_REGISTER(Context->Base + Context->Offset, GpTimerMode, 0);
- WRITE_TIMER_REGISTER(Context->Base + Context->Offset,
- GpTimerLoadCount,
- 0xFFFFFFFF - (UINT32)TickCount);
- WRITE_TIMER_REGISTER(Context->Base + Context->Offset,
- GpTimerCurrentCount,
- 0xFFFFFFFF - (UINT32)TickCount);
- Value = GPTIMER_STARTED;
- if (Periodic != FALSE) {
- Value |= GPTIMER_AUTORELOAD;
- }
- WRITE_TIMER_REGISTER(Context->Base + Context->Offset, GpTimerMode, Value);
- if (Context->Offset == 0) {
- WRITE_TIMER_REGISTER(Context->Base,
- GpTimerInterruptEnable,
- GPTIMER_OVERFLOW_INTERRUPT);
- } else {
- WRITE_TIMER_REGISTER(Context->Base + Context->Offset,
- GpTimerInterruptEnableAlternate,
- GPTIMER_OVERFLOW_INTERRUPT);
- }
- return;
- }
- VOID
- EfipOmap4TimerDisarm (
- PGP_TIMER_DATA Context
- )
- /*++
- Routine Description:
- This routine disarms the timer, stopping interrupts from firing.
- Arguments:
- Context - Supplies the pointer to the timer's context.
- Return Value:
- None.
- --*/
- {
- //
- // Disable all interrupts. The alternate register interface uses a
- // set/clear style for the interrupt mask bits.
- //
- if (Context->Offset == 0) {
- WRITE_TIMER_REGISTER(Context->Base, GpTimerInterruptEnable, 0);
- } else {
- WRITE_TIMER_REGISTER(Context->Base + Context->Offset,
- GpTimerInterruptDisable,
- 0x7);
- }
- //
- // Reset all interrupt-pending bits. This register has a unique offset
- // in the alternate interface.
- //
- if (Context->Offset == 0) {
- WRITE_TIMER_REGISTER(Context->Base, GpTimerInterruptStatus, 0x7);
- } else {
- WRITE_TIMER_REGISTER(Context->Base + Context->Offset,
- GpTimerInterruptStatusAlternate,
- 0x7);
- }
- return;
- }
- VOID
- EfipOmap4TimerAcknowledgeInterrupt (
- PGP_TIMER_DATA 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 the pointer to the timer's context.
- Return Value:
- None.
- --*/
- {
- //
- // Clear the overflow interrupt by writing a 1 to the status bit.
- //
- if (Context->Offset == 0) {
- WRITE_TIMER_REGISTER(Context->Base,
- GpTimerInterruptStatus,
- GPTIMER_OVERFLOW_INTERRUPT);
- } else {
- WRITE_TIMER_REGISTER(Context->Base + Context->Offset,
- GpTimerInterruptStatusAlternate,
- GPTIMER_OVERFLOW_INTERRUPT);
- }
- return;
- }
|