Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com> Cc: Kelly Steele <kelly.steele@intel.com>
		
			
				
	
	
		
			343 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			343 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
System reset Library Services.  This library class provides a set of
 | 
						|
methods to reset whole system with manipulate QNC.
 | 
						|
 | 
						|
Copyright (c) 2013-2016 Intel Corporation.
 | 
						|
 | 
						|
This program and the accompanying materials
 | 
						|
are licensed and made available under the terms and conditions of the BSD License
 | 
						|
which accompanies this distribution.  The full text of the license may be found at
 | 
						|
http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include <Base.h>
 | 
						|
#include <IntelQNCBase.h>
 | 
						|
#include <QNCAccess.h>
 | 
						|
 | 
						|
#include <Uefi/UefiBaseType.h>
 | 
						|
 | 
						|
#include <Library/ResetSystemLib.h>
 | 
						|
#include <Library/BaseLib.h>
 | 
						|
#include <Library/IoLib.h>
 | 
						|
#include <Library/PcdLib.h>
 | 
						|
#include <Library/CpuLib.h>
 | 
						|
#include <Library/QNCAccessLib.h>
 | 
						|
 | 
						|
//
 | 
						|
// Amount of time (seconds) before RTC alarm fires
 | 
						|
// This must be < BCD_BASE
 | 
						|
//
 | 
						|
#define PLATFORM_WAKE_SECONDS_BUFFER 0x06
 | 
						|
 | 
						|
//
 | 
						|
// RTC 'seconds' above which we will not read to avoid potential rollover
 | 
						|
//
 | 
						|
#define PLATFORM_RTC_ROLLOVER_LIMIT 0x47
 | 
						|
 | 
						|
//
 | 
						|
// BCD is base 10
 | 
						|
//
 | 
						|
#define BCD_BASE 0x0A
 | 
						|
 | 
						|
#define PCAT_RTC_ADDRESS_REGISTER 0x70
 | 
						|
#define PCAT_RTC_DATA_REGISTER    0x71
 | 
						|
 | 
						|
//
 | 
						|
// Dallas DS12C887 Real Time Clock
 | 
						|
//
 | 
						|
#define RTC_ADDRESS_SECONDS           0   // R/W  Range 0..59
 | 
						|
#define RTC_ADDRESS_SECONDS_ALARM     1   // R/W  Range 0..59
 | 
						|
#define RTC_ADDRESS_MINUTES           2   // R/W  Range 0..59
 | 
						|
#define RTC_ADDRESS_MINUTES_ALARM     3   // R/W  Range 0..59
 | 
						|
#define RTC_ADDRESS_HOURS             4   // R/W  Range 1..12 or 0..23 Bit 7 is AM/PM
 | 
						|
#define RTC_ADDRESS_HOURS_ALARM       5   // R/W  Range 1..12 or 0..23 Bit 7 is AM/PM
 | 
						|
#define RTC_ADDRESS_DAY_OF_THE_WEEK   6   // R/W  Range 1..7
 | 
						|
#define RTC_ADDRESS_DAY_OF_THE_MONTH  7   // R/W  Range 1..31
 | 
						|
#define RTC_ADDRESS_MONTH             8   // R/W  Range 1..12
 | 
						|
#define RTC_ADDRESS_YEAR              9   // R/W  Range 0..99
 | 
						|
#define RTC_ADDRESS_REGISTER_A        10  // R/W[0..6]  R0[7]
 | 
						|
#define RTC_ADDRESS_REGISTER_B        11  // R/W
 | 
						|
#define RTC_ADDRESS_REGISTER_C        12  // RO
 | 
						|
#define RTC_ADDRESS_REGISTER_D        13  // RO
 | 
						|
#define RTC_ADDRESS_CENTURY           50  // R/W  Range 19..20 Bit 8 is R/W
 | 
						|
 | 
						|
