gTimer protocol的实现

来源:互联网 发布:淘宝开放平台 编辑:程序博客网 时间:2024/05/16 11:22
在Omap35xxpkg中的TimerDxe 有实现gTimer。
从inf中可以看到这个是一个DXE_DRIVER driver,其入口函数是TimerInitialize
[Defines]
  INF_VERSION                    = 0x00010005
  BASE_NAME                      = BeagleBoardTimerDxe
  FILE_GUID                      = 6ddbf08b-cfc9-43cc-9e81-0784ba312ca0
  MODULE_TYPE                    = DXE_DRIVER
  VERSION_STRING                 = 1.0

  ENTRY_POINT                    = TimerInitialize

EFI_STATUS
EFIAPI
TimerInitialize (
  IN EFI_HANDLE         ImageHandle,
  IN EFI_SYSTEM_TABLE   *SystemTable
  )
{
  EFI_HANDLE  Handle = NULL;
  EFI_STATUS  Status;
  UINT32      TimerBaseAddress;

  // Find the interrupt controller protocol.  ASSERT if not found.
  Status = gBS->LocateProtocol (&gHardwareInterruptProtocolGuid, NULL, (VOID **)&gInterrupt);
  ASSERT_EFI_ERROR (Status);

  // Set up the timer registers
  TimerBaseAddress = TimerBase (FixedPcdGet32(PcdOmap35xxArchTimer));
  TISR = TimerBaseAddress + GPTIMER_TISR;
  TCLR = TimerBaseAddress + GPTIMER_TCLR;
  TLDR = TimerBaseAddress + GPTIMER_TLDR;
  TCRR = TimerBaseAddress + GPTIMER_TCRR;
  TIER = TimerBaseAddress + GPTIMER_TIER;

  // Disable the timer
  Status = TimerDriverSetTimerPeriod (&gTimer, 0);
  ASSERT_EFI_ERROR (Status);

  // Install interrupt handler
  gVector = InterruptVectorForTimer (FixedPcdGet32(PcdOmap35xxArchTimer));
  Status = gInterrupt->RegisterInterruptSource (gInterrupt, gVector, TimerInterruptHandler);
  ASSERT_EFI_ERROR (Status);

  // Turn on the functional clock for Timer
  MmioOr32 (CM_FCLKEN_PER, CM_FCLKEN_PER_EN_GPT3_ENABLE);

  // Set up default timer
  Status = TimerDriverSetTimerPeriod (&gTimer, FixedPcdGet32(PcdTimerPeriod));
  ASSERT_EFI_ERROR (Status);

  // Install the Timer Architectural Protocol onto a new handle
  Status = gBS->InstallMultipleProtocolInterfaces (
                  &Handle,
                  &gEfiTimerArchProtocolGuid,      &gTimer,
                  NULL
                  );
  ASSERT_EFI_ERROR(Status);

  return Status;
}
在TimerInitialize 中首先通过LocateProtocol 找到gInterrupt的protocol,这样就可以通过gInterrupt来注册中断
从FixedPcd 中读到timer 寄存器的base address,然后分别得到控制timer的5个寄存器的地址.
  // Set up the timer registers
  TimerBaseAddress = TimerBase (FixedPcdGet32(PcdOmap35xxArchTimer));
  TISR = TimerBaseAddress + GPTIMER_TISR;
  TCLR = TimerBaseAddress + GPTIMER_TCLR;
  TLDR = TimerBaseAddress + GPTIMER_TLDR;
  TCRR = TimerBaseAddress + GPTIMER_TCRR;
  TIER = TimerBaseAddress + GPTIMER_TIER;

  关掉timer
  Status = TimerDriverSetTimerPeriod (&gTimer, 0);
  ASSERT_EFI_ERROR (Status);
