]> git.proxmox.com Git - mirror_edk2.git/blame - QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c
QuarkSocPkg: Add new package for Quark SoC X1000
[mirror_edk2.git] / QuarkSocPkg / QuarkNorthCluster / Smm / Dxe / SmmControlDxe / SmmControlDriver.c
CommitLineData
9b6bbcdb
MK
1/** @file\r
2This module produces the SMM COntrol2 Protocol for QNC\r
3\r
4Copyright (c) 2013-2015 Intel Corporation.\r
5\r
6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include <PiDxe.h>\r
17#include <Protocol/SmmControl2.h>\r
18#include <IndustryStandard/Pci.h>\r
19#include <Library/DebugLib.h>\r
20#include <Library/UefiBootServicesTableLib.h>\r
21#include <Library/UefiRuntimeServicesTableLib.h>\r
22#include <Library/PcdLib.h>\r
23#include <Library/IoLib.h>\r
24#include <Library/PciLib.h>\r
25#include <IntelQNCDxe.h>\r
26#include <Library/QNCAccessLib.h>\r
27#include <Uefi/UefiBaseType.h>\r
28\r
29#define EFI_INTERNAL_POINTER 0x00000004\r
30\r
31extern EFI_GUID gEfiEventVirtualAddressChangeGuid;\r
32\r
33/**\r
34 Generates an SMI using the parameters passed in.\r
35\r
36 @param This A pointer to an instance of\r
37 EFI_SMM_CONTROL2_PROTOCOL\r
38 @param ArgumentBuffer The argument buffer\r
39 @param ArgumentBufferSize The size of the argument buffer\r
40 @param Periodic TRUE to indicate a periodical SMI\r
41 @param ActivationInterval Interval of the periodical SMI\r
42\r
43 @retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1\r
44 @return Return value from SmmTrigger().\r
45\r
46**/\r
47EFI_STATUS\r
48EFIAPI\r
49Activate (\r
50 IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,\r
51 IN OUT UINT8 *CommandPort OPTIONAL,\r
52 IN OUT UINT8 *DataPort OPTIONAL,\r
53 IN BOOLEAN Periodic OPTIONAL,\r
54 IN EFI_SMM_PERIOD ActivationInterval OPTIONAL\r
55 );\r
56\r
57/**\r
58 Clears an SMI.\r
59\r
60 @param This Pointer to an instance of EFI_SMM_CONTROL2_PROTOCOL\r
61 @param Periodic TRUE to indicate a periodical SMI\r
62\r
63 @return Return value from SmmClear()\r
64\r
65**/\r
66EFI_STATUS\r
67EFIAPI\r
68Deactivate (\r
69 IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,\r
70 IN BOOLEAN Periodic OPTIONAL\r
71 );\r
72\r
73///\r
74/// Handle for the SMM Control2 Protocol\r
75///\r
76EFI_HANDLE mSmmControl2Handle = NULL;\r
77\r
78///\r
79/// SMM COntrol2 Protocol instance\r
80///\r
81EFI_SMM_CONTROL2_PROTOCOL mSmmControl2 = {\r
82 Activate,\r
83 Deactivate,\r
84 0\r
85};\r
86\r
87VOID\r
88EFIAPI\r
89SmmControlVirtualddressChangeEvent (\r
90 IN EFI_EVENT Event,\r
91 IN VOID *Context\r
92 )\r
93/*++\r
94\r
95Routine Description:\r
96\r
97 Fixup internal data pointers so that the services can be called in virtual mode.\r
98\r
99Arguments:\r
100\r
101 Event The event registered.\r
102 Context Event context.\r
103\r
104Returns:\r
105\r
106 None.\r
107\r
108--*/\r
109{\r
110 gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSmmControl2.Trigger));\r
111 gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSmmControl2.Clear));\r
112}\r
113\r
114/**\r
115 Clear SMI related chipset status and re-enable SMI by setting the EOS bit.\r
116\r
117 @retval EFI_SUCCESS The requested operation has been carried out successfully\r
118 @retval EFI_DEVICE_ERROR The EOS bit could not be set.\r
119\r
120**/\r
121EFI_STATUS\r
122SmmClear (\r
123 VOID\r
124 )\r
125{\r
126 UINT16 PM1BLK_Base;\r
127 UINT16 GPE0BLK_Base;\r
128\r
129 //\r
130 // Get PM1BLK_Base & GPE0BLK_Base\r
131 //\r
132 PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress);\r
133 GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);\r
134\r
135 //\r
136 // Clear the Power Button Override Status Bit, it gates EOS from being set.\r
137 // In QuarkNcSocId - Bit is read only. Handled by external SMC, do nothing.\r
138 //\r
139\r
140 //\r
141 // Clear the APM SMI Status Bit\r
142 //\r
143 IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM);\r
144\r
145 //\r
146 // Set the EOS Bit\r
147 //\r
148 IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);\r
149\r
150 return EFI_SUCCESS;\r
151}\r
152\r
153/**\r
154 Generates an SMI using the parameters passed in.\r
155\r
156 @param This A pointer to an instance of\r
157 EFI_SMM_CONTROL_PROTOCOL\r
158 @param ArgumentBuffer The argument buffer\r
159 @param ArgumentBufferSize The size of the argument buffer\r
160 @param Periodic TRUE to indicate a periodical SMI\r
161 @param ActivationInterval Interval of the periodical SMI\r
162\r
163 @retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1\r
164 @retval EFI_SUCCESS SMI generated\r
165\r
166**/\r
167EFI_STATUS\r
168EFIAPI\r
169Activate (\r
170 IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,\r
171 IN OUT UINT8 *CommandPort OPTIONAL,\r
172 IN OUT UINT8 *DataPort OPTIONAL,\r
173 IN BOOLEAN Periodic OPTIONAL,\r
174 IN EFI_SMM_PERIOD ActivationInterval OPTIONAL\r
175 )\r
176{\r
177 UINT16 GPE0BLK_Base;\r
178 UINT32 NewValue;\r
179\r
180 //\r
181 // Get GPE0BLK_Base\r
182 //\r
183 GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);\r
184\r
185 if (Periodic) {\r
186 return EFI_INVALID_PARAMETER;\r
187 }\r
188\r
189 //\r
190 // Clear any pending the APM SMI\r
191 //\r
192 if (EFI_ERROR (SmmClear())) {\r
193 return EFI_DEVICE_ERROR;\r
194 }\r
195\r
196 //\r
197 // Enable the APMC SMI\r
198 //\r
199 IoOr32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIE, B_QNC_GPE0BLK_SMIE_APM);\r
200\r
201 //\r
202 // Enable SMI globally\r
203 //\r
204 NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);\r
205 NewValue |= SMI_EN;\r
206 QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);\r
207\r
208\r
209 //\r
210 // Set APMC_STS\r
211 //\r
212 if (DataPort == NULL) {\r
213 IoWrite8 (PcdGet16 (PcdSmmDataPort), 0xFF);\r
214 } else {\r
215 IoWrite8 (PcdGet16 (PcdSmmDataPort), *DataPort);\r
216 }\r
217\r
218 //\r
219 // Generate the APMC SMI\r
220 //\r
221 if (CommandPort == NULL) {\r
222 IoWrite8 (PcdGet16 (PcdSmmActivationPort), 0xFF);\r
223 } else {\r
224 IoWrite8 (PcdGet16 (PcdSmmActivationPort), *CommandPort);\r
225 }\r
226\r
227 return EFI_SUCCESS;\r
228}\r
229\r
230/**\r
231 Clears an SMI.\r
232\r
233 @param This Pointer to an instance of EFI_SMM_CONTROL_PROTOCOL\r
234 @param Periodic TRUE to indicate a periodical SMI\r
235\r
236 @return Return value from SmmClear()\r
237\r
238**/\r
239EFI_STATUS\r
240EFIAPI\r
241Deactivate (\r
242 IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,\r
243 IN BOOLEAN Periodic\r
244 )\r
245{\r
246 if (Periodic) {\r
247 return EFI_INVALID_PARAMETER;\r
248 }\r
249\r
250 return SmmClear();\r
251}\r
252\r
253/**\r
254 This is the constructor for the SMM Control protocol.\r
255\r
256 This function installs EFI_SMM_CONTROL2_PROTOCOL.\r
257\r
258 @param ImageHandle Handle for the image of this driver\r
259 @param SystemTable Pointer to the EFI System Table\r
260\r
261 @retval EFI_UNSUPPORTED There's no Intel ICH on this platform\r
262 @return The status returned from InstallProtocolInterface().\r
263\r
264--*/\r
265EFI_STATUS\r
266SmmControl2Init (\r
267 IN EFI_HANDLE ImageHandle,\r
268 IN EFI_SYSTEM_TABLE *SystemTable\r
269 )\r
270{\r
271 EFI_STATUS Status;\r
272 EFI_EVENT Event;\r
273 UINT16 PM1BLK_Base;\r
274 UINT16 GPE0BLK_Base;\r
275 BOOLEAN SciEn;\r
276 UINT32 NewValue;\r
277\r
278 //\r
279 // Get PM1BLK_Base & GPE0BLK_Base\r
280 //\r
281 PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress);\r
282 GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);\r
283\r
284 //\r
285 // Install our protocol interfaces on the device's handle\r
286 //\r
287 Status = gBS->InstallMultipleProtocolInterfaces (\r
288 &mSmmControl2Handle,\r
289 &gEfiSmmControl2ProtocolGuid, &mSmmControl2,\r
290 NULL\r
291 );\r
292 ASSERT_EFI_ERROR (Status);\r
293\r
294 //\r
295 // Determine whether an ACPI OS is present (via the SCI_EN bit)\r
296 //\r
297 SciEn = (BOOLEAN)((IoRead16 (PM1BLK_Base + R_QNC_PM1BLK_PM1C) & B_QNC_PM1BLK_PM1C_SCIEN) != 0);\r
298 if (!SciEn) {\r
299 //\r
300 // Clear any SMIs that double as SCIs (when SCI_EN==0)\r
301 //\r
302 IoWrite16 ((PM1BLK_Base + R_QNC_PM1BLK_PM1S), B_QNC_PM1BLK_PM1S_ALL);\r
303 IoWrite16 ((PM1BLK_Base + R_QNC_PM1BLK_PM1E), 0x00000000);\r
304 IoWrite32 ((PM1BLK_Base + R_QNC_PM1BLK_PM1C), 0x00000000);\r
305 IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_GPE0S), B_QNC_GPE0BLK_GPE0S_ALL);\r
306 IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_GPE0E), 0x00000000);\r
307 }\r
308\r
309 //\r
310 // Clear and disable all SMIs that are unaffected by SCI_EN\r
311 // Set EOS\r
312 //\r
313 IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIE), 0x00000000);\r
314 IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), (B_QNC_GPE0BLK_SMIS_EOS + B_QNC_GPE0BLK_SMIS_ALL));\r
315\r
316 //\r
317 // Enable SMI globally\r
318 //\r
319 NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);\r
320 NewValue |= SMI_EN;\r
321 QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);\r
322\r
323 //\r
324 // Make sure to write this register last -- EOS re-enables SMIs for the QNC\r
325 //\r
326 IoAndThenOr32 (\r
327 GPE0BLK_Base + R_QNC_GPE0BLK_SMIE,\r
328 (UINT32)(~B_QNC_GPE0BLK_SMIE_ALL),\r
329 B_QNC_GPE0BLK_SMIE_APM\r
330 );\r
331\r
332 //\r
333 // Make sure EOS bit cleared\r
334 //\r
335 DEBUG_CODE_BEGIN ();\r
336 if (IoRead32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS) & B_QNC_GPE0BLK_SMIS_EOS) {\r
337 DEBUG ((\r
338 EFI_D_ERROR,\r
339 "******************************************************************************\n"\r
340 "BIG ERROR: SmmControl constructor couldn't properly initialize the ACPI table.\n"\r
341 " SmmControl->Clear will probably hang. \n"\r
342 " NOTE: SCI_EN = %d \n"\r
343 "******************************************************************************\n",\r
344 SciEn\r
345 ));\r
346\r
347 //\r
348 // If we want the system to stop, then keep the ASSERT(FALSE).\r
349 // Otherwise, comment it out.\r
350 //\r
351 ASSERT (FALSE);\r
352 }\r
353 DEBUG_CODE_END ();\r
354\r
355 Status = gBS->CreateEventEx (\r
356 EVT_NOTIFY_SIGNAL,\r
357 TPL_NOTIFY,\r
358 SmmControlVirtualddressChangeEvent,\r
359 NULL,\r
360 &gEfiEventVirtualAddressChangeGuid,\r
361 &Event\r
362 );\r
363 ASSERT_EFI_ERROR (Status);\r
364\r
365 return Status;\r
366}\r