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