summaryrefslogtreecommitdiffstats
path: root/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.c
diff options
context:
space:
mode:
Diffstat (limited to 'QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.c')
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.c322
1 files changed, 322 insertions, 0 deletions
diff --git a/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.c b/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.c
new file mode 100644
index 0000000000..c2ad7f3e1d
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.c
@@ -0,0 +1,322 @@
+/** @file
+System reset Library Services. This library class provides a set of
+methods to reset whole system with manipulate QNC.
+
+Copyright (c) 2013-2015 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 ();
+ }
+}
+