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