在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 是空函数,说明不支持软件中断.
从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 是空函数,说明不支持软件中断.