/** Initialize the state information for the Timer Architectural Protocol and the Timer Debug support protocol that allows the debugger to break into a running program. @param ImageHandle of the loaded driver @param SystemTable Pointer to the System Table @retval EFI_SUCCESS Protocol registered @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure @retval EFI_DEVICE_ERROR Hardware problems **/ EFI_STATUS EFIAPI TimerInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_HANDLE Handle = NULL; EFI_STATUS Status; UINTN TimerCtrlReg; if (ArmIsArchTimerImplemented () == 0) { DEBUG ((EFI_D_ERROR, "ARM Architectural Timer is not available in the CPU, hence cann't use this Driver \n")); ASSERT (0); } // Find the interrupt controller protocol. ASSERT if not found. Status = gBS->LocateProtocol (&gHardwareInterruptProtocolGuid, NULL, (VOID **)&gInterrupt); ASSERT_EFI_ERROR (Status); // Disable the timer TimerCtrlReg = ArmArchTimerGetTimerCtrlReg (); TimerCtrlReg |= ARM_ARCH_TIMER_IMASK; TimerCtrlReg &= ~ARM_ARCH_TIMER_ENABLE; ArmArchTimerSetTimerCtrlReg (TimerCtrlReg); Status = TimerDriverSetTimerPeriod (&gTimer, 0); ASSERT_EFI_ERROR (Status); // Install secure and Non-secure interrupt handlers // Note: Because it is not possible to determine the security state of the // CPU dynamically, we just install interrupt handler for both sec and non-sec // timer PPI Status = gInterrupt->RegisterInterruptSource (gInterrupt, PcdGet32 (PcdArmArchTimerSecIntrNum), TimerInterruptHandler); ASSERT_EFI_ERROR (Status); Status = gInterrupt->RegisterInterruptSource (gInterrupt, PcdGet32 (PcdArmArchTimerIntrNum), TimerInterruptHandler); ASSERT_EFI_ERROR (Status); // Set up default timer Status = TimerDriverSetTimerPeriod (&gTimer, FixedPcdGet32(PcdTimerPeriod)); // TIMER_DEFAULT_PERIOD ASSERT_EFI_ERROR (Status); // Install the Timer Architectural Protocol onto a new handle Status = gBS->InstallMultipleProtocolInterfaces( &Handle, &gEfiTimerArchProtocolGuid, &gTimer, NULL ); ASSERT_EFI_ERROR(Status); // Everything is ready, unmask and enable timer interrupts TimerCtrlReg = ARM_ARCH_TIMER_ENABLE; ArmArchTimerSetTimerCtrlReg (TimerCtrlReg); // Register for an ExitBootServicesEvent Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent); ASSERT_EFI_ERROR (Status); return Status; }
RETURN_STATUS EFIAPI TimerConstructor ( VOID ) { // Check if the ARM Generic Timer Extension is implemented if (ArmIsArchTimerImplemented ()) { UINTN TimerFreq; // Check if Architectural Timer frequency is valid number (should not be 0) ASSERT (PcdGet32 (PcdArmArchTimerFreqInHz)); // Check if ticks/uS is not 0. The Architectural timer runs at constant // frequency irrespective of CPU frequency. According to General Timer Ref // manual lower bound of the frequency is in the range of 1-10MHz ASSERT (TICKS_PER_MICRO_SEC); #ifdef MDE_CPU_ARM // Only set the frequency for ARMv7. We expect the secure firmware to have already do it // If the security extensions are not implemented set Timer Frequency if ((ArmReadIdPfr1 () & ARM_PFR1_SEC) == 0x0) { ArmArchTimerSetTimerFreq (PcdGet32 (PcdArmArchTimerFreqInHz)); } #endif // Architectural Timer Frequency must be set in the Secure privileged(if secure extensions are supported) mode. // If the reset value (0) is returned just ASSERT. TimerFreq = ArmArchTimerGetTimerFreq (); ASSERT (TimerFreq != 0); } else { DEBUG ((EFI_D_ERROR, "ARM Architectural Timer is not available in the CPU, hence this library can not be used.\n")); ASSERT (0); } return RETURN_SUCCESS; }
VOID EFIAPI ArmArchTimerWriteReg ( IN ARM_ARCH_TIMER_REGS Reg, IN VOID *SrcBuf ) { // Check if the Generic/Architecture timer is implemented if (ArmIsArchTimerImplemented ()) { switch (Reg) { case CntFrq: ArmWriteCntFrq (*((UINTN *)SrcBuf)); break; case CntPct: DEBUG ((EFI_D_ERROR, "Can't write to Read Only Register: CNTPCT \n")); break; case CntkCtl: ArmWriteCntkCtl (*((UINTN *)SrcBuf)); break; case CntpTval: ArmWriteCntpTval (*((UINTN *)SrcBuf)); break; case CntpCtl: ArmWriteCntpCtl (*((UINTN *)SrcBuf)); break; case CntvTval: ArmWriteCntvTval (*((UINTN *)SrcBuf)); break; case CntvCtl: ArmWriteCntvCtl (*((UINTN *)SrcBuf)); break; case CntvCt: DEBUG ((EFI_D_ERROR, "Can't write to Read Only Register: CNTVCT \n")); break; case CntpCval: ArmWriteCntpCval (*((UINT64 *)SrcBuf) ); break; case CntvCval: ArmWriteCntvCval (*((UINT64 *)SrcBuf) ); break; case CntvOff: ArmWriteCntvOff (*((UINT64 *)SrcBuf)); break; case CnthCtl: case CnthpTval: case CnthpCtl: case CnthpCval: DEBUG ((EFI_D_ERROR, "The register is related to Hypervisor Mode. Can't perform requested operation\n ")); break; default: DEBUG ((EFI_D_ERROR, "Unknown ARM Generic Timer register %x. \n ", Reg)); } } else { DEBUG ((EFI_D_ERROR, "Attempt to write to ARM Generic Timer registers. But ARM Generic Timer extension is not implemented \n ")); ASSERT (0); } }
VOID EFIAPI ArmArchTimerReadReg ( IN ARM_ARCH_TIMER_REGS Reg, OUT VOID *DstBuf ) { // Check if the Generic/Architecture timer is implemented if (ArmIsArchTimerImplemented ()) { switch (Reg) { case CntFrq: *((UINTN *)DstBuf) = ArmReadCntFrq (); return; case CntPct: *((UINT64 *)DstBuf) = ArmReadCntPct (); return; case CntkCtl: *((UINTN *)DstBuf) = ArmReadCntkCtl(); return; case CntpTval: *((UINTN *)DstBuf) = ArmReadCntpTval (); return; case CntpCtl: *((UINTN *)DstBuf) = ArmReadCntpCtl (); return; case CntvTval: *((UINTN *)DstBuf) = ArmReadCntvTval (); return; case CntvCtl: *((UINTN *)DstBuf) = ArmReadCntvCtl (); return; case CntvCt: *((UINT64 *)DstBuf) = ArmReadCntvCt (); return; case CntpCval: *((UINT64 *)DstBuf) = ArmReadCntpCval (); return; case CntvCval: *((UINT64 *)DstBuf) = ArmReadCntvCval (); return; case CntvOff: *((UINT64 *)DstBuf) = ArmReadCntvOff (); return; case CnthCtl: case CnthpTval: case CnthpCtl: case CnthpCval: DEBUG ((EFI_D_ERROR, "The register is related to Hypervisor Mode. Can't perform requested operation\n ")); break; default: DEBUG ((EFI_D_ERROR, "Unknown ARM Generic Timer register %x. \n ", Reg)); } } else { DEBUG ((EFI_D_ERROR, "Attempt to read ARM Generic Timer registers. But ARM Generic Timer extension is not implemented \n ")); ASSERT (0); } *((UINT64 *)DstBuf) = 0; }