11e57a46299244793beb27e74be171d1540606999oliviermartin/** @file
21e57a46299244793beb27e74be171d1540606999oliviermartin  Template for Timer Architecture Protocol driver of the ARM flavor
31e57a46299244793beb27e74be171d1540606999oliviermartin
41e57a46299244793beb27e74be171d1540606999oliviermartin  Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
51e57a46299244793beb27e74be171d1540606999oliviermartin
63402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  This program and the accompanying materials
73402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  are licensed and made available under the terms and conditions of the BSD License
83402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  which accompanies this distribution.  The full text of the license may be found at
93402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  http://opensource.org/licenses/bsd-license.php
103402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron
113402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
123402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
131e57a46299244793beb27e74be171d1540606999oliviermartin
141e57a46299244793beb27e74be171d1540606999oliviermartin**/
151e57a46299244793beb27e74be171d1540606999oliviermartin
161e57a46299244793beb27e74be171d1540606999oliviermartin
171e57a46299244793beb27e74be171d1540606999oliviermartin#include <PiDxe.h>
181e57a46299244793beb27e74be171d1540606999oliviermartin
191e57a46299244793beb27e74be171d1540606999oliviermartin#include <Library/BaseLib.h>
201e57a46299244793beb27e74be171d1540606999oliviermartin#include <Library/DebugLib.h>
211e57a46299244793beb27e74be171d1540606999oliviermartin#include <Library/BaseMemoryLib.h>
221e57a46299244793beb27e74be171d1540606999oliviermartin#include <Library/UefiBootServicesTableLib.h>
231e57a46299244793beb27e74be171d1540606999oliviermartin#include <Library/UefiLib.h>
241e57a46299244793beb27e74be171d1540606999oliviermartin#include <Library/PcdLib.h>
251e57a46299244793beb27e74be171d1540606999oliviermartin#include <Library/IoLib.h>
261e57a46299244793beb27e74be171d1540606999oliviermartin#include <Library/OmapLib.h>
271e57a46299244793beb27e74be171d1540606999oliviermartin
281e57a46299244793beb27e74be171d1540606999oliviermartin#include <Protocol/Timer.h>
291e57a46299244793beb27e74be171d1540606999oliviermartin#include <Protocol/HardwareInterrupt.h>
301e57a46299244793beb27e74be171d1540606999oliviermartin
311e57a46299244793beb27e74be171d1540606999oliviermartin#include <Omap3530/Omap3530.h>
321e57a46299244793beb27e74be171d1540606999oliviermartin
331e57a46299244793beb27e74be171d1540606999oliviermartin
341e57a46299244793beb27e74be171d1540606999oliviermartin// The notification function to call on every timer interrupt.
351e57a46299244793beb27e74be171d1540606999oliviermartinvolatile EFI_TIMER_NOTIFY      mTimerNotifyFunction   = (EFI_TIMER_NOTIFY)NULL;
361e57a46299244793beb27e74be171d1540606999oliviermartin
371e57a46299244793beb27e74be171d1540606999oliviermartin
381e57a46299244793beb27e74be171d1540606999oliviermartin// The current period of the timer interrupt
391e57a46299244793beb27e74be171d1540606999oliviermartinvolatile UINT64 mTimerPeriod = 0;
401e57a46299244793beb27e74be171d1540606999oliviermartin
411e57a46299244793beb27e74be171d1540606999oliviermartin// Cached copy of the Hardware Interrupt protocol instance
421e57a46299244793beb27e74be171d1540606999oliviermartinEFI_HARDWARE_INTERRUPT_PROTOCOL *gInterrupt = NULL;
431e57a46299244793beb27e74be171d1540606999oliviermartin
441e57a46299244793beb27e74be171d1540606999oliviermartin// Cached registers
451e57a46299244793beb27e74be171d1540606999oliviermartinvolatile UINT32 TISR;
461e57a46299244793beb27e74be171d1540606999oliviermartinvolatile UINT32 TCLR;
471e57a46299244793beb27e74be171d1540606999oliviermartinvolatile UINT32 TLDR;
481e57a46299244793beb27e74be171d1540606999oliviermartinvolatile UINT32 TCRR;
491e57a46299244793beb27e74be171d1540606999oliviermartinvolatile UINT32 TIER;
501e57a46299244793beb27e74be171d1540606999oliviermartin
511e57a46299244793beb27e74be171d1540606999oliviermartin// Cached interrupt vector
521e57a46299244793beb27e74be171d1540606999oliviermartinvolatile UINTN  gVector;
531e57a46299244793beb27e74be171d1540606999oliviermartin
541e57a46299244793beb27e74be171d1540606999oliviermartin
551e57a46299244793beb27e74be171d1540606999oliviermartin/**
561e57a46299244793beb27e74be171d1540606999oliviermartin
571e57a46299244793beb27e74be171d1540606999oliviermartin  C Interrupt Handler calledin the interrupt context when Source interrupt is active.
581e57a46299244793beb27e74be171d1540606999oliviermartin
591e57a46299244793beb27e74be171d1540606999oliviermartin
601e57a46299244793beb27e74be171d1540606999oliviermartin  @param Source         Source of the interrupt. Hardware routing off a specific platform defines
611e57a46299244793beb27e74be171d1540606999oliviermartin                        what source means.
621e57a46299244793beb27e74be171d1540606999oliviermartin
631e57a46299244793beb27e74be171d1540606999oliviermartin  @param SystemContext  Pointer to system register context. Mostly used by debuggers and will
643402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron                        update the system context after the return from the interrupt if
651e57a46299244793beb27e74be171d1540606999oliviermartin                        modified. Don't change these values unless you know what you are doing
661e57a46299244793beb27e74be171d1540606999oliviermartin
671e57a46299244793beb27e74be171d1540606999oliviermartin**/
681e57a46299244793beb27e74be171d1540606999oliviermartinVOID
691e57a46299244793beb27e74be171d1540606999oliviermartinEFIAPI
701e57a46299244793beb27e74be171d1540606999oliviermartinTimerInterruptHandler (
711e57a46299244793beb27e74be171d1540606999oliviermartin  IN  HARDWARE_INTERRUPT_SOURCE   Source,
723402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  IN  EFI_SYSTEM_CONTEXT          SystemContext
731e57a46299244793beb27e74be171d1540606999oliviermartin  )
741e57a46299244793beb27e74be171d1540606999oliviermartin{
751e57a46299244793beb27e74be171d1540606999oliviermartin  EFI_TPL OriginalTPL;
761e57a46299244793beb27e74be171d1540606999oliviermartin
771e57a46299244793beb27e74be171d1540606999oliviermartin
781e57a46299244793beb27e74be171d1540606999oliviermartin
791e57a46299244793beb27e74be171d1540606999oliviermartin  //
803402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  // DXE core uses this callback for the EFI timer tick. The DXE core uses locks
811e57a46299244793beb27e74be171d1540606999oliviermartin  // that raise to TPL_HIGH and then restore back to current level. Thus we need
823402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  // to make sure TPL level is set to TPL_HIGH while we are handling the timer tick.
831e57a46299244793beb27e74be171d1540606999oliviermartin  //
841e57a46299244793beb27e74be171d1540606999oliviermartin  OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
851e57a46299244793beb27e74be171d1540606999oliviermartin
861e57a46299244793beb27e74be171d1540606999oliviermartin  if (mTimerNotifyFunction) {
871e57a46299244793beb27e74be171d1540606999oliviermartin    mTimerNotifyFunction(mTimerPeriod);
881e57a46299244793beb27e74be171d1540606999oliviermartin  }
891e57a46299244793beb27e74be171d1540606999oliviermartin
901e57a46299244793beb27e74be171d1540606999oliviermartin  // Clear all timer interrupts
913402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  MmioWrite32 (TISR, TISR_CLEAR_ALL);
921e57a46299244793beb27e74be171d1540606999oliviermartin
931e57a46299244793beb27e74be171d1540606999oliviermartin  // Poll interrupt status bits to ensure clearing
941e57a46299244793beb27e74be171d1540606999oliviermartin  while ((MmioRead32 (TISR) & TISR_ALL_INTERRUPT_MASK) != TISR_NO_INTERRUPTS_PENDING);
951e57a46299244793beb27e74be171d1540606999oliviermartin
961e57a46299244793beb27e74be171d1540606999oliviermartin  gBS->RestoreTPL (OriginalTPL);
971e57a46299244793beb27e74be171d1540606999oliviermartin}
981e57a46299244793beb27e74be171d1540606999oliviermartin
991e57a46299244793beb27e74be171d1540606999oliviermartin/**
1003402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  This function registers the handler NotifyFunction so it is called every time
1013402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  the timer interrupt fires.  It also passes the amount of time since the last
1023402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  handler call to the NotifyFunction.  If NotifyFunction is NULL, then the
1033402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  handler is unregistered.  If the handler is registered, then EFI_SUCCESS is
1043402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  returned.  If the CPU does not support registering a timer interrupt handler,
1053402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  then EFI_UNSUPPORTED is returned.  If an attempt is made to register a handler
1063402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  when a handler is already registered, then EFI_ALREADY_STARTED is returned.
1073402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  If an attempt is made to unregister a handler when a handler is not registered,
1083402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  then EFI_INVALID_PARAMETER is returned.  If an error occurs attempting to
1093402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  register the NotifyFunction with the timer interrupt, then EFI_DEVICE_ERROR
1101e57a46299244793beb27e74be171d1540606999oliviermartin  is returned.
1111e57a46299244793beb27e74be171d1540606999oliviermartin
1121e57a46299244793beb27e74be171d1540606999oliviermartin  @param  This             The EFI_TIMER_ARCH_PROTOCOL instance.
1131e57a46299244793beb27e74be171d1540606999oliviermartin  @param  NotifyFunction   The function to call when a timer interrupt fires. This
1141e57a46299244793beb27e74be171d1540606999oliviermartin                           function executes at TPL_HIGH_LEVEL. The DXE Core will
1151e57a46299244793beb27e74be171d1540606999oliviermartin                           register a handler for the timer interrupt, so it can know
1161e57a46299244793beb27e74be171d1540606999oliviermartin                           how much time has passed. This information is used to
1171e57a46299244793beb27e74be171d1540606999oliviermartin                           signal timer based events. NULL will unregister the handler.
1181e57a46299244793beb27e74be171d1540606999oliviermartin  @retval EFI_SUCCESS           The timer handler was registered.
1191e57a46299244793beb27e74be171d1540606999oliviermartin  @retval EFI_UNSUPPORTED       The platform does not support timer interrupts.
1201e57a46299244793beb27e74be171d1540606999oliviermartin  @retval EFI_ALREADY_STARTED   NotifyFunction is not NULL, and a handler is already
1211e57a46299244793beb27e74be171d1540606999oliviermartin                                registered.
1221e57a46299244793beb27e74be171d1540606999oliviermartin  @retval EFI_INVALID_PARAMETER NotifyFunction is NULL, and a handler was not
1231e57a46299244793beb27e74be171d1540606999oliviermartin                                previously registered.
1241e57a46299244793beb27e74be171d1540606999oliviermartin  @retval EFI_DEVICE_ERROR      The timer handler could not be registered.
1251e57a46299244793beb27e74be171d1540606999oliviermartin
1261e57a46299244793beb27e74be171d1540606999oliviermartin**/
1271e57a46299244793beb27e74be171d1540606999oliviermartinEFI_STATUS
1281e57a46299244793beb27e74be171d1540606999oliviermartinEFIAPI
1291e57a46299244793beb27e74be171d1540606999oliviermartinTimerDriverRegisterHandler (
1301e57a46299244793beb27e74be171d1540606999oliviermartin  IN EFI_TIMER_ARCH_PROTOCOL  *This,
1311e57a46299244793beb27e74be171d1540606999oliviermartin  IN EFI_TIMER_NOTIFY         NotifyFunction
1321e57a46299244793beb27e74be171d1540606999oliviermartin  )
1331e57a46299244793beb27e74be171d1540606999oliviermartin{
1341e57a46299244793beb27e74be171d1540606999oliviermartin  if ((NotifyFunction == NULL) && (mTimerNotifyFunction == NULL)) {
1351e57a46299244793beb27e74be171d1540606999oliviermartin    return EFI_INVALID_PARAMETER;
1361e57a46299244793beb27e74be171d1540606999oliviermartin  }
1371e57a46299244793beb27e74be171d1540606999oliviermartin
1381e57a46299244793beb27e74be171d1540606999oliviermartin  if ((NotifyFunction != NULL) && (mTimerNotifyFunction != NULL)) {
1391e57a46299244793beb27e74be171d1540606999oliviermartin    return EFI_ALREADY_STARTED;
1401e57a46299244793beb27e74be171d1540606999oliviermartin  }
1411e57a46299244793beb27e74be171d1540606999oliviermartin
1421e57a46299244793beb27e74be171d1540606999oliviermartin  mTimerNotifyFunction = NotifyFunction;
1431e57a46299244793beb27e74be171d1540606999oliviermartin
1441e57a46299244793beb27e74be171d1540606999oliviermartin  return EFI_SUCCESS;
1451e57a46299244793beb27e74be171d1540606999oliviermartin}
1461e57a46299244793beb27e74be171d1540606999oliviermartin
1471e57a46299244793beb27e74be171d1540606999oliviermartin/**
1481e57a46299244793beb27e74be171d1540606999oliviermartin
1493402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  This function adjusts the period of timer interrupts to the value specified
1503402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  by TimerPeriod.  If the timer period is updated, then the selected timer
1513402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  period is stored in EFI_TIMER.TimerPeriod, and EFI_SUCCESS is returned.  If
1523402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  the timer hardware is not programmable, then EFI_UNSUPPORTED is returned.
1533402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  If an error occurs while attempting to update the timer period, then the
1543402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  timer hardware will be put back in its state prior to this call, and
1553402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  EFI_DEVICE_ERROR is returned.  If TimerPeriod is 0, then the timer interrupt
1563402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  is disabled.  This is not the same as disabling the CPU's interrupts.
1573402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  Instead, it must either turn off the timer hardware, or it must adjust the
1583402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  interrupt controller so that a CPU interrupt is not generated when the timer
1593402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  interrupt fires.
1601e57a46299244793beb27e74be171d1540606999oliviermartin
1611e57a46299244793beb27e74be171d1540606999oliviermartin  @param  This             The EFI_TIMER_ARCH_PROTOCOL instance.
1621e57a46299244793beb27e74be171d1540606999oliviermartin  @param  TimerPeriod      The rate to program the timer interrupt in 100 nS units. If
1631e57a46299244793beb27e74be171d1540606999oliviermartin                           the timer hardware is not programmable, then EFI_UNSUPPORTED is
1641e57a46299244793beb27e74be171d1540606999oliviermartin                           returned. If the timer is programmable, then the timer period
1651e57a46299244793beb27e74be171d1540606999oliviermartin                           will be rounded up to the nearest timer period that is supported
1661e57a46299244793beb27e74be171d1540606999oliviermartin                           by the timer hardware. If TimerPeriod is set to 0, then the
1671e57a46299244793beb27e74be171d1540606999oliviermartin                           timer interrupts will be disabled.
1681e57a46299244793beb27e74be171d1540606999oliviermartin
1691e57a46299244793beb27e74be171d1540606999oliviermartin
1701e57a46299244793beb27e74be171d1540606999oliviermartin  @retval EFI_SUCCESS           The timer period was changed.
1711e57a46299244793beb27e74be171d1540606999oliviermartin  @retval EFI_UNSUPPORTED       The platform cannot change the period of the timer interrupt.
1721e57a46299244793beb27e74be171d1540606999oliviermartin  @retval EFI_DEVICE_ERROR      The timer period could not be changed due to a device error.
1731e57a46299244793beb27e74be171d1540606999oliviermartin
1741e57a46299244793beb27e74be171d1540606999oliviermartin**/
1751e57a46299244793beb27e74be171d1540606999oliviermartinEFI_STATUS
1761e57a46299244793beb27e74be171d1540606999oliviermartinEFIAPI
1771e57a46299244793beb27e74be171d1540606999oliviermartinTimerDriverSetTimerPeriod (
1781e57a46299244793beb27e74be171d1540606999oliviermartin  IN EFI_TIMER_ARCH_PROTOCOL  *This,
1791e57a46299244793beb27e74be171d1540606999oliviermartin  IN UINT64                   TimerPeriod
1801e57a46299244793beb27e74be171d1540606999oliviermartin  )
1811e57a46299244793beb27e74be171d1540606999oliviermartin{
1821e57a46299244793beb27e74be171d1540606999oliviermartin  EFI_STATUS  Status;
1831e57a46299244793beb27e74be171d1540606999oliviermartin  UINT64      TimerCount;
1841e57a46299244793beb27e74be171d1540606999oliviermartin  INT32       LoadValue;
1853402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron
1861e57a46299244793beb27e74be171d1540606999oliviermartin  if (TimerPeriod == 0) {
1871e57a46299244793beb27e74be171d1540606999oliviermartin    // Turn off GPTIMER3
1881e57a46299244793beb27e74be171d1540606999oliviermartin    MmioWrite32 (TCLR, TCLR_ST_OFF);
1893402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron
1903402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron    Status = gInterrupt->DisableInterruptSource(gInterrupt, gVector);
1913402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  } else {
1921e57a46299244793beb27e74be171d1540606999oliviermartin    // Calculate required timer count
1931e57a46299244793beb27e74be171d1540606999oliviermartin    TimerCount = DivU64x32(TimerPeriod * 100, PcdGet32(PcdEmbeddedPerformanceCounterPeriodInNanoseconds));
1941e57a46299244793beb27e74be171d1540606999oliviermartin
1951e57a46299244793beb27e74be171d1540606999oliviermartin    // Set GPTIMER3 Load register
1961e57a46299244793beb27e74be171d1540606999oliviermartin    LoadValue = (INT32) -TimerCount;
1971e57a46299244793beb27e74be171d1540606999oliviermartin    MmioWrite32 (TLDR, LoadValue);
1981e57a46299244793beb27e74be171d1540606999oliviermartin    MmioWrite32 (TCRR, LoadValue);
1991e57a46299244793beb27e74be171d1540606999oliviermartin
2001e57a46299244793beb27e74be171d1540606999oliviermartin    // Enable Overflow interrupt
2011e57a46299244793beb27e74be171d1540606999oliviermartin    MmioWrite32 (TIER, TIER_TCAR_IT_DISABLE | TIER_OVF_IT_ENABLE | TIER_MAT_IT_DISABLE);
2021e57a46299244793beb27e74be171d1540606999oliviermartin
2031e57a46299244793beb27e74be171d1540606999oliviermartin    // Turn on GPTIMER3, it will reload at overflow
2041e57a46299244793beb27e74be171d1540606999oliviermartin    MmioWrite32 (TCLR, TCLR_AR_AUTORELOAD | TCLR_ST_ON);
2051e57a46299244793beb27e74be171d1540606999oliviermartin
2063402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron    Status = gInterrupt->EnableInterruptSource(gInterrupt, gVector);
2071e57a46299244793beb27e74be171d1540606999oliviermartin  }
2081e57a46299244793beb27e74be171d1540606999oliviermartin
2091e57a46299244793beb27e74be171d1540606999oliviermartin  //
2101e57a46299244793beb27e74be171d1540606999oliviermartin  // Save the new timer period
2111e57a46299244793beb27e74be171d1540606999oliviermartin  //
2121e57a46299244793beb27e74be171d1540606999oliviermartin  mTimerPeriod = TimerPeriod;
2131e57a46299244793beb27e74be171d1540606999oliviermartin  return Status;
2141e57a46299244793beb27e74be171d1540606999oliviermartin}
2151e57a46299244793beb27e74be171d1540606999oliviermartin
2161e57a46299244793beb27e74be171d1540606999oliviermartin
2171e57a46299244793beb27e74be171d1540606999oliviermartin/**
2183402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  This function retrieves the period of timer interrupts in 100 ns units,
2193402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  returns that value in TimerPeriod, and returns EFI_SUCCESS.  If TimerPeriod
2203402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  is NULL, then EFI_INVALID_PARAMETER is returned.  If a TimerPeriod of 0 is
2211e57a46299244793beb27e74be171d1540606999oliviermartin  returned, then the timer is currently disabled.
2221e57a46299244793beb27e74be171d1540606999oliviermartin
2231e57a46299244793beb27e74be171d1540606999oliviermartin  @param  This             The EFI_TIMER_ARCH_PROTOCOL instance.
2241e57a46299244793beb27e74be171d1540606999oliviermartin  @param  TimerPeriod      A pointer to the timer period to retrieve in 100 ns units. If
2251e57a46299244793beb27e74be171d1540606999oliviermartin                           0 is returned, then the timer is currently disabled.
2261e57a46299244793beb27e74be171d1540606999oliviermartin
2271e57a46299244793beb27e74be171d1540606999oliviermartin
2281e57a46299244793beb27e74be171d1540606999oliviermartin  @retval EFI_SUCCESS           The timer period was returned in TimerPeriod.
2291e57a46299244793beb27e74be171d1540606999oliviermartin  @retval EFI_INVALID_PARAMETER TimerPeriod is NULL.
2301e57a46299244793beb27e74be171d1540606999oliviermartin
2311e57a46299244793beb27e74be171d1540606999oliviermartin**/
2321e57a46299244793beb27e74be171d1540606999oliviermartinEFI_STATUS
2331e57a46299244793beb27e74be171d1540606999oliviermartinEFIAPI
2341e57a46299244793beb27e74be171d1540606999oliviermartinTimerDriverGetTimerPeriod (
2351e57a46299244793beb27e74be171d1540606999oliviermartin  IN EFI_TIMER_ARCH_PROTOCOL   *This,
2361e57a46299244793beb27e74be171d1540606999oliviermartin  OUT UINT64                   *TimerPeriod
2371e57a46299244793beb27e74be171d1540606999oliviermartin  )
2381e57a46299244793beb27e74be171d1540606999oliviermartin{
2391e57a46299244793beb27e74be171d1540606999oliviermartin  if (TimerPeriod == NULL) {
2401e57a46299244793beb27e74be171d1540606999oliviermartin    return EFI_INVALID_PARAMETER;
2411e57a46299244793beb27e74be171d1540606999oliviermartin  }
2421e57a46299244793beb27e74be171d1540606999oliviermartin
2431e57a46299244793beb27e74be171d1540606999oliviermartin  *TimerPeriod = mTimerPeriod;
2441e57a46299244793beb27e74be171d1540606999oliviermartin  return EFI_SUCCESS;
2451e57a46299244793beb27e74be171d1540606999oliviermartin}
2461e57a46299244793beb27e74be171d1540606999oliviermartin
2471e57a46299244793beb27e74be171d1540606999oliviermartin/**
2483402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  This function generates a soft timer interrupt. If the platform does not support soft
2493402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  timer interrupts, then EFI_UNSUPPORTED is returned. Otherwise, EFI_SUCCESS is returned.
2503402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  If a handler has been registered through the EFI_TIMER_ARCH_PROTOCOL.RegisterHandler()
2513402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  service, then a soft timer interrupt will be generated. If the timer interrupt is
2523402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  enabled when this service is called, then the registered handler will be invoked. The
2533402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  registered handler should not be able to distinguish a hardware-generated timer
2541e57a46299244793beb27e74be171d1540606999oliviermartin  interrupt from a software-generated timer interrupt.
2551e57a46299244793beb27e74be171d1540606999oliviermartin
2561e57a46299244793beb27e74be171d1540606999oliviermartin  @param  This             The EFI_TIMER_ARCH_PROTOCOL instance.
2571e57a46299244793beb27e74be171d1540606999oliviermartin
2581e57a46299244793beb27e74be171d1540606999oliviermartin  @retval EFI_SUCCESS           The soft timer interrupt was generated.
2591e57a46299244793beb27e74be171d1540606999oliviermartin  @retval EFI_UNSUPPORTED       The platform does not support the generation of soft timer interrupts.
2601e57a46299244793beb27e74be171d1540606999oliviermartin
2611e57a46299244793beb27e74be171d1540606999oliviermartin**/
2621e57a46299244793beb27e74be171d1540606999oliviermartinEFI_STATUS
2631e57a46299244793beb27e74be171d1540606999oliviermartinEFIAPI
2641e57a46299244793beb27e74be171d1540606999oliviermartinTimerDriverGenerateSoftInterrupt (
2651e57a46299244793beb27e74be171d1540606999oliviermartin  IN EFI_TIMER_ARCH_PROTOCOL  *This
2661e57a46299244793beb27e74be171d1540606999oliviermartin  )
2671e57a46299244793beb27e74be171d1540606999oliviermartin{
2681e57a46299244793beb27e74be171d1540606999oliviermartin  return EFI_UNSUPPORTED;
2691e57a46299244793beb27e74be171d1540606999oliviermartin}
2701e57a46299244793beb27e74be171d1540606999oliviermartin
2711e57a46299244793beb27e74be171d1540606999oliviermartin
2721e57a46299244793beb27e74be171d1540606999oliviermartin/**
2731e57a46299244793beb27e74be171d1540606999oliviermartin  Interface stucture for the Timer Architectural Protocol.
2741e57a46299244793beb27e74be171d1540606999oliviermartin
2751e57a46299244793beb27e74be171d1540606999oliviermartin  @par Protocol Description:
2763402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  This protocol provides the services to initialize a periodic timer
2771e57a46299244793beb27e74be171d1540606999oliviermartin  interrupt, and to register a handler that is called each time the timer
2781e57a46299244793beb27e74be171d1540606999oliviermartin  interrupt fires.  It may also provide a service to adjust the rate of the
2793402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  periodic timer interrupt.  When a timer interrupt occurs, the handler is
2803402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  passed the amount of time that has passed since the previous timer
2811e57a46299244793beb27e74be171d1540606999oliviermartin  interrupt.
2821e57a46299244793beb27e74be171d1540606999oliviermartin
2831e57a46299244793beb27e74be171d1540606999oliviermartin  @param RegisterHandler
2843402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  Registers a handler that will be called each time the
2853402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  timer interrupt fires.  TimerPeriod defines the minimum
2863402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  time between timer interrupts, so TimerPeriod will also
2873402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  be the minimum time between calls to the registered
2881e57a46299244793beb27e74be171d1540606999oliviermartin  handler.
2891e57a46299244793beb27e74be171d1540606999oliviermartin
2901e57a46299244793beb27e74be171d1540606999oliviermartin  @param SetTimerPeriod
2913402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  Sets the period of the timer interrupt in 100 nS units.
2923402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  This function is optional, and may return EFI_UNSUPPORTED.
2933402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  If this function is supported, then the timer period will
2941e57a46299244793beb27e74be171d1540606999oliviermartin  be rounded up to the nearest supported timer period.
2951e57a46299244793beb27e74be171d1540606999oliviermartin
2961e57a46299244793beb27e74be171d1540606999oliviermartin
2971e57a46299244793beb27e74be171d1540606999oliviermartin  @param GetTimerPeriod
2981e57a46299244793beb27e74be171d1540606999oliviermartin  Retrieves the period of the timer interrupt in 100 nS units.
2991e57a46299244793beb27e74be171d1540606999oliviermartin
3001e57a46299244793beb27e74be171d1540606999oliviermartin  @param GenerateSoftInterrupt
3013402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  Generates a soft timer interrupt that simulates the firing of
3023402aac7d985bf8a9f9d3c639f3fe93609380513Ronald Cron  the timer interrupt. This service can be used to invoke the   registered handler if the timer interrupt has been masked for
3031e57a46299244793beb27e74be171d1540606999oliviermartin  a period of time.
3041e57a46299244793beb27e74be171d1540606999oliviermartin
3051e57a46299244793beb27e74be171d1540606999oliviermartin**/
3061e57a46299244793beb27e74be171d1540606999oliviermartinEFI_TIMER_ARCH_PROTOCOL   gTimer = {
3071e57a46299244793beb27e74be171d1540606999oliviermartin  TimerDriverRegisterHandler,
3081e57a46299244793beb27e74be171d1540606999oliviermartin  TimerDriverSetTimerPeriod,
3091e57a46299244793beb27e74be171d1540606999oliviermartin  TimerDriverGetTimerPeriod,
3101e57a46299244793beb27e74be171d1540606999oliviermartin  TimerDriverGenerateSoftInterrupt
3111e57a46299244793beb27e74be171d1540606999oliviermartin};
3121e57a46299244793beb27e74be171d1540606999oliviermartin
3131e57a46299244793beb27e74be171d1540606999oliviermartin
3141e57a46299244793beb27e74be171d1540606999oliviermartin/**
3151e57a46299244793beb27e74be171d1540606999oliviermartin  Initialize the state information for the Timer Architectural Protocol and
3161e57a46299244793beb27e74be171d1540606999oliviermartin  the Timer Debug support protocol that allows the debugger to break into a
3171e57a46299244793beb27e74be171d1540606999oliviermartin  running program.
3181e57a46299244793beb27e74be171d1540606999oliviermartin
3191e57a46299244793beb27e74be171d1540606999oliviermartin  @param  ImageHandle   of the loaded driver
3201e57a46299244793beb27e74be171d1540606999oliviermartin  @param  SystemTable   Pointer to the System Table
3211e57a46299244793beb27e74be171d1540606999oliviermartin
3221e57a46299244793beb27e74be171d1540606999oliviermartin  @retval EFI_SUCCESS           Protocol registered
3231e57a46299244793beb27e74be171d1540606999oliviermartin  @retval EFI_OUT_OF_RESOURCES  Cannot allocate protocol data structure
3241e57a46299244793beb27e74be171d1540606999oliviermartin  @retval EFI_DEVICE_ERROR      Hardware problems
3251e57a46299244793beb27e74be171d1540606999oliviermartin
3261e57a46299244793beb27e74be171d1540606999oliviermartin**/
3271e57a46299244793beb27e74be171d1540606999oliviermartinEFI_STATUS
3281e57a46299244793beb27e74be171d1540606999oliviermartinEFIAPI
3291e57a46299244793beb27e74be171d1540606999oliviermartinTimerInitialize (
3301e57a46299244793beb27e74be171d1540606999oliviermartin  IN EFI_HANDLE         ImageHandle,
3311e57a46299244793beb27e74be171d1540606999oliviermartin  IN EFI_SYSTEM_TABLE   *SystemTable
3321e57a46299244793beb27e74be171d1540606999oliviermartin  )
3331e57a46299244793beb27e74be171d1540606999oliviermartin{
3341e57a46299244793beb27e74be171d1540606999oliviermartin  EFI_HANDLE  Handle = NULL;
3351e57a46299244793beb27e74be171d1540606999oliviermartin  EFI_STATUS  Status;
3361e57a46299244793beb27e74be171d1540606999oliviermartin  UINT32      TimerBaseAddress;
3371e57a46299244793beb27e74be171d1540606999oliviermartin
3381e57a46299244793beb27e74be171d1540606999oliviermartin  // Find the interrupt controller protocol.  ASSERT if not found.
3391e57a46299244793beb27e74be171d1540606999oliviermartin  Status = gBS->LocateProtocol (&gHardwareInterruptProtocolGuid, NULL, (VOID **)&gInterrupt);
3401e57a46299244793beb27e74be171d1540606999oliviermartin  ASSERT_EFI_ERROR (Status);
3411e57a46299244793beb27e74be171d1540606999oliviermartin
3421e57a46299244793beb27e74be171d1540606999oliviermartin  // Set up the timer registers
3431e57a46299244793beb27e74be171d1540606999oliviermartin  TimerBaseAddress = TimerBase (FixedPcdGet32(PcdOmap35xxArchTimer));
3441e57a46299244793beb27e74be171d1540606999oliviermartin  TISR = TimerBaseAddress + GPTIMER_TISR;
3451e57a46299244793beb27e74be171d1540606999oliviermartin  TCLR = TimerBaseAddress + GPTIMER_TCLR;
3461e57a46299244793beb27e74be171d1540606999oliviermartin  TLDR = TimerBaseAddress + GPTIMER_TLDR;
3471e57a46299244793beb27e74be171d1540606999oliviermartin  TCRR = TimerBaseAddress + GPTIMER_TCRR;
3481e57a46299244793beb27e74be171d1540606999oliviermartin  TIER = TimerBaseAddress + GPTIMER_TIER;
3491e57a46299244793beb27e74be171d1540606999oliviermartin
3501e57a46299244793beb27e74be171d1540606999oliviermartin  // Disable the timer
3511e57a46299244793beb27e74be171d1540606999oliviermartin  Status = TimerDriverSetTimerPeriod (&gTimer, 0);
3521e57a46299244793beb27e74be171d1540606999oliviermartin  ASSERT_EFI_ERROR (Status);
3531e57a46299244793beb27e74be171d1540606999oliviermartin
3541e57a46299244793beb27e74be171d1540606999oliviermartin  // Install interrupt handler
3551e57a46299244793beb27e74be171d1540606999oliviermartin  gVector = InterruptVectorForTimer (FixedPcdGet32(PcdOmap35xxArchTimer));
3561e57a46299244793beb27e74be171d1540606999oliviermartin  Status = gInterrupt->RegisterInterruptSource (gInterrupt, gVector, TimerInterruptHandler);
3571e57a46299244793beb27e74be171d1540606999oliviermartin  ASSERT_EFI_ERROR (Status);
3581e57a46299244793beb27e74be171d1540606999oliviermartin
3591e57a46299244793beb27e74be171d1540606999oliviermartin  // Turn on the functional clock for Timer
3601e57a46299244793beb27e74be171d1540606999oliviermartin  MmioOr32 (CM_FCLKEN_PER, CM_FCLKEN_PER_EN_GPT3_ENABLE);
3611e57a46299244793beb27e74be171d1540606999oliviermartin
3621e57a46299244793beb27e74be171d1540606999oliviermartin  // Set up default timer
3631e57a46299244793beb27e74be171d1540606999oliviermartin  Status = TimerDriverSetTimerPeriod (&gTimer, FixedPcdGet32(PcdTimerPeriod));
3641e57a46299244793beb27e74be171d1540606999oliviermartin  ASSERT_EFI_ERROR (Status);
3651e57a46299244793beb27e74be171d1540606999oliviermartin
3661e57a46299244793beb27e74be171d1540606999oliviermartin  // Install the Timer Architectural Protocol onto a new handle
3671e57a46299244793beb27e74be171d1540606999oliviermartin  Status = gBS->InstallMultipleProtocolInterfaces (
3681e57a46299244793beb27e74be171d1540606999oliviermartin                  &Handle,
3691e57a46299244793beb27e74be171d1540606999oliviermartin                  &gEfiTimerArchProtocolGuid,      &gTimer,
3701e57a46299244793beb27e74be171d1540606999oliviermartin                  NULL
3711e57a46299244793beb27e74be171d1540606999oliviermartin                  );
3721e57a46299244793beb27e74be171d1540606999oliviermartin  ASSERT_EFI_ERROR(Status);
3731e57a46299244793beb27e74be171d1540606999oliviermartin
3741e57a46299244793beb27e74be171d1540606999oliviermartin  return Status;
3751e57a46299244793beb27e74be171d1540606999oliviermartin}
3761e57a46299244793beb27e74be171d1540606999oliviermartin
377