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