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