Home | History | Annotate | Download | only in ResetSystemLib
      1 /** @file
      2 System reset Library Services.  This library class provides a set of
      3 methods to reset whole system with manipulate QNC.
      4 
      5 Copyright (c) 2013-2015 Intel Corporation.
      6 
      7 This program and the accompanying materials
      8 are licensed and made available under the terms and conditions of the BSD License
      9 which accompanies this distribution.  The full text of the license may be found at
     10 http://opensource.org/licenses/bsd-license.php
     11 
     12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include <Base.h>
     18 #include <IntelQNCBase.h>
     19 #include <QNCAccess.h>
     20 
     21 #include <Uefi/UefiBaseType.h>
     22 
     23 #include <Library/ResetSystemLib.h>
     24 #include <Library/BaseLib.h>
     25 #include <Library/IoLib.h>
     26 #include <Library/PcdLib.h>
     27 #include <Library/CpuLib.h>
     28 #include <Library/QNCAccessLib.h>
     29 
     30 //
     31 // Amount of time (seconds) before RTC alarm fires
     32 // This must be < BCD_BASE
     33 //
     34 #define PLATFORM_WAKE_SECONDS_BUFFER 0x06
     35 
     36 //
     37 // RTC 'seconds' above which we will not read to avoid potential rollover
     38 //
     39 #define PLATFORM_RTC_ROLLOVER_LIMIT 0x47
     40 
     41 //
     42 // BCD is base 10
     43 //
     44 #define BCD_BASE 0x0A
     45 
     46 #define PCAT_RTC_ADDRESS_REGISTER 0x70
     47 #define PCAT_RTC_DATA_REGISTER    0x71
     48 
     49 //
     50 // Dallas DS12C887 Real Time Clock
     51 //
     52 #define RTC_ADDRESS_SECONDS           0   // R/W  Range 0..59
     53 #define RTC_ADDRESS_SECONDS_ALARM     1   // R/W  Range 0..59
     54 #define RTC_ADDRESS_MINUTES           2   // R/W  Range 0..59
     55 #define RTC_ADDRESS_MINUTES_ALARM     3   // R/W  Range 0..59
     56 #define RTC_ADDRESS_HOURS             4   // R/W  Range 1..12 or 0..23 Bit 7 is AM/PM
     57 #define RTC_ADDRESS_HOURS_ALARM       5   // R/W  Range 1..12 or 0..23 Bit 7 is AM/PM
     58 #define RTC_ADDRESS_DAY_OF_THE_WEEK   6   // R/W  Range 1..7
     59 #define RTC_ADDRESS_DAY_OF_THE_MONTH  7   // R/W  Range 1..31
     60 #define RTC_ADDRESS_MONTH             8   // R/W  Range 1..12
     61 #define RTC_ADDRESS_YEAR              9   // R/W  Range 0..99
     62 #define RTC_ADDRESS_REGISTER_A        10  // R/W[0..6]  R0[7]
     63 #define RTC_ADDRESS_REGISTER_B        11  // R/W
     64 #define RTC_ADDRESS_REGISTER_C        12  // RO
     65 #define RTC_ADDRESS_REGISTER_D        13  // RO
     66 #define RTC_ADDRESS_CENTURY           50  // R/W  Range 19..20 Bit 8 is R/W
     67 
     68 /**
     69   Wait for an RTC update to happen
     70 
     71 **/
     72 VOID
     73 EFIAPI
     74 WaitForRTCUpdate (
     75 VOID
     76 )
     77 {
     78   UINT8   Data8;
     79 
     80   IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);
     81   Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
     82   if ((Data8 & BIT7) == BIT7) {
     83     while ((Data8 & BIT7) == BIT7) {
     84       IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);
     85       Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
     86     }
     87 
     88   } else {
     89     while ((Data8 & BIT7) == 0) {
     90       IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);
     91       Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
     92     }
     93 
     94     while ((Data8 & BIT7) == BIT7) {
     95       IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);
     96       Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
     97     }
     98   }
     99 }
    100 
    101 /**
    102   Calling this function causes a system-wide reset. This sets
    103   all circuitry within the system to its initial state. This type of reset
    104   is asynchronous to system operation and operates without regard to
    105   cycle boundaries.
    106 
    107   System reset should not return, if it returns, it means the system does
    108   not support cold reset.
    109 **/
    110 VOID
    111 EFIAPI
    112 ResetCold (
    113 VOID
    114 )
    115 {
    116   //
    117   // Reference to QuarkNcSocId BWG
    118   // Setting bit 1 will generate a warm reset, driving only RSTRDY# low
    119   //
    120   IoWrite8 (RST_CNT, B_RST_CNT_COLD_RST);
    121 }
    122 
    123 /**
    124   Calling this function causes a system-wide initialization. The processors
    125   are set to their initial state, and pending cycles are not corrupted.
    126 
    127   System reset should not return, if it returns, it means the system does
    128   not support warm reset.
    129 **/
    130 VOID
    131 EFIAPI
    132 ResetWarm (
    133 VOID
    134 )
    135 {
    136   //
    137   // Reference to QuarkNcSocId BWG
    138   // Setting bit 1 will generate a warm reset, driving only RSTRDY# low
    139   //
    140   IoWrite8 (RST_CNT, B_RST_CNT_WARM_RST);
    141 }
    142 
    143 /**
    144   Calling this function causes the system to enter a power state equivalent
    145   to the ACPI G2/S5 or G3 states.
    146 
    147   System shutdown should not return, if it returns, it means the system does
    148   not support shut down reset.
    149 **/
    150 VOID
    151 EFIAPI
    152 ResetShutdown (
    153 VOID
    154 )
    155 {
    156   //
    157   // Reference to QuarkNcSocId BWG
    158   //  Disable RTC Alarm :  (RTC Enable at PM1BLK + 02h[10]))
    159   //
    160   IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, 0);
    161 
    162   //
    163   // Firstly, GPE0_EN should be disabled to
    164   // avoid any GPI waking up the system from S5
    165   //
    166   IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0E, 0);
    167 
    168   //
    169   // Reference to QuarkNcSocId BWG
    170   //  Disable Resume Well GPIO :  (GPIO bits in GPIOBASE + 34h[8:0])
    171   //
    172   IoWrite32 (PcdGet16 (PcdGbaIoBaseAddress) + R_QNC_GPIO_RGGPE_RESUME_WELL, 0);
    173 
    174   //
    175   // No power button status bit to clear for our platform, go to next step.
    176   //
    177 
    178   //
    179   // Finally, transform system into S5 sleep state
    180   //
    181   IoAndThenOr32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, 0xffffc3ff, B_QNC_PM1BLK_PM1C_SLPEN | V_S5);
    182 }
    183 
    184 /**
    185   Calling this function causes the system to enter a power state for capsule
    186   update.
    187 
    188   Reset update should not return, if it returns, it means the system does
    189   not support capsule update.
    190 
    191 **/
    192 VOID
    193 EFIAPI
    194 EnterS3WithImmediateWake (
    195 VOID
    196 )
    197 {
    198   UINT8     Data8;
    199   UINT16    Data16;
    200   UINT32    Data32;
    201   UINTN     Eflags;
    202   UINTN     RegCr0;
    203   EFI_TIME  EfiTime;
    204   UINT32    SmiEnSave;
    205 
    206   Eflags  = AsmReadEflags ();
    207   if ( (Eflags & 0x200) ) {
    208      DisableInterrupts ();
    209   }
    210 
    211   //
    212   //  Write all cache data to memory because processor will lost power
    213   //
    214   AsmWbinvd();
    215   RegCr0 = AsmReadCr0();
    216   AsmWriteCr0 (RegCr0 | 0x060000000);
    217 
    218   SmiEnSave = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
    219   QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, (SmiEnSave & ~SMI_EN));
    220 
    221   //
    222   // Pogram RTC alarm for immediate WAKE
    223   //
    224 
    225   //
    226   // Disable SMI sources
    227   //
    228   IoWrite16 (PcdGet16 (PcdGpe0blkIoBaseAddress) + R_QNC_GPE0BLK_SMIE, 0);
    229 
    230   //
    231   // Disable RTC alarm interrupt
    232   //
    233   IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);
    234   Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
    235   IoWrite8 (PCAT_RTC_DATA_REGISTER, (Data8 & ~BIT5));
    236 
    237   //
    238   // Clear RTC alarm if already set
    239   //
    240   IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_C);
    241   Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);              // Read clears alarm status
    242 
    243   //
    244   // Disable all WAKE events
    245   //
    246   IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, B_QNC_PM1BLK_PM1E_PWAKED);
    247 
    248   //
    249   // Clear all WAKE status bits
    250   //
    251   IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S, B_QNC_PM1BLK_PM1S_ALL);
    252 
    253   //
    254   // Avoid RTC rollover
    255   //
    256   do {
    257     WaitForRTCUpdate();
    258     IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS);
    259     EfiTime.Second = IoRead8 (PCAT_RTC_DATA_REGISTER);
    260   } while (EfiTime.Second > PLATFORM_RTC_ROLLOVER_LIMIT);
    261 
    262   //
    263   // Read RTC time
    264   //
    265   IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOURS);
    266   EfiTime.Hour = IoRead8 (PCAT_RTC_DATA_REGISTER);
    267   IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTES);
    268   EfiTime.Minute = IoRead8 (PCAT_RTC_DATA_REGISTER);
    269   IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS);
    270   EfiTime.Second = IoRead8 (PCAT_RTC_DATA_REGISTER);
    271 
    272   //
    273   // Set RTC alarm
    274   //
    275 
    276   //
    277   // Add PLATFORM_WAKE_SECONDS_BUFFER to current EfiTime.Second
    278   // The maths is to allow for the fact we are adding to a BCD number and require the answer to be BCD (EfiTime.Second)
    279   //
    280   if ((BCD_BASE - (EfiTime.Second & 0x0F)) <= PLATFORM_WAKE_SECONDS_BUFFER) {
    281     Data8 = (((EfiTime.Second & 0xF0) + 0x10) + (PLATFORM_WAKE_SECONDS_BUFFER - (BCD_BASE - (EfiTime.Second & 0x0F))));
    282   } else {
    283     Data8 = EfiTime.Second + PLATFORM_WAKE_SECONDS_BUFFER;
    284   }
    285 
    286   IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOURS_ALARM);
    287   IoWrite8 (PCAT_RTC_DATA_REGISTER, EfiTime.Hour);
    288   IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTES_ALARM);
    289   IoWrite8 (PCAT_RTC_DATA_REGISTER, EfiTime.Minute);
    290   IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS_ALARM);
    291   IoWrite8 (PCAT_RTC_DATA_REGISTER, Data8);
    292 
    293   //
    294   // Enable RTC alarm interrupt
    295   //
    296   IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);
    297   Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
    298   IoWrite8 (PCAT_RTC_DATA_REGISTER, (Data8 | BIT5));
    299 
    300   //
    301   // Enable RTC alarm as WAKE event
    302   //
    303   Data16 = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E);
    304   IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, (Data16 | B_QNC_PM1BLK_PM1E_RTC));
    305 
    306   //
    307   // Enter S3
    308   //
    309   Data32 = IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
    310   Data32  = (UINT32) ((Data32 & 0xffffc3fe) | V_S3 | B_QNC_PM1BLK_PM1C_SCIEN);
    311   IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Data32);
    312   Data32 = Data32 | B_QNC_PM1BLK_PM1C_SLPEN;
    313   IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Data32);
    314 
    315   //
    316   // Enable Interrupt if it's enabled before
    317   //
    318   if ( (Eflags & 0x200) ) {
    319      EnableInterrupts ();
    320   }
    321 }
    322 
    323