123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603 |
- /*++
- Copyright (c) 2015 Minoca Corp. All Rights Reserved
- Module Name:
- am335tmr.c
- Abstract:
- This module implements support for the TI AM335x SoC DM timers.
- Author:
- Evan Green 6-Jan-2015
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- //
- // Include kernel.h, but be cautious about which APIs are used. Most of the
- // system depends on the hardware modules. Limit use to HL, RTL and AR routines.
- //
- #include <minoca/kernel/kernel.h>
- #include <minoca/soc/am335x.h>
- #include "am335.h"
- //
- // --------------------------------------------------------------------- Macros
- //
- //
- // This macro reads from an AM335 timer. _Base should be a pointer, and
- // _Register should be a AM335_TIMER_REGISTER value.
- //
- #define READ_TIMER_REGISTER(_Base, _Register) \
- HlReadRegister32((_Base) + (_Register))
- //
- // This macro writes to an AM335 timer. _Base should be a pointer,
- // _Register should be AM335_TIMER_REGISTER value, and _Value should be a
- // ULONG.
- //
- #define WRITE_TIMER_REGISTER(_Base, _Register, _Value) \
- HlWriteRegister32((_Base) + (_Register), (_Value))
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- /*++
- Structure Description:
- This structure stores the internal state associated with an AM335 DM
- timer.
- Members:
- Base - Stores the virtual address of the timer.
- PhysicalAddress - Stores the physical address of the timer.
- Index - Stores the zero-based index of this timer number.
- --*/
- typedef struct _AM335_TIMER_DATA {
- PVOID Base;
- PHYSICAL_ADDRESS PhysicalAddress;
- ULONG Index;
- } AM335_TIMER_DATA, *PAM335_TIMER_DATA;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- HlpAm335TimerInitialize (
- PVOID Context
- );
- ULONGLONG
- HlpAm335TimerRead (
- PVOID Context
- );
- VOID
- HlpAm335TimerWrite (
- PVOID Context,
- ULONGLONG NewCount
- );
- KSTATUS
- HlpAm335TimerArm (
- PVOID Context,
- TIMER_MODE Mode,
- ULONGLONG TickCount
- );
- VOID
- HlpAm335TimerDisarm (
- PVOID Context
- );
- VOID
- HlpAm335TimerAcknowledgeInterrupt (
- PVOID Context
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- PAM335X_TABLE HlAm335Table = NULL;
- //
- // ------------------------------------------------------------------ Functions
- //
- VOID
- HlpAm335TimerModuleEntry (
- VOID
- )
- /*++
- Routine Description:
- This routine is the entry point for the AM335 DM Timer hardware module.
- Its role is to detect and report the prescense of AM335 Timers.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- KSTATUS Status;
- TIMER_DESCRIPTION Timer;
- PAM335_TIMER_DATA TimerData;
- ULONG TimerIndex;
- HlAm335Table = HlGetAcpiTable(AM335X_SIGNATURE, NULL);
- if (HlAm335Table == NULL) {
- goto Am335TimerModuleEntryEnd;
- }
- //
- // Fire up the timer's power.
- //
- Status = HlpAm335InitializePowerAndClocks();
- if (!KSUCCESS(Status)) {
- goto Am335TimerModuleEntryEnd;
- }
- //
- // Register each of the independent timers in the timer block.
- //
- for (TimerIndex = 0; TimerIndex < AM335X_TIMER_COUNT; TimerIndex += 1) {
- //
- // Skip the timer if it has no address.
- //
- if (HlAm335Table->TimerBase[TimerIndex] == 0) {
- continue;
- }
- //
- // Skip timer 1 for now, as it has funky register offsets and not that
- // many timers are needed. Skip timer 0 as it seems to interact with
- // power management.
- //
- if ((TimerIndex == 1) || (TimerIndex == 0)) {
- continue;
- }
- RtlZeroMemory(&Timer, sizeof(TIMER_DESCRIPTION));
- Timer.TableVersion = TIMER_DESCRIPTION_VERSION;
- Timer.FunctionTable.Initialize = HlpAm335TimerInitialize;
- Timer.FunctionTable.ReadCounter = HlpAm335TimerRead;
- Timer.FunctionTable.WriteCounter = HlpAm335TimerWrite;
- Timer.FunctionTable.Arm = HlpAm335TimerArm;
- Timer.FunctionTable.Disarm = HlpAm335TimerDisarm;
- Timer.FunctionTable.AcknowledgeInterrupt =
- HlpAm335TimerAcknowledgeInterrupt;
- TimerData = HlAllocateMemory(sizeof(AM335_TIMER_DATA),
- AM335_ALLOCATION_TAG,
- FALSE,
- NULL);
- if (TimerData == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto Am335TimerModuleEntryEnd;
- }
- RtlZeroMemory(TimerData, sizeof(AM335_TIMER_DATA));
- TimerData->PhysicalAddress = HlAm335Table->TimerBase[TimerIndex];
- TimerData->Index = TimerIndex;
- Timer.Context = TimerData;
- Timer.Features = TIMER_FEATURE_READABLE |
- TIMER_FEATURE_WRITABLE |
- TIMER_FEATURE_PERIODIC |
- TIMER_FEATURE_ONE_SHOT;
- Timer.CounterBitWidth = AM335_TIMER_BIT_WIDTH;
- //
- // The first two timers run at a fixed frequency, but the rest run at
- // the system clock rate.
- //
- if ((TimerIndex == 0) || (TimerIndex == 1)) {
- Timer.CounterFrequency = AM335_TIMER_FREQUENCY_32KHZ;
- } else {
- Timer.CounterFrequency = 0;
- }
- Timer.Interrupt.Line.Type = InterruptLineControllerSpecified;
- Timer.Interrupt.Line.U.Local.Controller = 0;
- Timer.Interrupt.Line.U.Local.Line = HlAm335Table->TimerGsi[TimerIndex];
- Timer.Interrupt.TriggerMode = InterruptModeLevel;
- Timer.Interrupt.ActiveLevel = InterruptActiveLevelUnknown;
- Timer.Identifier = TimerIndex;
- //
- // Register the timer with the system.
- //
- Status = HlRegisterHardware(HardwareModuleTimer, &Timer);
- if (!KSUCCESS(Status)) {
- goto Am335TimerModuleEntryEnd;
- }
- }
- Am335TimerModuleEntryEnd:
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- HlpAm335TimerInitialize (
- PVOID Context
- )
- /*++
- Routine Description:
- This routine initializes an AM335 timer.
- Arguments:
- Context - Supplies the pointer to the timer's context, provided by the
- hardware module upon initialization.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- PAM335_TIMER_DATA Timer;
- ULONG Value;
- Timer = (PAM335_TIMER_DATA)Context;
- //
- // Map the hardware if that has not been done.
- //
- if (Timer->Base == NULL) {
- Timer->Base = HlMapPhysicalAddress(Timer->PhysicalAddress,
- AM335_TIMER_CONTROLLER_SIZE,
- TRUE);
- if (Timer->Base == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto Am335TimerInitializeEnd;
- }
- }
- //
- // Program the timer in free running mode with no interrupt.
- //
- WRITE_TIMER_REGISTER(Timer->Base,
- Am335TimerOcpConfig,
- AM335_TIMER_IDLEMODE_SMART);
- //
- // Disable wakeup functionality.
- //
- WRITE_TIMER_REGISTER(Timer->Base,
- Am335TimerInterruptWakeEnable,
- 0);
- //
- // Set the synchronous 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(Timer->Base,
- Am335TimerSynchronousInterfaceControl,
- 0);
- //
- // Disable all interrupts for now. The alternate register interface uses a
- // set/clear style for the interrupt mask bits.
- //
- WRITE_TIMER_REGISTER(Timer->Base,
- Am335TimerInterruptEnableClear,
- AM335_TIMER_INTERRUPT_MASK);
- //
- // Set the load value to zero to create a free-running timer, and reset the
- // current counter now too.
- //
- WRITE_TIMER_REGISTER(Timer->Base, Am335TimerLoad, 0);
- WRITE_TIMER_REGISTER(Timer->Base, Am335TimerCount, 0);
- //
- // Set the mode register to auto-reload, and start the timer.
- //
- Value = AM335_TIMER_OVERFLOW_TRIGGER |
- AM335_TIMER_STARTED |
- AM335_TIMER_AUTORELOAD;
- WRITE_TIMER_REGISTER(Timer->Base, Am335TimerControl, Value);
- //
- // Reset all interrupt-pending bits.
- //
- //
- WRITE_TIMER_REGISTER(Timer->Base,
- Am335TimerInterruptStatus,
- AM335_TIMER_INTERRUPT_MASK);
- Status = STATUS_SUCCESS;
- Am335TimerInitializeEnd:
- return Status;
- }
- ULONGLONG
- HlpAm335TimerRead (
- PVOID 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.
- --*/
- {
- PAM335_TIMER_DATA Timer;
- ULONG Value;
- Timer = (PAM335_TIMER_DATA)Context;
- Value = READ_TIMER_REGISTER(Timer->Base, Am335TimerCount);
- return Value;
- }
- VOID
- HlpAm335TimerWrite (
- PVOID Context,
- ULONGLONG NewCount
- )
- /*++
- Routine Description:
- This routine writes to the timer's hardware counter. This routine will
- only be called for timers that have the writable counter feature bit set.
- Arguments:
- Context - Supplies the pointer to the timer's context, provided by the
- hardware module upon initialization.
- NewCount - Supplies the value to write into the counter. It is expected that
- the counter will not stop after the write.
- Return Value:
- None.
- --*/
- {
- PAM335_TIMER_DATA Timer;
- Timer = (PAM335_TIMER_DATA)Context;
- WRITE_TIMER_REGISTER(Timer->Base, Am335TimerCount, (ULONG)NewCount);
- return;
- }
- KSTATUS
- HlpAm335TimerArm (
- PVOID Context,
- TIMER_MODE Mode,
- ULONGLONG 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, provided by the
- hardware module upon initialization.
- Mode - Supplies the mode to arm the timer in. The system will never request
- a mode not supported by the timer's feature bits. The mode dictates
- how the tick count argument is interpreted.
- TickCount - Supplies the number of timer ticks from now for the timer to
- fire in. In absolute mode, this supplies the time in timer ticks at
- which to fire an interrupt.
- Return Value:
- STATUS_SUCCESS always.
- --*/
- {
- PAM335_TIMER_DATA Timer;
- ULONG Value;
- Timer = (PAM335_TIMER_DATA)Context;
- if (TickCount >= MAX_ULONG) {
- TickCount = MAX_ULONG - 1;
- }
- if (TickCount < 2) {
- TickCount = 2;
- }
- //
- // Start the timer ticking.
- //
- WRITE_TIMER_REGISTER(Timer->Base, Am335TimerControl, 0);
- WRITE_TIMER_REGISTER(Timer->Base, Am335TimerLoad, 0 - (ULONG)TickCount);
- WRITE_TIMER_REGISTER(Timer->Base, Am335TimerCount, 0 - (ULONG)TickCount);
- Value = AM335_TIMER_STARTED;
- if (Mode == TimerModePeriodic) {
- Value |= AM335_TIMER_AUTORELOAD;
- }
- WRITE_TIMER_REGISTER(Timer->Base,
- Am335TimerInterruptEnableSet,
- AM335_TIMER_OVERFLOW_INTERRUPT);
- WRITE_TIMER_REGISTER(Timer->Base, Am335TimerControl, Value);
- return STATUS_SUCCESS;
- }
- VOID
- HlpAm335TimerDisarm (
- PVOID Context
- )
- /*++
- Routine Description:
- This routine disarms the timer, stopping interrupts from firing.
- Arguments:
- Context - Supplies the pointer to the timer's context, provided by the
- hardware module upon initialization.
- Return Value:
- None.
- --*/
- {
- PAM335_TIMER_DATA Timer;
- //
- // Disable all interrupts.
- //
- Timer = (PAM335_TIMER_DATA)Context;
- WRITE_TIMER_REGISTER(Timer->Base,
- Am335TimerInterruptEnableClear,
- AM335_TIMER_INTERRUPT_MASK);
- //
- // Reset all pending interrupt bits.
- //
- WRITE_TIMER_REGISTER(Timer->Base,
- Am335TimerInterruptStatus,
- AM335_TIMER_INTERRUPT_MASK);
- return;
- }
- VOID
- HlpAm335TimerAcknowledgeInterrupt (
- PVOID 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, provided by the
- hardware module upon initialization.
- Return Value:
- None.
- --*/
- {
- PAM335_TIMER_DATA Timer;
- Timer = (PAM335_TIMER_DATA)Context;
- //
- // Clear the overflow interrupt by writing a 1 to the status bit.
- //
- WRITE_TIMER_REGISTER(Timer->Base,
- Am335TimerInterruptStatus,
- AM335_TIMER_OVERFLOW_INTERRUPT);
- return;
- }
|