EFI_STATUS
EFIAPI
TimerDriverSetTimerPeriod (
  IN EFI_TIMER_ARCH_PROTOCOL  *This,
  IN UINT64                   TimerPeriod
  )
{
  EFI_STATUS  Status;
  UINT64      TimerCount;
  INT32       LoadValue;

  if (TimerPeriod == 0) {
    // Turn off GPTIMER3
    MmioWrite32 (TCLR, TCLR_ST_OFF);

    Status = gInterrupt->DisableInterruptSource(gInterrupt, gVector);
  } else {
    // Calculate required timer count
    TimerCount = DivU64x32(TimerPeriod * 100, PcdGet32(PcdEmbeddedPerformanceCounterPeriodInNanoseconds));

    // Set GPTIMER3 Load register
    LoadValue = (INT32) -TimerCount;
    MmioWrite32 (TLDR, LoadValue);
    MmioWrite32 (TCRR, LoadValue);

    // Enable Overflow interrupt
    MmioWrite32 (TIER, TIER_TCAR_IT_DISABLE | TIER_OVF_IT_ENABLE | TIER_MAT_IT_DISABLE);

    // Turn on GPTIMER3, it will reload at overflow
    MmioWrite32 (TCLR, TCLR_AR_AUTORELOAD | TCLR_ST_ON);

    Status = gInterrupt->EnableInterruptSource(gInterrupt, gVector);
  }

  //
  // Save the new timer period
  //
  mTimerPeriod = TimerPeriod;
  return Status;
}
如果参数是0的话
    MmioWrite32 (TCLR, TCLR_ST_OFF);

    Status = gInterrupt->DisableInterruptSource(gInterrupt, gVector);
直接通过gInterrupt 关掉中断.
回到TimerInitialize 中,继续通过gInterrupt的RegisterInterruptSource 来注册gVector的中断处理函数TimerInterruptHandler
  // Install interrupt handler
  gVector = InterruptVectorForTimer (FixedPcdGet32(PcdOmap35xxArchTimer));
  Status = gInterrupt->RegisterInterruptSource (gInterrupt, gVector, TimerInterruptHandler);
  ASSERT_EFI_ERROR (Status);
然后再次调用TimerDriverSetTimerPeriod打开中断
  // Set up default timer
  Status = TimerDriverSetTimerPeriod (&gTimer, FixedPcdGet32(PcdTimerPeriod));
  ASSERT_EFI_ERROR (Status);
在TimerDriverSetTimerPeriod 函数中参数这次不为0,是从FixedPcdGet32(PcdTimerPeriod) 读到的
    TimerCount = DivU64x32(TimerPeriod * 100, PcdGet32(PcdEmbeddedPerformanceCounterPeriodInNanoseconds));

    // Set GPTIMER3 Load register
    LoadValue = (INT32) -TimerCount;
    MmioWrite32 (TLDR, LoadValue);
    MmioWrite32 (TCRR, LoadValue);

    // Enable Overflow interrupt
    MmioWrite32 (TIER, TIER_TCAR_IT_DISABLE | TIER_OVF_IT_ENABLE | TIER_MAT_IT_DISABLE);

    // Turn on GPTIMER3, it will reload at overflow
    MmioWrite32 (TCLR, TCLR_AR_AUTORELOAD | TCLR_ST_ON);

    Status = gInterrupt->EnableInterruptSource(gInterrupt, gVector);
计算TimerCount。设定寄存器后,最终通过EnableInterruptSource 重新使能中断.
最终在TimerInitialize中调用InstallMultipleProtocolInterfaces 来安装gTimer
  // Install the Timer Architectural Protocol onto a new handle
  Status = gBS->InstallMultipleProtocolInterfaces (
                  &Handle,
                  &gEfiTimerArchProtocolGuid,      &gTimer,
                  NULL
                  );


这样别的程序就可以通过gEfiTimerArchProtocolGuid 得到gTimer,从而调用gTimer的四个函数。
EFI_TIMER_ARCH_PROTOCOL   gTimer = {
  TimerDriverRegisterHandler,
  TimerDriverSetTimerPeriod,
  TimerDriverGetTimerPeriod,
  TimerDriverGenerateSoftInterrupt
};
先看第一个函数,由于uefi中只support 时间中断,因此会在TimerDriverRegisterHandler 中调用mTimerNotifyFunction 来通知其他函数已经产生中断了
TimerDriverGetTimerPeriod (
  IN EFI_TIMER_ARCH_PROTOCOL   *This,
  OUT UINT64                   *TimerPeriod
  )
{
  if (TimerPeriod == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  *TimerPeriod = mTimerPeriod;
  return EFI_SUCCESS;
}
TimerDriverGetTimerPeriod 仅仅返回中断的周期mTimerPeriod,这个mTimerPeriod 我们是在TimerDriverSetTimerPeriod 中设定的
TimerDriverGenerateSoftInterrupt (
  IN EFI_TIMER_ARCH_PROTOCOL  *This
  )
{
  return EFI_UNSUPPORTED;
}
TimerDriverGenerateSoftInterrupt 是空函数,说明不支持软件中断.


0 0
原创粉丝点击