QuarkSocPkg/QncSmmDispatcher: Fix context passed to SMI handlers
[mirror_edk2.git] / QuarkSocPkg / QuarkNorthCluster / Library / ResetSystemLib / ResetSystemLib.c
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-2016 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 /**
324 This function causes a systemwide reset. The exact type of the reset is
325 defined by the EFI_GUID that follows the Null-terminated Unicode string passed
326 into ResetData. If the platform does not recognize the EFI_GUID in ResetData
327 the platform must pick a supported reset type to perform.The platform may
328 optionally log the parameters from any non-normal reset that occurs.
329
330 @param[in] DataSize The size, in bytes, of ResetData.
331 @param[in] ResetData The data buffer starts with a Null-terminated string,
332 followed by the EFI_GUID.
333 **/
334 VOID
335 EFIAPI
336 ResetPlatformSpecific (
337 IN UINTN DataSize,
338 IN VOID *ResetData
339 )
340 {
341 ResetCold ();
342 }