EFI_STATUS RtcWaitToUpdate ( UINTN Timeout ) { RTC_REGISTER_A RegisterA; RTC_REGISTER_D RegisterD; // // See if the RTC is functioning correctly // RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D); if (RegisterD.Bits.VRT == 0) { return EFI_DEVICE_ERROR; } // // Wait for up to 0.1 seconds for the RTC to be ready. // Timeout = (Timeout / 10) + 1; RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A); while (RegisterA.Bits.UIP == 1 && Timeout > 0) { MicroSecondDelay (10); RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A); Timeout--; } RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D); if (Timeout == 0 || RegisterD.Bits.VRT == 0) { return EFI_DEVICE_ERROR; } return EFI_SUCCESS; }
EFI_STATUS RtcTestCenturyRegister ( VOID ) { UINT8 Century; UINT8 Temp; Century = RtcRead (RTC_ADDRESS_CENTURY); // // RtcWrite (RTC_ADDRESS_CENTURY, 0x00); // Temp = (UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f); RtcWrite (RTC_ADDRESS_CENTURY, Century); if (Temp == 0x19 || Temp == 0x20) { return EFI_SUCCESS; } return EFI_DEVICE_ERROR; }
// return the calendar time, seconds since the Epoch (Jan 1 1970 00:00:00) time_t time(time_t *timeptr) { struct tm now; time_t t=(time_t) -1; if (RtcRead(&now)) { t=mktime(&now); } if (timeptr) { *timeptr=t; } return t; }
VOID LibRtcInitialize ( VOID ) { EFI_STATUS Status; RTC_REGISTER_A RegisterA; RTC_REGISTER_B RegisterB; RTC_REGISTER_C RegisterC; RTC_REGISTER_D RegisterD; UINT8 Century; EFI_TIME Time; // // Acquire RTC Lock to make access to RTC atomic // EfiAcquireLock (&mRtc.RtcLock); // // Initialize RTC Register // // Make sure Division Chain is properly configured, // or RTC clock won't "tick" -- time won't increment // RegisterA.Data = RTC_INIT_REGISTER_A; RtcWrite (RTC_ADDRESS_REGISTER_A, RegisterA.Data); // // Read Register B // RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B); // // Clear RTC flag register // RegisterC.Data = RtcRead (RTC_ADDRESS_REGISTER_C); // // Clear RTC register D // RegisterD.Data = RTC_INIT_REGISTER_D; RtcWrite (RTC_ADDRESS_REGISTER_D, RegisterD.Data); // // Wait for up to 0.1 seconds for the RTC to be updated // Status = RtcWaitToUpdate (100000); if (EFI_ERROR (Status)) { EfiReleaseLock (&mRtc.RtcLock); return; } // // Get the Time/Date/Daylight Savings values. // Time.Second = RtcRead (RTC_ADDRESS_SECONDS); Time.Minute = RtcRead (RTC_ADDRESS_MINUTES); Time.Hour = RtcRead (RTC_ADDRESS_HOURS); Time.Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH); Time.Month = RtcRead (RTC_ADDRESS_MONTH); Time.Year = RtcRead (RTC_ADDRESS_YEAR); ConvertRtcTimeToEfiTime (&Time, RegisterB); if (RtcTestCenturyRegister () == EFI_SUCCESS) { Century = BcdToDecimal ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f)); } else { Century = BcdToDecimal (RtcRead (RTC_ADDRESS_CENTURY)); } Time.Year = (UINT16) (Century * 100 + Time.Year); // // Set RTC configuration after get original time // RtcWrite (RTC_ADDRESS_REGISTER_B, RTC_INIT_REGISTER_B); // // Release RTC Lock. // EfiReleaseLock (&mRtc.RtcLock); // // Validate time fields // Status = RtcTimeFieldsValid (&Time); if (EFI_ERROR (Status)) { Time.Second = RTC_INIT_SECOND; Time.Minute = RTC_INIT_MINUTE; Time.Hour = RTC_INIT_HOUR; Time.Day = RTC_INIT_DAY; Time.Month = RTC_INIT_MONTH; Time.Year = RTC_INIT_YEAR; } // // Reset time value according to new RTC configuration // LibSetTime (&Time); return; }
EFI_STATUS LibSetWakeupTime ( IN BOOLEAN Enabled, OUT EFI_TIME *Time ) { EFI_STATUS Status; EFI_TIME RtcTime; RTC_REGISTER_B RegisterB; UINT8 Century; EFI_TIME_CAPABILITIES Capabilities; if (Enabled) { if (Time == NULL) { return EFI_INVALID_PARAMETER; } // // Make sure that the time fields are valid // Status = RtcTimeFieldsValid (Time); if (EFI_ERROR (Status)) { return EFI_INVALID_PARAMETER; } // // Just support set alarm time within 24 hours // LibGetTime (&RtcTime, &Capabilities); if (Time->Year != RtcTime.Year || Time->Month != RtcTime.Month || (Time->Day != RtcTime.Day && Time->Day != (RtcTime.Day + 1)) ) { return EFI_UNSUPPORTED; } // // Make a local copy of the time and date // CopyMem (&RtcTime, Time, sizeof (EFI_TIME)); } // // Acquire RTC Lock to make access to RTC atomic // EfiAcquireLock (&mRtc.RtcLock); // // Wait for up to 0.1 seconds for the RTC to be updated // Status = RtcWaitToUpdate (100000); if (EFI_ERROR (Status)) { EfiReleaseLock (&mRtc.RtcLock); return EFI_DEVICE_ERROR; } // // Read Register B, and inhibit updates of the RTC // RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B); RegisterB.Bits.SET = 1; RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data); if (Enabled) { ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century); // // Set RTC alarm time // RtcWrite (RTC_ADDRESS_SECONDS_ALARM, RtcTime.Second); RtcWrite (RTC_ADDRESS_MINUTES_ALARM, RtcTime.Minute); RtcWrite (RTC_ADDRESS_HOURS_ALARM, RtcTime.Hour); RegisterB.Bits.AIE = 1; } else { RegisterB.Bits.AIE = 0; } // // Allow updates of the RTC registers // RegisterB.Bits.SET = 0; RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data); // // Release RTC Lock. // EfiReleaseLock (&mRtc.RtcLock); return EFI_SUCCESS; }
EFI_STATUS libGetWakeupTime ( OUT BOOLEAN *Enabled, OUT BOOLEAN *Pending, OUT EFI_TIME *Time ) { EFI_STATUS Status; RTC_REGISTER_B RegisterB; RTC_REGISTER_C RegisterC; UINT8 Century; // // Check paramters for null pointers // if ((Enabled == NULL) || (Pending == NULL) || (Time == NULL)) { return EFI_INVALID_PARAMETER; } // // Acquire RTC Lock to make access to RTC atomic // EfiAcquireLock (&mRtc.RtcLock); // // Wait for up to 0.1 seconds for the RTC to be updated // Status = RtcWaitToUpdate (100000); if (EFI_ERROR (Status)) { EfiReleaseLock (&mRtc.RtcLock); return EFI_DEVICE_ERROR; } // // Read Register B and Register C // RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B); RegisterC.Data = RtcRead (RTC_ADDRESS_REGISTER_C); // // Get the Time/Date/Daylight Savings values. // *Enabled = RegisterB.Bits.AIE; if (*Enabled) { Time->Second = RtcRead (RTC_ADDRESS_SECONDS_ALARM); Time->Minute = RtcRead (RTC_ADDRESS_MINUTES_ALARM); Time->Hour = RtcRead (RTC_ADDRESS_HOURS_ALARM); Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH); Time->Month = RtcRead (RTC_ADDRESS_MONTH); Time->Year = RtcRead (RTC_ADDRESS_YEAR); } else { Time->Second = 0; Time->Minute = 0; Time->Hour = 0; Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH); Time->Month = RtcRead (RTC_ADDRESS_MONTH); Time->Year = RtcRead (RTC_ADDRESS_YEAR); } ConvertRtcTimeToEfiTime (Time, RegisterB); if (RtcTestCenturyRegister () == EFI_SUCCESS) { Century = BcdToDecimal ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f)); } else { Century = BcdToDecimal (RtcRead (RTC_ADDRESS_CENTURY)); } Time->Year = (UINT16) (Century * 100 + Time->Year); // // Release RTC Lock. // EfiReleaseLock (&mRtc.RtcLock); // // Make sure all field values are in correct range // Status = RtcTimeFieldsValid (Time); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } *Pending = RegisterC.Bits.AF; return EFI_SUCCESS; }
EFI_STATUS LibSetTime ( IN EFI_TIME *Time ) { EFI_STATUS Status; EFI_TIME RtcTime; RTC_REGISTER_B RegisterB; UINT8 Century; if (Time == NULL) { return EFI_INVALID_PARAMETER; } // // Make sure that the time fields are valid // Status = RtcTimeFieldsValid (Time); if (EFI_ERROR (Status)) { return Status; } CopyMem (&RtcTime, Time, sizeof (EFI_TIME)); // // Acquire RTC Lock to make access to RTC atomic // EfiAcquireLock (&mRtc.RtcLock); // // Wait for up to 0.1 seconds for the RTC to be updated // Status = RtcWaitToUpdate (100000); if (EFI_ERROR (Status)) { EfiReleaseLock (&mRtc.RtcLock); return Status; } // // Read Register B, and inhibit updates of the RTC // RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B); RegisterB.Bits.SET = 1; RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data); ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century); RtcWrite (RTC_ADDRESS_SECONDS, RtcTime.Second); RtcWrite (RTC_ADDRESS_MINUTES, RtcTime.Minute); RtcWrite (RTC_ADDRESS_HOURS, RtcTime.Hour); RtcWrite (RTC_ADDRESS_DAY_OF_THE_MONTH, RtcTime.Day); RtcWrite (RTC_ADDRESS_MONTH, RtcTime.Month); RtcWrite (RTC_ADDRESS_YEAR, (UINT8) RtcTime.Year); if (RtcTestCenturyRegister () == EFI_SUCCESS) { Century = (UINT8) ((Century & 0x7f) | (RtcRead (RTC_ADDRESS_CENTURY) & 0x80)); } RtcWrite (RTC_ADDRESS_CENTURY, Century); // // Allow updates of the RTC registers // RegisterB.Bits.SET = 0; RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data); // // Release RTC Lock. // EfiReleaseLock (&mRtc.RtcLock); // // Set the variable that containts the TimeZone and Daylight fields // mRtc.SavedTimeZone = Time->TimeZone; mRtc.Daylight = Time->Daylight; return Status; }
EFI_STATUS LibGetTime ( OUT EFI_TIME *Time, OUT EFI_TIME_CAPABILITIES *Capabilities ) { EFI_STATUS Status; RTC_REGISTER_B RegisterB; UINT8 Century; UINTN BufferSize; // // Check parameters for null pointer // if (Time == NULL) { return EFI_INVALID_PARAMETER; } // // Acquire RTC Lock to make access to RTC atomic // EfiAcquireLock (&mRtc.RtcLock); // // Wait for up to 0.1 seconds for the RTC to be updated // Status = RtcWaitToUpdate (100000); if (EFI_ERROR (Status)) { EfiReleaseLock (&mRtc.RtcLock); return Status; } // // Read Register B // RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B); // // Get the Time/Date/Daylight Savings values. // Time->Second = RtcRead (RTC_ADDRESS_SECONDS); Time->Minute = RtcRead (RTC_ADDRESS_MINUTES); Time->Hour = RtcRead (RTC_ADDRESS_HOURS); Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH); Time->Month = RtcRead (RTC_ADDRESS_MONTH); Time->Year = RtcRead (RTC_ADDRESS_YEAR); ConvertRtcTimeToEfiTime (Time, RegisterB); if (RtcTestCenturyRegister () == EFI_SUCCESS) { Century = BcdToDecimal ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f)); } else { Century = BcdToDecimal (RtcRead (RTC_ADDRESS_CENTURY)); } Time->Year = (UINT16) (Century * 100 + Time->Year); // // Release RTC Lock. // EfiReleaseLock (&mRtc.RtcLock); // // Get the variable that containts the TimeZone and Daylight fields // Time->TimeZone = mRtc.SavedTimeZone; Time->Daylight = mRtc.Daylight; BufferSize = sizeof (INT16) + sizeof (UINT8); // // Make sure all field values are in correct range // Status = RtcTimeFieldsValid (Time); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } // // Fill in Capabilities if it was passed in // if (Capabilities) { Capabilities->Resolution = 1; // // 1 hertz // Capabilities->Accuracy = 50000000; // // 50 ppm // Capabilities->SetsToZero = FALSE; } return EFI_SUCCESS; }