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