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