/**
 | 
						|
  Wait for an RTC update to happen
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
WaitForRTCUpdate (
 | 
						|
VOID
 | 
						|
)
 | 
						|
{
 | 
						|
  UINT8   Data8;
 | 
						|
 | 
						|
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);
 | 
						|
  Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
 | 
						|
  if ((Data8 & BIT7) == BIT7) {
 | 
						|
    while ((Data8 & BIT7) == BIT7) {
 | 
						|
      IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);
 | 
						|
      Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
 | 
						|
    }
 | 
						|
 | 
						|
  } else {
 | 
						|
    while ((Data8 & BIT7) == 0) {
 | 
						|
      IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);
 | 
						|
      Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
 | 
						|
    }
 | 
						|
 | 
						|
    while ((Data8 & BIT7) == BIT7) {
 | 
						|
      IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);
 | 
						|
      Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Calling this function causes a system-wide reset. This sets
 | 
						|
  all circuitry within the system to its initial state. This type of reset
 | 
						|
  is asynchronous to system operation and operates without regard to
 | 
						|
  cycle boundaries.
 | 
						|
 | 
						|
  System reset should not return, if it returns, it means the system does
 | 
						|
  not support cold reset.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
ResetCold (
 | 
						|
VOID
 | 
						|
)
 | 
						|
{
 | 
						|
  //
 | 
						|
  // Reference to QuarkNcSocId BWG
 | 
						|
  // Setting bit 1 will generate a warm reset, driving only RSTRDY# low
 | 
						|
  //
 | 
						|
  IoWrite8 (RST_CNT, B_RST_CNT_COLD_RST);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Calling this function causes a system-wide initialization. The processors
 | 
						|
  are set to their initial state, and pending cycles are not corrupted.
 | 
						|
 | 
						|
  System reset should not return, if it returns, it means the system does
 | 
						|
  not support warm reset.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
ResetWarm (
 | 
						|
VOID
 | 
						|
)
 | 
						|
{
 | 
						|
  //
 | 
						|
  // Reference to QuarkNcSocId BWG
 | 
						|
  // Setting bit 1 will generate a warm reset, driving only RSTRDY# low
 | 
						|
  //
 | 
						|
  IoWrite8 (RST_CNT, B_RST_CNT_WARM_RST);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Calling this function causes the system to enter a power state equivalent
 | 
						|
  to the ACPI G2/S5 or G3 states.
 | 
						|
 | 
						|
  System shutdown should not return, if it returns, it means the system does
 | 
						|
  not support shut down reset.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
ResetShutdown (
 | 
						|
VOID
 | 
						|
)
 | 
						|
{
 | 
						|
  //
 | 
						|
  // Reference to QuarkNcSocId BWG
 | 
						|
  //  Disable RTC Alarm :  (RTC Enable at PM1BLK + 02h[10]))
 | 
						|
  //
 | 
						|
  IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, 0);
 | 
						|
 | 
						|
  //
 | 
						|
  // Firstly, GPE0_EN should be disabled to
 | 
						|
  // avoid any GPI waking up the system from S5
 | 
						|
  //
 | 
						|
  IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0E, 0);
 | 
						|
 | 
						|
  //
 | 
						|
  // Reference to QuarkNcSocId BWG
 | 
						|
  //  Disable Resume Well GPIO :  (GPIO bits in GPIOBASE + 34h[8:0])
 | 
						|
  //
 | 
						|
  IoWrite32 (PcdGet16 (PcdGbaIoBaseAddress) + R_QNC_GPIO_RGGPE_RESUME_WELL, 0);
 | 
						|
 | 
						|
  //
 | 
						|
  // No power button status bit to clear for our platform, go to next step.
 | 
						|
  //
 | 
						|
 | 
						|
  //
 | 
						|
  // Finally, transform system into S5 sleep state
 | 
						|
  //
 | 
						|
  IoAndThenOr32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, 0xffffc3ff, B_QNC_PM1BLK_PM1C_SLPEN | V_S5);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Calling this function causes the system to enter a power state for capsule
 | 
						|
  update.
 | 
						|
 | 
						|
  Reset update should not return, if it returns, it means the system does
 | 
						|
  not support capsule update.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
EnterS3WithImmediateWake (
 | 
						|
VOID
 | 
						|
)
 | 
						|
{
 | 
						|
  UINT8     Data8;
 | 
						|
  UINT16    Data16;
 | 
						|
  UINT32    Data32;
 | 
						|
  UINTN     Eflags;
 | 
						|
  UINTN     RegCr0;
 | 
						|
  EFI_TIME  EfiTime;
 | 
						|
  UINT32    SmiEnSave;
 | 
						|
 | 
						|
  Eflags  = AsmReadEflags ();
 | 
						|
  if ( (Eflags & 0x200) ) {
 | 
						|
     DisableInterrupts ();
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Write all cache data to memory because processor will lost power
 | 
						|
  //
 | 
						|
  AsmWbinvd();
 | 
						|
  RegCr0 = AsmReadCr0();
 | 
						|
  AsmWriteCr0 (RegCr0 | 0x060000000);
 | 
						|
 | 
						|
  SmiEnSave = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
 | 
						|
  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, (SmiEnSave & ~SMI_EN));
 | 
						|
 | 
						|
  //
 | 
						|
  // Pogram RTC alarm for immediate WAKE
 | 
						|
  //
 | 
						|
 | 
						|
  //
 | 
						|
  // Disable SMI sources
 | 
						|
  //
 | 
						|
  IoWrite16 (PcdGet16 (PcdGpe0blkIoBaseAddress) + R_QNC_GPE0BLK_SMIE, 0);
 | 
						|
 | 
						|
  //
 | 
						|
  // Disable RTC alarm interrupt
 | 
						|
  //
 | 
						|
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);
 | 
						|
  Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
 | 
						|
  IoWrite8 (PCAT_RTC_DATA_REGISTER, (Data8 & ~BIT5));
 | 
						|
 | 
						|
  //
 | 
						|
  // Clear RTC alarm if already set
 | 
						|
  //
 | 
						|
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_C);
 | 
						|
  Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);              // Read clears alarm status
 | 
						|
 | 
						|
  //
 | 
						|
  // Disable all WAKE events
 | 
						|
  //
 | 
						|
  IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, B_QNC_PM1BLK_PM1E_PWAKED);
 | 
						|
 | 
						|
  //
 | 
						|
  // Clear all WAKE status bits
 | 
						|
  //
 | 
						|
  IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S, B_QNC_PM1BLK_PM1S_ALL);
 | 
						|
 | 
						|
  //
 | 
						|
  // Avoid RTC rollover
 | 
						|
  //
 | 
						|
  do {
 | 
						|
    WaitForRTCUpdate();
 | 
						|
    IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS);
 | 
						|
    EfiTime.Second = IoRead8 (PCAT_RTC_DATA_REGISTER);
 | 
						|
  } while (EfiTime.Second > PLATFORM_RTC_ROLLOVER_LIMIT);
 | 
						|
 | 
						|
  //
 | 
						|
  // Read RTC time
 | 
						|
  //
 | 
						|
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOURS);
 | 
						|
  EfiTime.Hour = IoRead8 (PCAT_RTC_DATA_REGISTER);
 | 
						|
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTES);
 | 
						|
  EfiTime.Minute = IoRead8 (PCAT_RTC_DATA_REGISTER);
 | 
						|
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS);
 | 
						|
  EfiTime.Second = IoRead8 (PCAT_RTC_DATA_REGISTER);
 | 
						|
 | 
						|
  //
 | 
						|
  // Set RTC alarm
 | 
						|
  //
 | 
						|
 | 
						|
  //
 | 
						|
  // Add PLATFORM_WAKE_SECONDS_BUFFER to current EfiTime.Second
 | 
						|
  // The maths is to allow for the fact we are adding to a BCD number and require the answer to be BCD (EfiTime.Second)
 | 
						|
  //
 | 
						|
  if ((BCD_BASE - (EfiTime.Second & 0x0F)) <= PLATFORM_WAKE_SECONDS_BUFFER) {
 | 
						|
    Data8 = (((EfiTime.Second & 0xF0) + 0x10) + (PLATFORM_WAKE_SECONDS_BUFFER - (BCD_BASE - (EfiTime.Second & 0x0F))));
 | 
						|
  } else {
 | 
						|
    Data8 = EfiTime.Second + PLATFORM_WAKE_SECONDS_BUFFER;
 | 
						|
  }
 | 
						|
 | 
						|
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOURS_ALARM);
 | 
						|
  IoWrite8 (PCAT_RTC_DATA_REGISTER, EfiTime.Hour);
 | 
						|
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTES_ALARM);
 | 
						|
  IoWrite8 (PCAT_RTC_DATA_REGISTER, EfiTime.Minute);
 | 
						|
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS_ALARM);
 | 
						|
  IoWrite8 (PCAT_RTC_DATA_REGISTER, Data8);
 | 
						|
 | 
						|
  //
 | 
						|
  // Enable RTC alarm interrupt
 | 
						|
  //
 | 
						|
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);
 | 
						|
  Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
 | 
						|
  IoWrite8 (PCAT_RTC_DATA_REGISTER, (Data8 | BIT5));
 | 
						|
 | 
						|
  //
 | 
						|
  // Enable RTC alarm as WAKE event
 | 
						|
  //
 | 
						|
  Data16 = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E);
 | 
						|
  IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, (Data16 | B_QNC_PM1BLK_PM1E_RTC));
 | 
						|
 | 
						|
  //
 | 
						|
  // Enter S3
 | 
						|
  //
 | 
						|
  Data32 = IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
 | 
						|
  Data32  = (UINT32) ((Data32 & 0xffffc3fe) | V_S3 | B_QNC_PM1BLK_PM1C_SCIEN);
 | 
						|
  IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Data32);
 | 
						|
  Data32 = Data32 | B_QNC_PM1BLK_PM1C_SLPEN;
 | 
						|
  IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Data32);
 | 
						|
 | 
						|
  //
 | 
						|
  // Enable Interrupt if it's enabled before
 | 
						|
  //
 | 
						|
  if ( (Eflags & 0x200) ) {
 | 
						|
     EnableInterrupts ();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function causes a systemwide reset. The exact type of the reset is
 | 
						|
  defined by the EFI_GUID that follows the Null-terminated Unicode string passed
 | 
						|
  into ResetData. If the platform does not recognize the EFI_GUID in ResetData
 | 
						|
  the platform must pick a supported reset type to perform.The platform may
 | 
						|
  optionally log the parameters from any non-normal reset that occurs.
 | 
						|
 | 
						|
  @param[in]  DataSize   The size, in bytes, of ResetData.
 | 
						|
  @param[in]  ResetData  The data buffer starts with a Null-terminated string,
 | 
						|
                         followed by the EFI_GUID.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
ResetPlatformSpecific (
 | 
						|
  IN UINTN   DataSize,
 | 
						|
  IN VOID    *ResetData
 | 
						|
  )
 | 
						|
{
 | 
						|
  ResetCold ();
 | 
						|
}
 |