• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
SmmControlVirtualddressChangeEvent(IN EFI_EVENT Event,IN VOID * Context)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
SmmClear(VOID)122 SmmClear (
123   VOID
124   )
125 {
126   UINT16                       GPE0BLK_Base;
127 
128   //
129   // Get GPE0BLK_Base
130   //
131   GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);
132 
133   //
134   // Clear the Power Button Override Status Bit, it gates EOS from being set.
135   // In QuarkNcSocId - Bit is read only. Handled by external SMC, do nothing.
136   //
137 
138   //
139   // Clear the APM SMI Status Bit
140   //
141   IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM);
142 
143   //
144   // Set the EOS Bit
145   //
146   IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);
147 
148   return EFI_SUCCESS;
149 }
150 
151 /**
152   Generates an SMI using the parameters passed in.
153 
154   @param  This                A pointer to an instance of
155                               EFI_SMM_CONTROL_PROTOCOL
156   @param  ArgumentBuffer      The argument buffer
157   @param  ArgumentBufferSize  The size of the argument buffer
158   @param  Periodic            TRUE to indicate a periodical SMI
159   @param  ActivationInterval  Interval of the periodical SMI
160 
161   @retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1
162   @retval EFI_SUCCESS            SMI generated
163 
164 **/
165 EFI_STATUS
166 EFIAPI
Activate(IN CONST EFI_SMM_CONTROL2_PROTOCOL * This,IN OUT UINT8 * CommandPort OPTIONAL,IN OUT UINT8 * DataPort OPTIONAL,IN BOOLEAN Periodic OPTIONAL,IN EFI_SMM_PERIOD ActivationInterval OPTIONAL)167 Activate (
168   IN CONST EFI_SMM_CONTROL2_PROTOCOL     *This,
169   IN OUT  UINT8                          *CommandPort       OPTIONAL,
170   IN OUT  UINT8                          *DataPort          OPTIONAL,
171   IN      BOOLEAN                        Periodic           OPTIONAL,
172   IN      EFI_SMM_PERIOD                 ActivationInterval OPTIONAL
173   )
174 {
175   UINT16        GPE0BLK_Base;
176   UINT32        NewValue;
177 
178   //
179   // Get GPE0BLK_Base
180   //
181   GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);
182 
183   if (Periodic) {
184     return EFI_INVALID_PARAMETER;
185   }
186 
187   //
188   // Clear any pending the APM SMI
189   //
190   if (EFI_ERROR (SmmClear())) {
191     return EFI_DEVICE_ERROR;
192     }
193 
194   //
195   // Enable the APMC SMI
196   //
197   IoOr32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIE, B_QNC_GPE0BLK_SMIE_APM);
198 
199   //
200   // Enable SMI globally
201   //
202   NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
203   NewValue |= SMI_EN;
204   QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
205 
206 
207   //
208   // Set APMC_STS
209   //
210   if (DataPort == NULL) {
211     IoWrite8 (PcdGet16 (PcdSmmDataPort), 0xFF);
212   } else {
213     IoWrite8 (PcdGet16 (PcdSmmDataPort), *DataPort);
214   }
215 
216   //
217   // Generate the APMC SMI
218   //
219   if (CommandPort == NULL) {
220     IoWrite8 (PcdGet16 (PcdSmmActivationPort), 0xFF);
221   } else {
222     IoWrite8 (PcdGet16 (PcdSmmActivationPort), *CommandPort);
223   }
224 
225   return EFI_SUCCESS;
226 }
227 
228 /**
229   Clears an SMI.
230 
231   @param  This      Pointer to an instance of EFI_SMM_CONTROL_PROTOCOL
232   @param  Periodic  TRUE to indicate a periodical SMI
233 
234   @return Return value from SmmClear()
235 
236 **/
237 EFI_STATUS
238 EFIAPI
Deactivate(IN CONST EFI_SMM_CONTROL2_PROTOCOL * This,IN BOOLEAN Periodic)239 Deactivate (
240   IN CONST EFI_SMM_CONTROL2_PROTOCOL     *This,
241   IN      BOOLEAN                   Periodic
242   )
243 {
244   if (Periodic) {
245     return EFI_INVALID_PARAMETER;
246   }
247 
248   return SmmClear();
249 }
250 
251 /**
252   This is the constructor for the SMM Control protocol.
253 
254   This function installs EFI_SMM_CONTROL2_PROTOCOL.
255 
256   @param  ImageHandle Handle for the image of this driver
257   @param  SystemTable Pointer to the EFI System Table
258 
259   @retval EFI_UNSUPPORTED There's no Intel ICH on this platform
260   @return The status returned from InstallProtocolInterface().
261 
262 --*/
263 EFI_STATUS
SmmControl2Init(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)264 SmmControl2Init (
265   IN EFI_HANDLE        ImageHandle,
266   IN EFI_SYSTEM_TABLE  *SystemTable
267   )
268 {
269   EFI_STATUS  Status;
270   EFI_EVENT   Event;
271   UINT16      PM1BLK_Base;
272   UINT16      GPE0BLK_Base;
273   BOOLEAN     SciEn;
274   UINT32      NewValue;
275 
276   //
277   // Get PM1BLK_Base & GPE0BLK_Base
278   //
279   PM1BLK_Base  = PcdGet16 (PcdPm1blkIoBaseAddress);
280   GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);
281 
282   //
283   // Install our protocol interfaces on the device's handle
284   //
285   Status = gBS->InstallMultipleProtocolInterfaces (
286                   &mSmmControl2Handle,
287                   &gEfiSmmControl2ProtocolGuid,  &mSmmControl2,
288                   NULL
289                   );
290   ASSERT_EFI_ERROR (Status);
291 
292   //
293   // Determine whether an ACPI OS is present (via the SCI_EN bit)
294   //
295   SciEn = (BOOLEAN)((IoRead16 (PM1BLK_Base + R_QNC_PM1BLK_PM1C) & B_QNC_PM1BLK_PM1C_SCIEN) != 0);
296   if (!SciEn) {
297     //
298     // Clear any SMIs that double as SCIs (when SCI_EN==0)
299     //
300     IoWrite16 ((PM1BLK_Base + R_QNC_PM1BLK_PM1S), B_QNC_PM1BLK_PM1S_ALL);
301     IoWrite16 ((PM1BLK_Base + R_QNC_PM1BLK_PM1E), 0x00000000);
302     IoWrite32 ((PM1BLK_Base + R_QNC_PM1BLK_PM1C),  0x00000000);
303     IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_GPE0S), B_QNC_GPE0BLK_GPE0S_ALL);
304     IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_GPE0E), 0x00000000);
305   }
306 
307   //
308   // Clear and disable all SMIs that are unaffected by SCI_EN
309   // Set EOS
310   //
311   IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIE), 0x00000000);
312   IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), (B_QNC_GPE0BLK_SMIS_EOS + B_QNC_GPE0BLK_SMIS_ALL));
313 
314   //
315   // Enable SMI globally
316   //
317   NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
318   NewValue |= SMI_EN;
319   QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
320 
321   //
322   // Make sure to write this register last -- EOS re-enables SMIs for the QNC
323   //
324   IoAndThenOr32 (
325     GPE0BLK_Base + R_QNC_GPE0BLK_SMIE,
326     (UINT32)(~B_QNC_GPE0BLK_SMIE_ALL),
327     B_QNC_GPE0BLK_SMIE_APM
328     );
329 
330   //
331   // Make sure EOS bit cleared
332   //
333   DEBUG_CODE_BEGIN ();
334   if (IoRead32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS) & B_QNC_GPE0BLK_SMIS_EOS) {
335     DEBUG ((
336       EFI_D_ERROR,
337       "******************************************************************************\n"
338       "BIG ERROR: SmmControl constructor couldn't properly initialize the ACPI table.\n"
339       "           SmmControl->Clear will probably hang.                              \n"
340       "              NOTE: SCI_EN = %d                                               \n"
341       "******************************************************************************\n",
342       SciEn
343       ));
344 
345     //
346     // If we want the system to stop, then keep the ASSERT(FALSE).
347     // Otherwise, comment it out.
348     //
349     ASSERT (FALSE);
350   }
351   DEBUG_CODE_END ();
352 
353   Status = gBS->CreateEventEx (
354                 EVT_NOTIFY_SIGNAL,
355                 TPL_NOTIFY,
356                 SmmControlVirtualddressChangeEvent,
357                 NULL,
358                 &gEfiEventVirtualAddressChangeGuid,
359                 &Event
360                 );
361   ASSERT_EFI_ERROR (Status);
362 
363   return Status;
364 }
365