文章目录
初识CSDN
本人小白一枚,最近在看Rtc管理这一块,也是第一次写博客,请多多指教哦~
下面以MIPS平台的龙芯3A4000为例,以及掌握的固件为例进行梳理.
自我认识的Rtc时钟
关于这一章后期会补上.
剖析代码
InitializePcRtc 这个函数是PcRtc module的入口点函数.
首先介绍下Rtc上电初始化的代码:
EFI_STATUS
PcRtcInit (
IN PC_RTC_MODULE_GLOBALS *Global
)
{
EFI_STATUS Status;
EFI_TIME Time;
UINTN DataSize;
UINT32 year, month, date, hour, min, sec;
LS7A_TOY_REG0 RTC_READ0;
//
// Acquire RTC Lock to make access to RTC atomic
//
if (!EfiAtRuntime ()) {
EfiAcquireLock (&Global->RtcLock);
}
outl(LS7A_RTC_CTRL_REG, LS7A_RTC_CTRL_INIT_DATA);//Enable Rtc
outl(LS7A_TOY_TRIM_REG, 0);//0x20
outl(LS7A_RTC_TRIM_REG, 0);//0x60 must init 0
RTC_READ0.Data = inl (LS7A_TOY_READ0_REG);
year = inl(LS7A_TOY_READ1_REG);
month = RTC_READ0.Bits.TOY_MONTH;
date = RTC_READ0.Bits.TOY_DAY;
hour = RTC_READ0.Bits.TOY_HOUR;
min = RTC_READ0.Bits.TOY_MIN;
sec = RTC_READ0.Bits.TOY_SEC;
//init read reg
if ((year < 0 || year > 16383)
__|| (month < 1 || month > 12)
__|| (date < 1 || date > 31)
__|| (hour > 23) || (min > 59)
__|| (sec > 59)) {
/* 2000-01-01 00:00:00 */
RTC_READ0.Bits.TOY_MONTH = 1;
RTC_READ0.Bits.TOY_DAY = 1;
outl(LS7A_TOY_WRITE1_REG, 0x64);
outl(LS7A_TOY_WRITE0_REG, RTC_READ0.Data);
}//if it is error ,reset Rtc reg.
//
// Get the Time/Date/Daylight Savings values.
//
RTC_READ0.Data = inl (LS7A_TOY_READ0_REG);
year = (inl(LS7A_TOY_READ1_REG) & 0x3fff) + 1900;
month = RTC_READ0.Bits.TOY_MONTH;
date = RTC_READ0.Bits.TOY_DAY;
hour = RTC_READ0.Bits.TOY_HOUR;
min = RTC_READ0.Bits.TOY_MIN;
sec = RTC_READ0.Bits.TOY_SEC;
Time.Second = sec;
Time.Minute = min;
Time.Hour = hour;
Time.Day = date;
Time.Month = month;
Time.Year = year;
//
// Release RTC Lock.
//
if (!EfiAtRuntime ()) {
EfiReleaseLock (&Global->RtcLock);
}
//
// Get the data of Daylight saving and time zone, if they have been
// stored in NV variable during previous boot.
//
DataSize = sizeof (UINT32);
Status = EfiGetVariable (
L"RTC",
&gEfiCallerIdGuid,
NULL,
&DataSize,
(VOID *) &RTC_READ0.Data
);
if (!EFI_ERROR (Status)) {
Time.TimeZone = (INT16) RTC_READ0.Data;
Time.Daylight = (UINT8) (RTC_READ0.Data >> 16);
} else {
Time.TimeZone = EFI_UNSPECIFIED_TIMEZONE;
Time.Daylight = 0;
}
//
// Reset time value according to new RTC configuration
//
#ifndef LS7A1000
Status = PcRtcSetTime (&Time, Global);
#else
/*
* If PcRtcSetTime is called at this time on the Ls7A1000 platform, the RTC time will be
* faster than real time. So now call the NULL funciton to fix it, but this bug needs to
* find real results in the future.
*/
Status = NullFunction (&Time, Global);// TODO
#endif
if(!EFI_ERROR (Status)) {
return EFI_SUCCESS;
} else {
return EFI_DEVICE_ERROR;
}
}
EFI_STATUS
EFIAPI
InitializePcRtc (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EfiInitializeLock (&mModuleGlobal.RtcLock, TPL_HIGH_LEVEL);
Status = PcRtcInit (&mModuleGlobal);
// if (EFI_ERROR (Status)) {
// return Status;
// }
gRT->GetTime = PcRtcEfiGetTime;
gRT->SetTime = PcRtcEfiSetTime;
gRT->GetWakeupTime = PcRtcEfiGetWakeupTime;
gRT->SetWakeupTime = PcRtcEfiSetWakeupTime;
Status = gBS->InstallMultipleProtocolInterfaces (
&mHandle,
&gEfiRealTimeClockArchProtocolGuid,
NULL,
NULL
);
ASSERT_EFI_ERROR (Status);
return Status;
}
这个函数安装了UEFI的 Runtime Service中的GetTime(),SetTime(),GetWakeupTime(),and SetWakeupTime().
gRT里定义的函数point 对应的CPU时钟寄存器的读写操作.
先来熟悉一下四个接口函数吧,关于Lock的操作后续再补.
typedef struct {
EFI_LOCK RtcLock;
INT16 SavedTimeZone;
UINT8 Daylight;
} PC_RTC_MODULE_GLOBALS;
EFI_STATUS
PcRtcGetTime (
OUT EFI_TIME *Time,
OUT EFI_TIME_CAPABILITIES *Capabilities, OPTIONAL
IN PC_RTC_MODULE_GLOBALS *Global
)
{
ZeroMem(Time,sizeof(EFI_TIME));
LS7A_TOY_REG0 RTC_READ0;
// UINT32 Val;
//
// Check parameters for null pointer
//
if (Time == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Acquire RTC Lock to make access to RTC atomic
//
if (!EfiAtRuntime ()) {
EfiAcquireLock (&Global->RtcLock);
}
RTC_READ0.Data = inl (LS7A_TOY_READ0_REG);
/* Val = RTC_READ0.Data;
Time->Second = (Val >> TOY_SEC_SHIFT) & TOY_SEC_MASK;
Time->Minute = (Val >> TOY_MIN_SHIFT) & TOY_MIN_MASK;
Time->Hour = (Val >> TOY_HOUR_SHIFT) & TOY_HOUR_MASK;
Time->Day = (Val >> TOY_DAY_SHIFT) & TOY_DAY_MASK;
Time->Month = ((Val >> TOY_MON_SHIFT) & TOY_MON_MASK);
Time->Year = ((inl(LS7A_TOY_READ1_REG) & 0x3fff) + 1900);
*/
Time->Second = RTC_READ0.Bits.TOY_SEC;
Time->Minute = RTC_READ0.Bits.TOY_MIN;
Time->Hour = RTC_READ0.Bits.TOY_HOUR;
Time->Day = RTC_READ0.Bits.TOY_DAY;
Time->Month = RTC_READ0.Bits.TOY_MONTH;
Time->Year = (inl(LS7A_TOY_READ1_REG) + 1900);
//
// Release RTC Lock.
//
if (!EfiAtRuntime ()) {
EfiReleaseLock (&Global->RtcLock);
}
//
// Get the variable that contains the TimeZone and Daylight fields
//
Time->TimeZone = Global->SavedTimeZone;
Time->Daylight = Global->Daylight;
return EFI_SUCCESS;
}
首先先从Rtc寄存器offset 0x2c内读取32Bit数据存储到LS7A_TOY_REG.类型如下:
typedef union {
struct {
__ UINT32 TOY_MILLISEC_:4;
__ UINT32 TOY_SEC__:6;
__ UINT32 TOY_MIN__:6;
__ UINT32 TOY_HOUR_:5;
__ UINT32 TOY_DAY__:5;
__ UINT32 TOY_MONTH__:6;
}Bits;
UINT32 Data;
}LS7A_TOY_REG0 //这是一个联合类型 指保存桥片的Rtc寄存器内的数值
其实这个联合已经定义好了哪些位存取的哪些数据,很好的可以解析出来,如何以后抽象寄存器,你也可以按这种方式抽象.
三