From b7c51c9cf4864df6aabb99a1ae843becd577237c Mon Sep 17 00:00:00 2001 From: raywu Date: Fri, 15 Jun 2018 00:00:50 +0800 Subject: init. 1AQQW051 --- Chipset/SB/SBRun.c | 1144 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1144 insertions(+) create mode 100644 Chipset/SB/SBRun.c (limited to 'Chipset/SB/SBRun.c') diff --git a/Chipset/SB/SBRun.c b/Chipset/SB/SBRun.c new file mode 100644 index 0000000..a5f9430 --- /dev/null +++ b/Chipset/SB/SBRun.c @@ -0,0 +1,1144 @@ +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* + +//************************************************************************* +// $Header: /Alaska/Projects/Intel/Haswell/LynxPoint_SharkBay-DT_Crb_1AQQW/Chipset/SB/SBRun.c 1 4/19/16 7:42a Chienhsieh $ +// +// $Revision: 1 $ +// +// $Date: 4/19/16 7:42a $ +//************************************************************************* +// Revision History +// ---------------- +// $Log: /Alaska/Projects/Intel/Haswell/LynxPoint_SharkBay-DT_Crb_1AQQW/Chipset/SB/SBRun.c $ +// +// 1 4/19/16 7:42a Chienhsieh +// +// 5 7/17/13 1:54a Scottyang +// [TAG] EIP128233 +// [Category] Improvement +// [Description] Improving UEFI PXE image downloading proformance. +// [Files] RTC.h +// SBRun.c +// +// 4 3/19/13 8:24a Scottyang +// [TAG] EIP106509 +// [Category] Improvement +// [Description] 3. Improve the Intel UEFI GbE driver performance in +// IPv4 connection. +// [Files] SBRun.c +// +// 3 1/27/13 11:01p Scottyang +// [TAG] None +// [Category] Improvement +// [Description] Capsule 2.0 crash dump link function. +// [Files] SBPEI.c +// SBDxe.c +// SBRun.c +// +// 2 12/20/12 9:59p Scottyang +// [TAG] EIP77459 +// [Category] Improvement +// [Description] Update for Intel flash utility "FPT.efi" support. +// [Files] SBRun.c +// +// 1 2/08/12 8:24a Yurenlai +// Intel Lynx Point/SB eChipset initially releases. +// +//************************************************************************* +// +// +// Name: SBRUN.C +// +// Description: This file contains code for general Southbridge runtime +// protocol +// +// +//************************************************************************* + +//--------------------------------------------------------------------------- +// Include(s) +//--------------------------------------------------------------------------- + +#include +#include +#include +#include +#include +#include "RTC.h" + +// Produced Protocols +#include +#include +#include +#include + +//--------------------------------------------------------------------------- +// Constant, Macro and Type Definition(s) +//--------------------------------------------------------------------------- +// Constant Definition(s) + +// Macro Definition(s) + +// Type Definition(s) + +// Function Prototype(s) + +EFI_STATUS WaitForTick ( + IN EFI_METRONOME_ARCH_PROTOCOL *This, + IN UINT32 TickNumber +); + +//--------------------------------------------------------------------------- +// Variable and External Declaration(s) +//--------------------------------------------------------------------------- +// Variable Declaration(s) + +EFI_HANDLE mResetProtocolHandle = NULL; +static BOOLEAN gTimeOut = FALSE; + // [EIP77459]> +UINT16 gTimeZone; +UINT8 gDaylight; + // <[EIP77459] + +EFI_RESET_SYSTEM gCallSavedIntelPointer; + +// This the number of days in a month - 1. (0 Based) +UINT8 DaysInMonth[] = { 30, 27, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30 }; + // (EIP128233)>> +#pragma pack(push, 1) +typedef struct { + INT16 TimeZone; + UINT8 Daylight; + } TIME_VARIABLE; +#pragma pack(pop) + +static TIME_VARIABLE CachedTimeVariable; +static BOOLEAN CachedTimeVariableValid = FALSE; + // <<(EIP128233) +// GUID Definition(s) + +EFI_GUID gEfiMetronomeArchProtocolGuid = EFI_METRONOME_ARCH_PROTOCOL_GUID; +EFI_GUID guidReset = EFI_RESET_ARCH_PROTOCOL_GUID; +EFI_GUID gEfiRtcArchProtocolGuid = EFI_REAL_TIME_CLOCK_ARCH_PROTOCOL_GUID; +EFI_GUID gEfiTimeVariableGuid = EFI_TIME_VARIABLE_GUID; + +// Protocol Definition(s) + +EFI_METRONOME_ARCH_PROTOCOL mMetronomeProtocol = { + WaitForTick, + 1 +}; + +// External Declaration(s) + +// Function Definition(s) + +//--------------------------------------------------------------------------- + +// +//---------------------------------------------------------------------------- +// +// Procedure: EfiResetSystem +// +// Description: This function is the interface for the reset function. +// In the future, this may allow for a shared library for DXE +// and PEI. +// +// Input: ResetType - Type of reset to perform +// ResetStatus - System status that caused the reset. if part +// of normal operation then this should be +// EFI_SUCCESS, Otherwise it should reflect the +// state of the system that caused it +// DataSize - Size in bytes of the data to be logged +// *ResetData - Pointer to the data buffer that is to be +// logged +// +// Output: None, Even though it should never get that far +//---------------------------------------------------------------------------- +// + +EFI_STATUS EfiResetSystem ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN CHAR16 *ResetData OPTIONAL +) +{ + // Add logging messages here + // do a cold reset of the system + if (ResetType == EfiResetWarm) + { + SBLib_ResetSystem (ResetType); + } + else + { + if (gCallSavedIntelPointer == NULL) + SBLib_ResetSystem (ResetType); + + gCallSavedIntelPointer( ResetType, \ + ResetStatus, \ + DataSize, \ + ResetData ); + } + + // This should not get here + return EFI_SUCCESS; +} + +// +//---------------------------------------------------------------------------- +// +// Procedure: WaitForTick +// +// Description: This function calculates the time needed to delay and then +// calls a library function to delay that amount of time +// +// Input: *This - Pointer to the instance of the Metronome Arch +// Protocol +// TickNumber - Number of ticks needed based off of tick period +// defined in Protocol Definiton +// +// Output: Return Status based on errors that occurred while waiting for +// time to expire. +//---------------------------------------------------------------------------- +// + +EFI_STATUS WaitForTick ( + IN EFI_METRONOME_ARCH_PROTOCOL *This, + IN UINT32 TickNumber ) +{ + EFI_STATUS Status; + UINT32 TotalTime; + + // Manipulate TickNumber into a valid value for the library function call + // the Current Resolution is 10us. + // The Library uses Microseconds to count delayed time. + TotalTime = (TickNumber * This->TickPeriod) / 10; + + // Make Library Function call here + Status = CountTime( TotalTime, PM_BASE_ADDRESS ); + + return Status; +} + +// +//---------------------------------------------------------------------------- +// +// Procedure: DecToBCD +// +// Description: This function converts data from DEC to BCD format +// +// Input: UINT8 Dec - Value to be converted +// +// Output: UINT8 - Result of conversion +//---------------------------------------------------------------------------- +// + +UINT8 DecToBCD ( + IN UINT8 Dec ) +{ + UINT8 FirstDigit = Dec % 10; + UINT8 SecondDigit = Dec / 10; + + // Only for 2 digit BCD. + return (SecondDigit << 4) + FirstDigit; +} + +// +//---------------------------------------------------------------------------- +// +// Procedure: BCDToDec +// +// Description: This function converts data from BCD to DEC format +// +// Input: UINT8 Bcd - Value to be converted +// +// Output: UINT8 - Result of conversion +//---------------------------------------------------------------------------- +// + +UINT8 BCDToDec ( + IN UINT8 Bcd ) +{ + UINT8 FirstDigit = Bcd & 0xf; + UINT8 SecondDigit = Bcd >> 4;; + + // Only for 2 digit BCD. + return SecondDigit * 10 + FirstDigit; +} + +// +//---------------------------------------------------------------------------- +// +// Procedure: ReadRtcIndex +// +// Description: Read the RTC value at the given Index. +// +// Input: Index - RTC Index +// +// Output: RTC Value read from the provided Index +// +// Notes: Here is the control flow of this function: +// 1. Read port 0x70 (RTC Index Register) to get bit 7. +// Bit 7 is the NMI bit-it should not be changed. +// 2. Set Index with the NMI bit setting. +// 3. Output 0x70 with the Index and NMI bit setting. +// 4. Read 0x71 for Data. Getting Dec when appropriate. +// 5. Return the Data. +//---------------------------------------------------------------------------- +// + +UINT8 ReadRtcIndex ( + IN UINT8 Index ) +{ + volatile UINT8 Value; + BOOLEAN IntState = CPULib_GetInterruptState(); + + CPULib_DisableInterrupt(); + + IoWrite8(CMOS_IO_INDEX_BACKDOOR, Index); + Value = IoRead8(CMOS_IO_DATA_BACKDOOR); // Read register. + + if (IntState) CPULib_EnableInterrupt(); + + if ((Index <= RTC_YEAR_REG) || (Index == ACPI_CENTURY_CMOS)) + Value = BCDToDec(Value); + + return (UINT8)Value; +} + +// +//---------------------------------------------------------------------------- +// +// Procedure: WriteRtcIndex +// +// Description: Write the RTC value at the given Index. +// +// Input: Index - RTC Index +// Value - Value to write +// +// Output: None +// +// Notes: Here is the control flow of this function: +// 1. Read port 0x70 (RTC Index Register) to get bit 7. +// Bit 7 is the NMI bit-it should not be changed. +// 2. Set Index with the NMI bit setting. +// 3. Output 0x70 with the Index. Switch to BCD when needed. +// 4. Write the data to 0x71. +//---------------------------------------------------------------------------- +// + +VOID WriteRtcIndex ( + IN UINT8 Index, + IN UINT8 Value ) +{ + BOOLEAN IntState = CPULib_GetInterruptState(); + + if ((Index <= RTC_YEAR_REG) || (Index == ACPI_CENTURY_CMOS)) + Value = DecToBCD(Value); + + CPULib_DisableInterrupt(); + + IoWrite8(CMOS_IO_INDEX_BACKDOOR, Index); + IoWrite8(CMOS_IO_DATA_BACKDOOR, Value); // Write Register. + + if (IntState) CPULib_EnableInterrupt(); + +} + +// +//---------------------------------------------------------------------------- +// +// Procedure: InitRtc +// +// Description: This function initializes RTC +// +// Input: None +// +// Output: None +//---------------------------------------------------------------------------- +// + +VOID InitRtc (VOID) +{ + WriteRtcIndex(RTC_REG_B_INDEX, 0x82); + WriteRtcIndex(RTC_REG_A_INDEX, 0x26); + ReadRtcIndex(RTC_REG_C_INDEX); + ReadRtcIndex(RTC_REG_D_INDEX); + WriteRtcIndex(RTC_REG_B_INDEX, 0x02); +} + +// +//---------------------------------------------------------------------------- +// Procedure: SetUpdate +// +// Description: Enables Disables RTC Date and Time update cicles. +// +// Input: Enable - TRUE or FALSE to Enable\Disabe RTC Update. +// +// Output: None +//---------------------------------------------------------------------------- +// + +VOID SetUpdate ( + IN BOOLEAN Enable ) +{ + RTC_REG_B RegB; + UINT8 Set = (Enable) ? 0 : 1; + + RegB.REG_B = ReadRtcIndex(RTC_REG_B_INDEX); + if (RegB.Set != Set) { + RegB.Set = Set; + WriteRtcIndex(RTC_REG_B_INDEX, RegB.REG_B); + } +} + +// +//---------------------------------------------------------------------------- +// Procedure: CheckUpdateCmplete +// +// Description: Check if RTC Date and Time update in progress and waits till +// it's over. +// +// Input: None +// +// Output: None +//---------------------------------------------------------------------------- +// + +VOID CheckUpdateCmplete (VOID) +{ + volatile RTC_REG_A RegA; + UINTN TimeOut = 0; + + RegA.REG_A = ReadRtcIndex(RTC_REG_A_INDEX); + while (RegA.UpdInProgr) { + RegA.REG_A = ReadRtcIndex(RTC_REG_A_INDEX); + TimeOut++; + if (TimeOut >= 0x0fffff) { + gTimeOut = TRUE; + return; + } + } + + gTimeOut = FALSE; +} + +BOOLEAN IsLeapYear ( + IN EFI_TIME *Time ) +{ + if (Time->Year % 4 == 0) { + if (Time->Year % 100 == 0) { + if (Time->Year % 400 == 0) { + return TRUE; + } else { + return FALSE; + } + } else { + return TRUE; + } + } else { + return FALSE; + } +} + +// +//---------------------------------------------------------------------------- +// +// Procedure: VerifyTime +// +// Description: This routine verifies if time and data if needed, before +// setting the RTC +// +// Input: *Time - Time to verify with +// +// Output: TRUE if valid time and date +// +// Notes: Here is the control flow of this function: +// 1. Decrease month and date to change to 0-base +// 2. Validate Year, Month and Day. If invalid, return FALSE. +// 3. Validate Hour, Minute and Second. If invalid, return FALSE. +// 4. Return True. +//---------------------------------------------------------------------------- +// + +BOOLEAN VerifyTime ( + IN EFI_TIME *Time ) +{ + // Always check these to satisfy EFI compliancy test even for setting + // wake-up time. + UINT8 Month = Time->Month - 1; + UINT8 Day = Time->Day - 1; + + if ((Time->Year < EARLIEST_YEAR) || (Time->Year > 9999)) return FALSE; + if (Month > 11) return FALSE; // 0 based month + if ((Month != 1) || (!IsLeapYear(Time))) { // Not leap year or not February. + // All values already adjusted for 0 based. + if (Day > DaysInMonth[Month]) return FALSE; + } else { + if (Day > 28) return FALSE; // February + } + + if (Time->Hour > 23) return FALSE; + if (Time->Minute > 59) return FALSE; + if (Time->Second > 59) return FALSE; + + // Check these to satisfy EFI compliancy test. + if (Time->Nanosecond > 999999999) return FALSE; // 999,999,999 + if (Time->TimeZone < -1440) return FALSE; + if (Time->TimeZone > 1440 && Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE) + return FALSE; + + return TRUE; +} + +// +//---------------------------------------------------------------------------- +// +// Procedure: GetDayOfTheWeek +// +// Description: Returns an index that represents the day of the week of the +// date passed in +// +// Input: *Time - Pointer to EFI_TIME structure +// +// Output: Returns the index to the day of the week. 0 = Sunday, +// 1 = Monday ... 6 = Saturday +//---------------------------------------------------------------------------- +// + +UINT8 GetDayOfTheWeek ( + IN EFI_TIME *Time ) +{ + UINT16 a; + UINT16 m; + UINT16 d; + UINT16 y; + + a = (14 - Time->Month) / 12; + y = Time->Year - a; + m = Time->Month + 12 * a - 2; + d = (Time->Day + y + y / 4 - y / 100 + y / 400 + (31 * m) / 12) % 7; + + return (UINT8)d; +} + + +// +//---------------------------------------------------------------------------- +// Procedure: CheckRtc +// +// Description: Check if RTC Mode and Format have appropriate values and sets +// them if necessary +// +// Input: Set - if true, force Rtc to 24 hour mode and binary format. +// +// Output: EFI_STATUS +// EFI_SUCCESS - RTC mode and format have appropriate values. +// EFI_DEVICE_ERROR - RTC mode and/or format are invalid. +//---------------------------------------------------------------------------- +// +EFI_STATUS CheckRtc ( + IN BOOLEAN Set ) +{ + RTC_REG_B RegB; + + // Check RTC Conditions and stuff + RegB.REG_B = ReadRtcIndex(RTC_REG_B_INDEX); + if((RegB.Mode == 0) || (RegB.Format == 1)) { + if (Set) { + RegB.Mode = 1; // 1 - 24 hour mode + RegB.Format = 0; // 0 - BCD Format + WriteRtcIndex(RTC_REG_B_INDEX, RegB.REG_B); + } else { + return EFI_DEVICE_ERROR; + } + } + + return EFI_SUCCESS; +} + +// +//---------------------------------------------------------------------------- +// +// Procedure: EfiGetTime +// +// Description: Return the current date and time +// +// Input: *Time - Current time filled in EFI_TIME structure +// *Capabilities - Time capabilities (OPTIONAL) +// +// Output: EFI_SUCCESS +// EFI_INVALID_PARAMETER - A NULL Time. +// EFI_DEVICE_ERROR - RTC mode and/or format are invalid +// EFI_SUCCESS - Read the current date and time successfully. +// +// +// Notes: Here is the control flow of this function: +// 1. Read the original time format 12/24 hours and BCD/binary. +// 2. Set the format to 24 hrs and binary. +// 3. Read the 2 digit year. +// 4. Add either 1900 or 2000, so the year is between 1998 - 2097 +// 5. Read the month, day, hour, minute, second. +// 6. Set the nanosecond to 0. +// 7. Set the time to zone to unspecified. +// 8. Set daylight savings value to 0. +// 9. Restore the original time format. +// 10.Set Capabilities with 1 sec Resolution, 0 Accuracy +// (Unknown), and False SetsToZero. +// 11.Return EFI_SUCCESS. +//---------------------------------------------------------------------------- +// + +EFI_STATUS EfiGetTime ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL ) +{ + EFI_STATUS Status; + UINT8 Year; + BOOLEAN IntState; + BOOLEAN SmiState; + UINTN TimeVarSize = sizeof(TIME_VARIABLE); + UINT8 Buffer8; // [EIP77459] + + if (Time == NULL) return EFI_INVALID_PARAMETER; + + // Check RTC Conditions (24h Mode and BCD is ON) + Status = CheckRtc(FALSE); + if (EFI_ERROR(Status)) return Status; + + // Get SMI State and disable it + SmiState = SbLib_GetSmiState(); + SbLib_SmiDisable(); + // Get INTERRUPT State and disable it + IntState = CPULib_GetInterruptState(); + CPULib_DisableInterrupt(); + + // Wait till RTC is safe to read, + CheckUpdateCmplete(); + if (gTimeOut) InitRtc(); + + // After control comes back, we will have 488 u's to read data. + Year = ReadRtcIndex(RTC_YEAR_REG); + Time->Month = ReadRtcIndex(RTC_MONTH_REG); + Time->Day = ReadRtcIndex(RTC_DAY_OF_MONTH_REG); + Time->Hour = ReadRtcIndex(RTC_HOURS_REG); + Time->Minute = ReadRtcIndex(RTC_MINUTES_REG); + Time->Second = ReadRtcIndex(RTC_SECONDS_REG); + + // Restore SMIs and INTERRUPT State + if(IntState) CPULib_EnableInterrupt(); + if(SmiState) SbLib_SmiEnable(); + + // This Register is not affected by UIP bit so read it very last. + // If RTC Year only 1 digit, EFI spec says years rang is 1998 - 2097 + Time->Year = ReadRtcIndex(ACPI_CENTURY_CMOS) * 100 + Year; + + Time->Nanosecond= 0; + + // [EIP77459]> + // Save BIOSWE bit (B0:D31:F0 Reg#DCh[0]) + Buffer8 = READ_PCI8_SB(SB_REG_BIOS_CNTL); + // (EIP128233)>> + if(CachedTimeVariableValid && (Buffer8 & BIT00) != 0) { + Time->TimeZone = CachedTimeVariable.TimeZone; + Time->Daylight = CachedTimeVariable.Daylight; + } else { + Status = pRS->GetVariable( L"EfiTime", \ + &gEfiTimeVariableGuid, \ + NULL, \ + &TimeVarSize, \ + &CachedTimeVariable ); + if (EFI_ERROR(Status)) { + CachedTimeVariable.TimeZone = EFI_UNSPECIFIED_TIMEZONE; + CachedTimeVariable.Daylight = 0; + } + + Time->TimeZone = CachedTimeVariable.TimeZone; + Time->Daylight = CachedTimeVariable.Daylight; + CachedTimeVariableValid = TRUE; + } + + // Restore BIOSWE bit (B0:D31:F0 Reg#DCh[0]) + WRITE_PCI8_SB(SB_REG_BIOS_CNTL, Buffer8); + // <[EIP77459] + // <<(EIP128233) + if (Capabilities != NULL) { + Capabilities->Resolution = 1; + Capabilities->Accuracy = 0; + Capabilities->SetsToZero = 0; + } + + return EFI_SUCCESS; +} + +// +//---------------------------------------------------------------------------- +// +// Procedure: EfiSetTime +// +// Description: Sets the RTC time +// +// Input: *Time - Time to set +// +// Output: EFI_STATUS +// EFI_SUCCESS - Time is Set +// EFI_INVALID_PARAMETER - Time to Set is not valid. +// +// Notes: Here is the control flow of this function: +// 1. Read the original time format 12/24 hours and BCD/binary. +// 2. Set the format to 24 hrs and binary. +// 3. Verify the time to set. If it is an invalid time, +// restore the time format and return EFI_INVALID_PARAMETER. +// 4. Change the 4 digit year to a 2 digit year. +// 5. Stop the RTC time. +// 6. Store time and data on the RTC. +// 7. Read the month, day, hour, minute, second. +// 8. Start the RTC time. +// 9. Restore the original time format. +// 10.Return EFI_SUCCESS. +//---------------------------------------------------------------------------- +// + +EFI_STATUS EfiSetTime ( + IN EFI_TIME *Time ) +{ + + EFI_STATUS Status = EFI_SUCCESS; + UINTN TimeVarSize = sizeof(TIME_VARIABLE); + + // Check RTC Conditions and stuff + CheckRtc(TRUE); + + if (Time == NULL) return EFI_INVALID_PARAMETER; + if (!VerifyTime(Time)) return EFI_INVALID_PARAMETER; + + SetUpdate(FALSE); + WriteRtcIndex(ACPI_CENTURY_CMOS, Time->Year / 100); + WriteRtcIndex(RTC_YEAR_REG, Time->Year % 100); + WriteRtcIndex(RTC_MONTH_REG, Time->Month); + WriteRtcIndex(RTC_DAY_OF_MONTH_REG, Time->Day); + WriteRtcIndex(RTC_DAY_OF_WEEK_REG, GetDayOfTheWeek(Time) + 1); + + WriteRtcIndex(RTC_HOURS_REG, Time->Hour); + WriteRtcIndex(RTC_MINUTES_REG, Time->Minute); + WriteRtcIndex(RTC_SECONDS_REG, Time->Second); + SetUpdate(TRUE); + + // (EIP128233)>> + if(CachedTimeVariableValid && + CachedTimeVariable.TimeZone == Time->TimeZone && + CachedTimeVariable.Daylight == Time->Daylight) + return EFI_SUCCESS; + + CachedTimeVariable.TimeZone = Time->TimeZone; + CachedTimeVariable.Daylight = Time->Daylight; + + Status = pRS->SetVariable( + L"EfiTime", + &gEfiTimeVariableGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(TIME_VARIABLE), + &CachedTimeVariable + ); + if(!EFI_ERROR(Status)) + CachedTimeVariableValid = TRUE; + // <<(EIP128233) + return Status; +} + +// +//---------------------------------------------------------------------------- +// +// Procedure: EfiGetWakeupTime +// +// Description: Read the wake time. Read the status if it is enabled or +// if the system has woken up. +// +// Input: *Enabled - Flag indicating the validity of wakeup time +// *Pending - Check if wake up time has expired. +// *Time - Current wake up time setting +// +// Output: EF_STATUS +// EFI_SUCCESS - Read the wake time successfully. +// EFI_INVALID_PARAMETER - Invalid input parameters +// EFI_DEVICE_ERROR - RTC mode and/or format are invalid +// +// Notes: Here is the control flow of this function: +// 1. Read the original time format 12/24 hours and BCD/binary. +// 2. Set the format to 24 hrs and binary. +// 3. Read the status if the wake up time is enabled or if it has expired. +// 4. Set the wakeup time. +// 5. Restore the original time format. +// 6. Return EFI_SUCCESS. +//---------------------------------------------------------------------------- +// + +EFI_STATUS EfiGetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time ) +{ + EFI_STATUS Status; + BOOLEAN IntState; + BOOLEAN SmiState; + RTC_REG_B RegB; + RTC_REG_C RegC; +#if ACPI_ALARM_DAY_CMOS + RTC_DATE_ALARM_REG RegDateAlarm; +#endif +#if ACPI_ALARM_MONTH_CMOS + RTC_MONTH_ALARM_REG RegMonthAlarm; +#endif + + if (!Enabled || !Pending || !Time) return EFI_INVALID_PARAMETER; + + // Check RTC Conditions (24h Mode and BCD is ON) + Status = CheckRtc(FALSE); + if (EFI_ERROR(Status)) return Status; + + // Get SMI State and disable it + SmiState = SbLib_GetSmiState(); + SbLib_SmiDisable(); + // Get INTERRUPT State and disable it + IntState = CPULib_GetInterruptState(); + CPULib_DisableInterrupt(); + + // Wait till RTC is safe to read, + CheckUpdateCmplete(); + if (gTimeOut) InitRtc(); + + Time->Hour = ReadRtcIndex(RTC_HOURS_ALARM_REG); + Time->Minute = ReadRtcIndex(RTC_MINUTES_ALARM_REG); + Time->Second = ReadRtcIndex(RTC_SECONDS_ALARM_REG); + + // Restore SMIs and INTERRUPT State + if (IntState) CPULib_EnableInterrupt(); + if (SmiState) SbLib_SmiEnable(); + +#if ACPI_ALARM_DAY_CMOS + RegDateAlarm.REG_DATE_ALARM = ReadRtcIndex(ACPI_ALARM_DAY_CMOS); + Time->Day = BCDToDec(RegDateAlarm.DateAlarm); +#else + Time->Day = 0; +#endif + +#if ACPI_ALARM_MONTH_CMOS + RegMonthAlarm.REG_MONTH_ALARM = ReadRtcIndex(ACPI_ALARM_MONTH_CMOS); + Time->Month = BCDToDec(RegMonthAlarm.MonthAlarm); +#else + Time->Month = 0; +#endif + + RegB.REG_B = ReadRtcIndex(RTC_REG_B_INDEX); + RegC.REG_C = ReadRtcIndex(RTC_REG_C_INDEX); + + + *Enabled = (RegB.AlarmInt == 1) ? TRUE : FALSE; + *Pending = (RegC.AlarmFlag == 1) ? TRUE : FALSE; + + return EFI_SUCCESS; +} + +// +//---------------------------------------------------------------------------- +// +// Procedure: EfiSetWakeupTime +// +// Description: Enable/disable and set wakeup time +// +// Input: Enable - Flag indicating whether to enable/disble the time +// *Time - Time to set +// +// Output: EFI_STATUS +// EFI_SUCCESS - Wakeup time is Set and/or Enabled/Disabled. +// EFI_DEVICE_ERROR - RTC mode and/or format are invalid +// EFI_INVALID_PARAMETER - Invalid time or enabling with a +// NULL Time. +// +// Notes: Here is the control flow of this function: +// 1. Read the original time format 12/24 hours and BCD/binary. +// 2. If Time is not NULL, +// a. Verify the wakeup time to set. If it is an invalid +// time, restore the time format and +// return EFI_INVALID_PARAMETER. +// b. Set the wakeup time. +// 3. If Time is NULL and Enable is true, restore original +// time format and return EFI_INVALID_PARAMETER. +// 4. Enable/Disable wakeup. +// 5. Restore the original time format. +// 6. Return EFI_SUCCESS. +//---------------------------------------------------------------------------- +// + +EFI_STATUS EfiSetWakeupTime ( + IN BOOLEAN Enable, + IN EFI_TIME *Time OPTIONAL ) +{ + + EFI_STATUS Status; + RTC_REG_B RegB; + RTC_REG_C RegC; +#if ACPI_ALARM_DAY_CMOS + RTC_DATE_ALARM_REG RegDateAlarm; +#endif +#if ACPI_ALARM_MONTH_CMOS + RTC_MONTH_ALARM_REG RegMonthAlarm; +#endif + + // Check RTC Conditions (24h Mode and BCD is ON) + Status = CheckRtc(FALSE); + if(EFI_ERROR(Status)) return Status; + + if (Time != NULL) { + if (!VerifyTime(Time)) return EFI_INVALID_PARAMETER; + } else { + if (Enable) return EFI_INVALID_PARAMETER; + } + + RegB.REG_B = ReadRtcIndex(RTC_REG_B_INDEX); + + SetUpdate(FALSE); + if (Time != NULL) { + WriteRtcIndex(RTC_HOURS_ALARM_REG, Time->Hour); + WriteRtcIndex(RTC_MINUTES_ALARM_REG, Time->Minute); + WriteRtcIndex(RTC_SECONDS_ALARM_REG, Time->Second); +#if ACPI_ALARM_DAY_CMOS + // Day == 0 means don't care + RegDateAlarm.DateAlarm = DecToBCD(Time->Day); + WriteRtcIndex(ACPI_ALARM_DAY_CMOS, RegDateAlarm.REG_DATE_ALARM); +#endif +#if ACPI_ALARM_MONTH_CMOS + // Month == 0 means don't care + RegMonthAlarm.MonthAlarm = DecToBCD(Time->Month); + WriteRtcIndex(ACPI_ALARM_MONTH_CMOS, RegMonthAlarm.REG_MONTH_ALARM); +#endif + } + + // Clear Alarm Flag + RegC.REG_C = ReadRtcIndex(RTC_REG_C_INDEX); + + // Set Enable/Disable + RegB.AlarmInt = (Enable) ? 1 : 0; + WriteRtcIndex(RTC_REG_B_INDEX, RegB.REG_B); + + SetUpdate(TRUE); + + return EFI_SUCCESS; +} + +// +//---------------------------------------------------------------------------- +// +// Procedure: SaveIntelResetPointer +// +// Description: +// +// Input: Event - Event of callback +// Context - Context of callback. +// +// Output: None +//---------------------------------------------------------------------------- +// + +VOID SaveIntelResetPointer ( + IN EFI_EVENT Event, + IN VOID *Context ) +{ + gCallSavedIntelPointer = pRS->ResetSystem; + pRS->ResetSystem = EfiResetSystem; + + pBS->CloseEvent(Event); +} + +// +//---------------------------------------------------------------------------- +// +// Procedure: SBRun_Init +// +// Description: This function is the entry point for this DXE. This function +// installs the runtime services related to SB +// +// Input: ImageHandle - Image handle +// SystemTable - Pointer to the system table +// +// Output: EFI_STATUS +// EFI_SUCCESS - All the protocol interfaces were installed. +// EFI_ALREADY_STARTED - A Device Path instance was passed +// in that is already present in the +// handle database. +// EFI_OUT_OF_RESOURCES - There was not enough memory in +// pool to install all the protocols. +//---------------------------------------------------------------------------- +// + +EFI_STATUS SBRun_Init ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable ) +{ + EFI_STATUS Status = EFI_SUCCESS; + EFI_TIME Time; + EFI_TIME NewTime; + EFI_HANDLE Handle = NULL; + UINT8 PM2 = READ_PCI8_SB(SB_REG_GEN_PMCON_2); + UINT8 PM3 = READ_PCI8_SB(SB_REG_GEN_PMCON_3); + RTC_REG_D RegD; + BOOLEAN RtcLostPower = FALSE; + + InitAmiRuntimeLib(ImageHandle, SystemTable, NULL, NULL); + + PROGRESS_CODE(DXE_SBRUN_INIT); + + // CspLib PM Specific function to check and Report + // CMOS Battary and Power Supply Power loss/failure + CspLibCheckPowerLoss(); + + if(PM3 & BIT02) { + // Clear RTC_PWR_STS. + PM3 &= ~BIT02; + RtcLostPower = TRUE; + } + //Write back Cleared Statuses + WRITE_PCI8_SB(SB_REG_GEN_PMCON_2, PM2); + WRITE_PCI8_SB(SB_REG_GEN_PMCON_3, PM3); + + RegD.REG_D = ReadRtcIndex(RTC_REG_D_INDEX); + if (RegD.DataValid == 0) + RtcLostPower = TRUE; + + if (RtcLostPower) { + ERROR_CODE(DXE_SB_BAD_BATTERY, EFI_ERROR_MAJOR); + InitRtc(); + } + + + // MakeSure Mode, Format and REG_A is OK + CheckRtc(TRUE); + + Status = EfiGetTime(&Time, NULL); + if (EFI_ERROR(Status) || !VerifyTime(&Time)) { + ERROR_CODE(GENERIC_BAD_DATE_TIME_ERROR, EFI_ERROR_MINOR); + + TRACE((TRACE_ALWAYS, "\n\nTime: %d/%d/%d %d:%d:%d\n", + Time.Month, + Time.Day, + Time.Year, + Time.Hour, + Time.Minute, + Time.Second + )); + + TRACE((TRACE_ALWAYS, "Nanosecond: %d TimeZone: %d\n\n\n", + Time.Nanosecond, + Time.TimeZone + )); + + // if Time is invalid the battery probably has been removed + // Let's setup RTC_REG_A just in case... + WriteRtcIndex(RTC_REG_A_INDEX, 0x26); + + // Check to see what part of EFI_TIME was wrong. + // reset unrelated to RTC fields. + Time.TimeZone = EFI_UNSPECIFIED_TIMEZONE; + Time.Daylight = 0; + Time.Nanosecond = 0; + + NewTime = Time; + + NewTime.Hour = 0; + NewTime.Minute = 0; + NewTime.Second = 0; + + if (VerifyTime(&NewTime)) { + // if we here that means Time was wrong + Time.Hour = 0; + Time.Minute = 0; + Time.Second = 0; + } else { + // if we here that means Date was wrong + Time.Month = DEFAULT_MONTH; + Time.Day = DEFAULT_DAY; + Time.Year = DEFAULT_YEAR; + } + + // Here is the situation when both Time and Date is Incorrect. + if (!VerifyTime(&Time)) { + Time.Hour = 0; + Time.Minute = 0; + Time.Second = 0; + Time.Month=DEFAULT_MONTH; + Time.Day=DEFAULT_DAY; + Time.Year=DEFAULT_YEAR; + } + + TRACE((TRACE_ALWAYS, "Reseting Date and Time to: %d/%d/%d %d:%d:%d\n", + Time.Month, + Time.Day, + Time.Year, + Time.Hour, + Time.Minute, + Time.Second + )); + EfiSetTime(&Time); + } + + // Install runtime services + pRS->ResetSystem = EfiResetSystem; + + gCallSavedIntelPointer = NULL; + + pRS->GetTime = EfiGetTime; + pRS->SetTime = EfiSetTime; + pRS->GetWakeupTime = EfiGetWakeupTime; + pRS->SetWakeupTime = EfiSetWakeupTime; + + Status = pBS->InstallProtocolInterface( &ImageHandle, \ + &gEfiMetronomeArchProtocolGuid, \ + EFI_NATIVE_INTERFACE, \ + &mMetronomeProtocol ); + ASSERT_EFI_ERROR(Status); +{ + EFI_EVENT Event = NULL; + VOID *Registration = NULL; + + Status = RegisterProtocolCallback( &gEfiResetArchProtocolGuid,\ + SaveIntelResetPointer,\ + NULL,\ + &Event,\ + &Registration ); + ASSERT_EFI_ERROR(Status); +} + + // This protocol is to notify core that the Runtime Table has been + // updated, so it can update the runtime table CRC. + return pBS->InstallMultipleProtocolInterfaces( &Handle, \ + &gEfiRtcArchProtocolGuid, \ + NULL, \ + NULL ); +} + +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* -- cgit v1.2.3