gTimer protocol的实现

    xiaoxiao2021-03-25  112

    在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 是空函数,说明不支持软件中断.
    转载请注明原文地址: https://ju.6miu.com/read-22849.html

    最新回复(0)