1 /** @file
2 
3 This driver is responsible for the registration of child drivers
4 and the abstraction of the QNC SMI sources.
5 
6 Copyright (c) 2013-2015 Intel Corporation.
7 
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution.  The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12 
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 
16 **/
17 
18 //
19 // Include common header file for this module.
20 //
21 #include "CommonHeader.h"
22 
23 #include "QNCSmmHelpers.h"
24 
25 //
26 // Help handle porting bit shifts to IA-64.
27 //
28 #define BIT_ZERO 0x00000001
29 
30 
31 VOID
QNCSmmPublishDispatchProtocols(VOID)32 QNCSmmPublishDispatchProtocols(
33   VOID
34   )
35 {
36   UINTN      Index;
37   EFI_STATUS Status;
38 
39   //
40   // Install protocol interfaces.
41   //
42   for (Index = 0; Index < NUM_PROTOCOLS; Index++) {
43     Status = gSmst->SmmInstallProtocolInterface (
44                  &mPrivateData.InstallMultProtHandle,
45                       mPrivateData.Protocols[Index].Guid,
46                       EFI_NATIVE_INTERFACE,
47                       &mPrivateData.Protocols[Index].Protocols.Generic
48                  );
49 
50   ASSERT_EFI_ERROR (Status);
51 }
52 }
53 
54 EFI_STATUS
QNCSmmInitHardware(VOID)55 QNCSmmInitHardware(
56   VOID
57   )
58 /*++
59 
60 Routine Description:
61 
62   Initialize bits that aren't necessarily related to an SMI source.
63 
64 Dependencies:
65 
66   gSmst - SMM System Table; contains an entry for SMM CPU IO
67 
68 Returns:
69 
70   EFI_SUCCESS.  Asserts, otherwise.
71 
72 --*/
73 {
74   EFI_STATUS Status;
75 
76   //
77   // Clear all SMIs
78   //
79   QNCSmmClearSmi();
80 
81   Status = QNCSmmEnableGlobalSmiBit ();
82   ASSERT_EFI_ERROR (Status);
83 
84   //
85   // Be *really* sure to clear all SMIs
86   //
87   QNCSmmClearSmi ();
88 
89   return EFI_SUCCESS;
90 }
91 
92 EFI_STATUS
QNCSmmEnableGlobalSmiBit(VOID)93 QNCSmmEnableGlobalSmiBit (
94   VOID
95   )
96 /*++
97 
98 Routine Description:
99 
100   Enables the QNC to generate SMIs. Note that no SMIs will be generated
101   if no SMI sources are enabled. Conversely, no enabled SMI source will
102   generate SMIs if SMIs are not globally enabled. This is the main
103   switchbox for SMI generation.
104 
105 Arguments:
106 
107   None
108 
109 Returns:
110 
111   EFI_SUCCESS.
112   Asserts, otherwise.
113 
114 --*/
115 {
116   UINT32        NewValue;
117 
118   //
119   // Enable SMI globally
120   //
121   NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
122   NewValue |= SMI_EN;
123   QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
124 
125   return EFI_SUCCESS;
126 }
127 
128 EFI_STATUS
QNCSmmClearSmi(VOID)129 QNCSmmClearSmi(
130   VOID
131   )
132 /*++
133 
134 Routine Description:
135 
136   Clears the SMI after all SMI source have been processed.
137   Note that this function will not work correctly (as it is
138   written) unless all SMI sources have been processed.
139   A revision of this function could manually clear all SMI
140   status bits to guarantee success.
141 
142 Returns:
143 
144   EFI_SUCCESS.
145   Asserts, otherwise.
146 
147 --*/
148 {
149   BOOLEAN EosSet;
150   BOOLEAN SciEn;
151 
152   UINT32 Pm1Cnt = 0;
153   UINT16 Pm1Sts = 0;
154   UINT32 Gpe0Sts = 0;
155   UINT32 SmiSts  = 0;
156 
157   //
158   // Determine whether an ACPI OS is present (via the SCI_EN bit)
159   //
160   Pm1Cnt = IoRead32(PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
161   SciEn = (BOOLEAN)((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == B_QNC_PM1BLK_PM1C_SCIEN);
162 
163   if (SciEn == FALSE) {
164 
165     //
166     // Clear any SMIs that double as SCIs (when SCI_EN==0)
167     //
168     Pm1Sts = (B_QNC_PM1BLK_PM1S_WAKE | B_QNC_PM1BLK_PM1S_PCIEWSTS | B_QNC_PM1BLK_PM1S_RTC | B_QNC_PM1BLK_PM1S_GLOB | B_QNC_PM1BLK_PM1S_TO);
169 
170     Gpe0Sts = B_QNC_GPE0BLK_GPE0S_ALL;
171 
172     IoOr16((PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S), Pm1Sts);
173     IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S), Gpe0Sts);
174   }
175 
176   //
177   // Clear all SMIs that are unaffected by SCI_EN
178   //
179   SmiSts = IoRead32((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS);
180   SmiSts |= B_QNC_GPE0BLK_SMIS_ALL;
181   IoWrite32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS), SmiSts);
182 
183   //
184   // Try to clear the EOS bit. ASSERT on an error
185   //
186   EosSet = QNCSmmSetAndCheckEos();
187   ASSERT (EosSet);
188 
189   return EFI_SUCCESS;
190 }
191 
192 BOOLEAN
QNCSmmSetAndCheckEos(VOID)193 QNCSmmSetAndCheckEos(
194   VOID
195   )
196 {
197   //
198   // Reset the QNC to generate subsequent SMIs
199   //
200   IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);
201     return TRUE;
202 }
203 
204 BOOLEAN
QNCSmmGetSciEn()205 QNCSmmGetSciEn(
206   )
207 {
208   BOOLEAN SciEn;
209   UINT32 Pm1Cnt;
210 
211   //
212   // Determine whether an ACPI OS is present (via the SCI_EN bit)
213   //
214   Pm1Cnt = IoRead32(PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
215 
216   SciEn = (BOOLEAN)((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == B_QNC_PM1BLK_PM1C_SCIEN);
217 
218   return SciEn;
219 }
220 
221 //
222 // These may or may not need to change w/ the QNC version; they're highly IA-32 dependent, though.
223 //
224 
225 BOOLEAN
ReadBitDesc(CONST QNC_SMM_BIT_DESC * BitDesc)226 ReadBitDesc (
227   CONST QNC_SMM_BIT_DESC  *BitDesc
228   )
229 {
230   UINT64           Register;
231   UINT32           PciBus;
232   UINT32           PciDev;
233   UINT32           PciFun;
234   UINT32           PciReg;
235   BOOLEAN          BitWasOne;
236 
237   ASSERT (BitDesc != NULL );
238   ASSERT (!IS_BIT_DESC_NULL( *BitDesc ) );
239 
240   Register  = 0;
241   BitWasOne = FALSE;
242 
243   switch (BitDesc->Reg.Type) {
244 
245   case ACPI_ADDR_TYPE:
246     //
247     // Double check that we correctly read in the acpi base address
248     //
249     ASSERT ((PcdGet16 (PcdPm1blkIoBaseAddress) != 0x0) && ((PcdGet16 (PcdPm1blkIoBaseAddress) & 0x1) != 0x1) );
250 
251     switch (BitDesc->SizeInBytes) {
252 
253     case 0:
254       //
255       // Chances are that this field didn't get initialized.
256       // Check your assignments to bit descriptions.
257       //
258       ASSERT (FALSE );
259       break;
260 
261       case 1:
262       Register = (UINT64) IoRead8 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);
263         break;
264 
265       case 2:
266       Register = (UINT64) IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);
267         break;
268 
269       case 4:
270       Register = (UINT64) IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);
271         break;
272 
273       default:
274         //
275         // Unsupported or invalid register size
276         //
277         ASSERT (FALSE );
278         break;
279       };
280 
281     if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {
282         BitWasOne = TRUE;
283       } else {
284         BitWasOne = FALSE;
285       }
286     break;
287 
288   case GPE_ADDR_TYPE:
289       //
290     // Double check that we correctly read in the gpe base address
291       //
292     ASSERT (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) != 0x0) && (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) & 0x1) != 0x1) );
293 
294     switch (BitDesc->SizeInBytes) {
295 
296     case 0:
297       //
298       // Chances are that this field didn't get initialized.
299       // Check your assignments to bit descriptions.
300       //
301       ASSERT (FALSE );
302       break;
303 
304     case 1:
305       Register = (UINT64) IoRead8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);
306       break;
307 
308     case 2:
309       Register = (UINT64) IoRead16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);
310       break;
311 
312     case 4:
313       Register = (UINT64) IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);
314       break;
315 
316     default:
317       //
318       // Unsupported or invalid register size
319       //
320       ASSERT (FALSE );
321       break;
322     };
323 
324     if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {
325         BitWasOne = TRUE;
326       } else {
327         BitWasOne = FALSE;
328       }
329     break;
330 
331   case MEMORY_MAPPED_IO_ADDRESS_TYPE:
332     //
333     // Read the register, and it with the bit to read
334     //
335 
336     //
337     // This code does not support reads greater then 64 bits
338     //
339     ASSERT (BitDesc->SizeInBytes <= 8);
340     CopyMem (&Register, BitDesc->Reg.Data.Mmio, BitDesc->SizeInBytes);
341     Register &= LShiftU64 (BIT0, BitDesc->Bit);
342     if (Register) {
343       BitWasOne = TRUE;
344     } else {
345       BitWasOne = FALSE;
346     }
347     break;
348 
349   case PCI_ADDR_TYPE:
350     PciBus = BitDesc->Reg.Data.pci.Fields.Bus;
351     PciDev = BitDesc->Reg.Data.pci.Fields.Dev;
352     PciFun = BitDesc->Reg.Data.pci.Fields.Fnc;
353     PciReg = BitDesc->Reg.Data.pci.Fields.Reg;
354     switch (BitDesc->SizeInBytes) {
355 
356     case 0:
357       //
358       // Chances are that this field didn't get initialized.
359       // Check your assignments to bit descriptions.
360       ASSERT (FALSE );
361       break;
362 
363     case 1:
364       Register = (UINT64) PciRead8 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));
365       break;
366 
367     case 2:
368       Register = (UINT64) PciRead16 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));
369       break;
370 
371     case 4:
372       Register = (UINT64) PciRead32 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));
373       break;
374 
375     default:
376       //
377       // Unsupported or invalid register size
378       //
379       ASSERT (FALSE );
380       break;
381     };
382 
383     if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {
384         BitWasOne = TRUE;
385     } else {
386       BitWasOne = FALSE;
387     }
388     break;
389 
390   default:
391     //
392     // This address type is not yet implemented
393     //
394     ASSERT (FALSE );
395     break;
396   };
397 
398   return BitWasOne;
399 }
400 
401 VOID
WriteBitDesc(CONST QNC_SMM_BIT_DESC * BitDesc,CONST BOOLEAN ValueToWrite)402 WriteBitDesc (
403   CONST QNC_SMM_BIT_DESC   *BitDesc,
404   CONST BOOLEAN           ValueToWrite
405   )
406 {
407   UINT64           Register;
408   UINT64           AndVal;
409   UINT64           OrVal;
410   UINT32           PciBus;
411   UINT32           PciDev;
412   UINT32           PciFun;
413   UINT32           PciReg;
414 
415   ASSERT (BitDesc != NULL);
416   ASSERT (!IS_BIT_DESC_NULL(*BitDesc));
417 
418   AndVal = ~(BIT_ZERO << (BitDesc->Bit));
419   OrVal  = ((UINT32)ValueToWrite) << (BitDesc->Bit);
420 
421   switch (BitDesc->Reg.Type) {
422 
423   case ACPI_ADDR_TYPE:
424     //
425     // Double check that we correctly read in the acpi base address
426     //
427     ASSERT ((PcdGet16 (PcdPm1blkIoBaseAddress) != 0x0) && ((PcdGet16 (PcdPm1blkIoBaseAddress) & 0x1) != 0x1));
428 
429     switch (BitDesc->SizeInBytes) {
430 
431     case 0:
432       //
433       // Chances are that this field didn't get initialized.
434       // Check your assignments to bit descriptions.
435       //
436       ASSERT (FALSE );
437       break;
438 
439     case 1:
440       IoAndThenOr8 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT8)AndVal, (UINT8)OrVal);
441       break;
442 
443     case 2:
444       IoAndThenOr16 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT16)AndVal, (UINT16)OrVal);
445       break;
446 
447     case 4:
448       IoAndThenOr32 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT32)AndVal, (UINT32)OrVal);
449       break;
450 
451     default:
452       //
453       // Unsupported or invalid register size
454       //
455       ASSERT (FALSE );
456       break;
457     };
458     break;
459 
460   case GPE_ADDR_TYPE:
461     //
462     // Double check that we correctly read in the gpe base address
463     //
464     ASSERT (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) != 0x0) && (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) & 0x1) != 0x1));
465 
466     switch (BitDesc->SizeInBytes) {
467 
468     case 0:
469       //
470       // Chances are that this field didn't get initialized.
471       // Check your assignments to bit descriptions.
472       //
473       ASSERT (FALSE );
474       break;
475 
476     case 1:
477       IoAndThenOr8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT8)AndVal, (UINT8)OrVal);
478       break;
479 
480     case 2:
481       IoAndThenOr16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT16)AndVal, (UINT16)OrVal);
482       break;
483 
484     case 4:
485       IoAndThenOr32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT32)AndVal, (UINT32)OrVal);
486       break;
487 
488     default:
489       //
490       // Unsupported or invalid register size
491       //
492       ASSERT (FALSE );
493       break;
494     };
495       break;
496 
497   case MEMORY_MAPPED_IO_ADDRESS_TYPE:
498     //
499     // Read the register, or it with the bit to set, then write it back.
500     //
501 
502     //
503     // This code does not support writes greater then 64 bits
504     //
505     ASSERT (BitDesc->SizeInBytes <= 8);
506     CopyMem (&Register, BitDesc->Reg.Data.Mmio, BitDesc->SizeInBytes);
507     Register &= AndVal;
508     Register |= OrVal;
509     CopyMem (BitDesc->Reg.Data.Mmio, &Register, BitDesc->SizeInBytes);
510     break;
511 
512   case PCI_ADDR_TYPE:
513     PciBus = BitDesc->Reg.Data.pci.Fields.Bus;
514     PciDev = BitDesc->Reg.Data.pci.Fields.Dev;
515     PciFun = BitDesc->Reg.Data.pci.Fields.Fnc;
516     PciReg = BitDesc->Reg.Data.pci.Fields.Reg;
517     switch (BitDesc->SizeInBytes) {
518 
519     case 0:
520       //
521       // Chances are that this field didn't get initialized -- check your assignments
522       // to bit descriptions.
523       //
524       ASSERT (FALSE );
525       break;
526 
527     case 1:
528       PciAndThenOr8 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT8) AndVal, (UINT8) OrVal);
529       break;
530 
531     case 2:
532       PciAndThenOr16 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT16) AndVal, (UINT16) OrVal);
533       break;
534 
535     case 4:
536       PciAndThenOr32 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT32) AndVal, (UINT32) OrVal);
537       break;
538 
539     default:
540       //
541       // Unsupported or invalid register size
542       //
543       ASSERT (FALSE );
544       break;
545     };
546     break;
547 
548     default:
549     //
550     // This address type is not yet implemented
551     //
552     ASSERT (FALSE );
553     break;
554   };
555 }
556