summaryrefslogtreecommitdiff
path: root/ReferenceCode/Chipset/LynxPoint/Reset/RuntimeDxe/PchReset.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Chipset/LynxPoint/Reset/RuntimeDxe/PchReset.c')
-rw-r--r--ReferenceCode/Chipset/LynxPoint/Reset/RuntimeDxe/PchReset.c496
1 files changed, 496 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/LynxPoint/Reset/RuntimeDxe/PchReset.c b/ReferenceCode/Chipset/LynxPoint/Reset/RuntimeDxe/PchReset.c
new file mode 100644
index 0000000..8f4b925
--- /dev/null
+++ b/ReferenceCode/Chipset/LynxPoint/Reset/RuntimeDxe/PchReset.c
@@ -0,0 +1,496 @@
+/** @file
+ PCH RESET Runtime Driver
+
+@copyright
+ Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved
+ This software and associated documentation (if any) is furnished
+ under a license and may only be used or copied in accordance
+ with the terms of the license. Except as permitted by such
+ license, no part of this software or documentation may be
+ reproduced, stored in a retrieval system, or transmitted in any
+ form or by any means without the express written consent of
+ Intel Corporation.
+
+ This file contains an 'Intel Peripheral Driver' and uniquely
+ identified as "Intel Reference Module" and is
+ licensed for Intel CPUs and chipsets under the terms of your
+ license agreement with Intel or your vendor. This file may
+ be modified by the user, subject to additional terms of the
+ license agreement
+
+**/
+#include "PchReset.h"
+
+PCH_RESET_INSTANCE *mPchResetInstance;
+
+STATIC UINT8 mDaysOfMonthInfo[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+/**
+ Check if it is leap year
+
+ @param[in] Year year to be check
+
+ @retval True year is leap year
+ @retval FALSE year is not a leap year
+**/
+BOOLEAN
+IsLeapYear (
+ IN UINT16 Year
+ )
+{
+ return (Year % 4 == 0) && ((Year % 100 != 0) || (Year % 400 == 0));
+}
+
+/**
+ Set System Wakeup Alarm.
+
+ @param[in] WakeAfter Time offset in seconds to wake from S3
+
+ @retval EFI_SUCCESS Timer started successfully
+**/
+
+STATIC
+EFI_STATUS
+SetSystemWakeupAlarm (
+ IN UINT32 WakeAfter
+ )
+{
+ EFI_STATUS Status;
+ EFI_TIME Time;
+ EFI_TIME_CAPABILITIES Capabilities;
+ UINT32 Reminder;
+ UINT16 PmBase;
+ UINT8 DayOfMonth;
+ ///
+ /// For an instant wake 2 seconds is a safe value
+ ///
+ if (WakeAfter < 2) {
+ WakeAfter = 2;
+ }
+
+ Status = EfiGetTime (&Time, &Capabilities);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Reminder = WakeAfter + (UINT32) Time.Second;
+ Time.Second = Reminder % 60;
+ Reminder = Reminder / 60;
+ Reminder = Reminder + (UINT32) Time.Minute;
+ Time.Minute = Reminder % 60;
+ Reminder = Reminder / 60;
+ Reminder = Reminder + (UINT32) Time.Hour;
+ Time.Hour = Reminder % 24;
+ Reminder = Reminder / 24;
+
+ if (Reminder > 0) {
+ Reminder = Reminder + (UINT32) Time.Day;
+ if ((Time.Month == 2) && IsLeapYear (Time.Year)) {
+ DayOfMonth = 29;
+ } else {
+ DayOfMonth = mDaysOfMonthInfo[Time.Month - 1];
+ }
+ if (Reminder > DayOfMonth) {
+ Time.Day = (UINT8)Reminder - DayOfMonth;
+ Reminder = 1;
+ } else {
+ Time.Day = (UINT8)Reminder;
+ Reminder = 0;
+ }
+ }
+
+ if (Reminder > 0) {
+ if (Time.Month == 12) {
+ Time.Month = 1;
+ Time.Year = Time.Year + 1;
+ } else {
+ Time.Month = Time.Month + 1;
+ }
+ }
+
+ Status = EfiSetWakeupTime (TRUE, &Time);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PmBase = (UINT16) (PciRead32 (
+ PCI_LIB_ADDRESS (DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ R_PCH_LPC_ACPI_BASE)
+ ) & B_PCH_LPC_ACPI_BASE_BAR);
+
+ ///
+ /// Clear RTC PM1 status
+ ///
+ IoWrite16 (PmBase + R_PCH_ACPI_PM1_STS, B_PCH_ACPI_PM1_STS_RTC);
+
+ ///
+ /// set RTC_EN bit in PM1_EN to wake up from the alarm
+ ///
+ IoWrite16 (
+ PmBase + R_PCH_ACPI_PM1_EN,
+ (IoRead16 (PmBase + R_PCH_ACPI_PM1_EN) | B_PCH_ACPI_PM1_EN_RTC)
+ );
+ return Status;
+}
+
+// AMI_OVERRIDE, [EIP111666] >>>
+EFI_GUID gPchGetResetTypeGuid = PCH_RESET_PROTOCOL_GUID;
+
+EFI_STATUS
+EFIAPI
+PchResetExitBootServicesEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+/*++
+
+Routine Description:
+
+ PCH initialization before ExitBootServices / LegacyBoot events
+ Useful for operations which must happen later than at EndOfPost event
+
+Arguments:
+
+ Event A pointer to the Event that triggered the callback.
+ Context A pointer to private data registered with the callback function.
+
+Returns:
+
+ EFI_SUCCESS The function completed successfully
+
+ --*/
+{
+ //
+ // Closed the event to avoid call twice
+ //
+ UINT8 LegacyBoot;
+ gBS->CloseEvent (Event);
+
+ gRT->SetVariable (
+ L"InLegacyBoot",
+ &gPchGetResetTypeGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof(UINT8),
+ &LegacyBoot
+ );
+ return EFI_SUCCESS;
+}
+// AMI_OVERRIDE, [EIP111666] <<<
+
+/**
+ Initialize the state information for the Timer Architectural Protocol
+
+ @param[in] ImageHandle Image handle of the loaded driver
+ @param[in] SystemTable Pointer to the System Table
+
+ @retval EFI_SUCCESS Thread can be successfully created
+ @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
+ @retval EFI_DEVICE_ERROR Cannot create the timer service
+**/
+EFI_STATUS
+EFIAPI
+InstallPchReset (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Length;
+// AMI_OVERRIDE, NBDXE.c already done. >>>
+/* UINT64 BaseAddress;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemorySpaceDescriptor;
+ UINT64 Attributes;*/
+// AMI_OVERRIDE, NBDXE.c already done. <<<
+// AMI_OVERRIDE, [EIP111666] >>>
+ EFI_EVENT LegacyBootEvent;
+// AMI_OVERRIDE, [EIP111666] <<<
+
+ DEBUG ((EFI_D_INFO, "InstallPchReset() Start\n"));
+
+ Status = PciLibConstructor ();
+ ASSERT_EFI_ERROR (Status);
+// AMI_OVERRIDE, NBDXE.c already done. >>>
+/*
+ BaseAddress = MmPciAddress(0,
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ 0
+ );
+ Length = 4096;
+
+ Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &MemorySpaceDescriptor);
+ ASSERT_EFI_ERROR (Status);
+
+ Attributes = MemorySpaceDescriptor.Attributes | EFI_MEMORY_RUNTIME;
+
+ Status = gDS->SetMemorySpaceAttributes (
+ BaseAddress,
+ Length,
+ Attributes
+ );
+ DEBUG ((EFI_D_INFO, "Status = %r\n",Status));
+ ASSERT_EFI_ERROR (Status);*/
+// AMI_OVERRIDE, NBDXE.c already done. <<<
+
+ Length = 4096;
+ // AMI_OVERRIDE_FOR_FIRST_BOOT
+ Status = PciLibRegisterMemory (
+ PCI_LIB_ADDRESS (0,
+ 0,
+ 0,
+ 0),
+ (UINTN) Length
+ );
+ // AMI_OVERRIDE_FOR_FIRST_BOOT
+
+ Status = PciLibRegisterMemory (
+ PCI_LIB_ADDRESS (DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ 0),
+ (UINTN) Length
+ );
+ ASSERT_EFI_ERROR (Status);
+ ///
+ /// Allocate Runtime memory for the PchReset protocol instance.
+ ///
+ mPchResetInstance = AllocateRuntimeZeroPool (sizeof (PCH_RESET_INSTANCE));
+ if (mPchResetInstance == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = PchResetProtocolConstructor (mPchResetInstance);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ///
+ /// Install protocol interface
+ ///
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mPchResetInstance->Handle,
+ &gPchResetProtocolGuid,
+ &mPchResetInstance->PchResetProtocol,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+// AMI_OVERRIDE, [EIP111666] >>>
+ Status = EfiCreateEventLegacyBootEx (
+ EFI_TPL_CALLBACK,
+ PchResetExitBootServicesEvent,
+ NULL,
+ &LegacyBootEvent
+ );
+// AMI_OVERRIDE, [EIP111666] <<<
+
+ ///
+ /// The Lib Deconstruct will automatically be called when entrypoint return error.
+ ///
+ DEBUG ((EFI_D_INFO, "InstallPchReset() End\n"));
+
+ return Status;
+}
+
+#if (EFI_SPECIFICATION_VERSION >= 0x00020000)
+/**
+ If need be, do any special reset required for capsules. For this
+ implementation where we're called from the ResetSystem() api,
+ just set our capsule variable and return to let the caller
+ do a soft reset.
+
+ @param[in] None
+
+ @retval None
+**/
+VOID
+CapsuleReset (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ UINTN CapsuleDataPtr;
+ UINT32 Data32;
+ UINT32 Eflags;
+ UINT16 PmBase;
+
+ ///
+ /// Check if there are pending capsules to process
+ ///
+ Size = sizeof (CapsuleDataPtr);
+ Status = EfiGetVariable (
+ EFI_CAPSULE_VARIABLE_NAME,
+ &gEfiCapsuleVendorGuid,
+ NULL,
+ &Size,
+ (VOID *) &CapsuleDataPtr
+ );
+
+ if (Status == EFI_SUCCESS) {
+ ///
+ /// Wake up system 2 seconds after putting system into S3 to complete the reset operation.
+ ///
+ SetSystemWakeupAlarm (2);
+ ///
+ /// Process capsules across a system reset.
+ ///
+ PmBase = PciRead16 (
+ PCI_LIB_ADDRESS (DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ R_PCH_LPC_ACPI_BASE)
+ ) & B_PCH_LPC_ACPI_BASE_BAR;
+
+ ASSERT (PmBase != 0);
+
+ Data32 = IoRead32 ((UINTN) (PmBase + R_PCH_ACPI_PM1_CNT));
+
+ Data32 = (UINT32) ((Data32 & ~(B_PCH_ACPI_PM1_CNT_SLP_TYP + B_PCH_ACPI_PM1_CNT_SLP_EN)) | V_PCH_ACPI_PM1_CNT_S3);
+
+ Eflags = (UINT32) AsmReadEflags ();
+
+ if ((Eflags & 0x200)) {
+ DisableInterrupts ();
+ }
+
+ AsmWbinvd ();
+ AsmWriteCr0 (AsmReadCr0 () | 0x060000000);
+
+ IoWrite32 (
+ (UINTN) (PmBase + R_PCH_ACPI_PM1_CNT),
+ (UINT32) Data32
+ );
+
+ Data32 = Data32 | B_PCH_ACPI_PM1_CNT_SLP_EN;
+
+ IoWrite32 (
+ (UINTN) (PmBase + R_PCH_ACPI_PM1_CNT),
+ (UINT32) Data32
+ );
+
+ if ((Eflags & 0x200)) {
+ EnableInterrupts ();
+ }
+ ///
+ /// Should not return
+ ///
+ EFI_DEADLOOP ();
+ }
+}
+#endif
+
+/**
+ Execute call back function for Pch Reset.
+
+ @param[in] PchResetType Pch Reset Types which includes PowerCycle, Globalreset.
+
+ @retval EFI_SUCCESS The callback function has been done successfully
+ @retval EFI_NOT_FOUND Failed to find Pch Reset Callback protocol. Or, none of
+ callback protocol is installed.
+ @retval Others Do not do any reset from PCH
+**/
+EFI_STATUS
+EFIAPI
+PchResetCallback (
+ IN PCH_RESET_TYPE PchResetType
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumHandles;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ PCH_RESET_CALLBACK_PROTOCOL *PchResetCallback;
+// AMI_OVERRIDE, [EIP111666] >>>
+ UINTN VariableSize = 1;
+ UINT8 TempBuffer;
+ BOOLEAN LegacyBoot = FALSE;
+// AMI_OVERRIDE, [EIP111666] <<<
+
+// AMI_OVERRIDE, [EIP111666] >>>
+ Status = gRT->GetVariable (
+ L"InLegacyBoot",
+ &gPchGetResetTypeGuid,
+ NULL,
+ &VariableSize,
+ &TempBuffer
+ );
+
+ // If variable found, we are in runtime.
+ if(!EFI_ERROR(Status))
+ LegacyBoot = TRUE;
+
+ if (!(EfiAtRuntime () || LegacyBoot)) {
+// AMI_OVERRIDE, [EIP111666] <<<
+
+ ///
+ /// Retrieve all instances of Pch Reset Callback protocol
+ ///
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gPchResetCallbackProtocolGuid,
+ NULL,
+ &NumHandles,
+ &HandleBuffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ ///
+ /// Those drivers that need to install Pch Reset Callback protocol have the responsibility
+ /// to make sure themselves execute before Pch Reset Runtime driver.
+ ///
+ if (Status == EFI_NOT_FOUND) {
+ DEBUG ((EFI_D_ERROR | EFI_D_INFO, "Or, none of Pch Reset callback protocol is installed.\n"));
+ }
+
+ return Status;
+ }
+
+ for (Index = 0; Index < NumHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gPchResetCallbackProtocolGuid,
+ (VOID **) &PchResetCallback
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (!EFI_ERROR (Status)) {
+ PchResetCallback->ResetCallback (PchResetType);
+ } else {
+ DEBUG ((EFI_D_ERROR | EFI_D_INFO, "Failed to locate Pch Reset Callback protocol.\n"));
+ return Status;
+ }
+ }
+ }
+
+#if (EFI_SPECIFICATION_VERSION >= 0x00020000)
+ if (PchResetType == WarmReset) {
+ CapsuleReset ();
+ }
+#endif
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Fixup internal data pointers so that the services can be called in virtual mode.
+
+ @param[in] Event The event registered.
+ @param[in] Context Event context. Not used in this event handler.
+
+ @retval None
+**/
+EFI_RUNTIMESERVICE
+VOID
+PchResetVirtualAddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mPchResetInstance->PchResetProtocol.Reset));
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mPchResetInstance->PchRootComplexBar));
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mPchResetInstance));
+}