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