+++ /dev/null
-/** @file\r
-\r
-This driver is responsible for the registration of child drivers\r
-and the abstraction of the QNC SMI sources.\r
-\r
-Copyright (c) 2013-2015 Intel Corporation.\r
-\r
-SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-//\r
-// Include common header file for this module.\r
-//\r
-#include "CommonHeader.h"\r
-\r
-#include "QNCSmmHelpers.h"\r
-\r
-//\r
-// Help handle porting bit shifts to IA-64.\r
-//\r
-#define BIT_ZERO 0x00000001\r
-\r
-\r
-VOID\r
-QNCSmmPublishDispatchProtocols(\r
- VOID\r
- )\r
-{\r
- UINTN Index;\r
- EFI_STATUS Status;\r
-\r
- //\r
- // Install protocol interfaces.\r
- //\r
- for (Index = 0; Index < NUM_PROTOCOLS; Index++) {\r
- Status = gSmst->SmmInstallProtocolInterface (\r
- &mPrivateData.InstallMultProtHandle,\r
- mPrivateData.Protocols[Index].Guid,\r
- EFI_NATIVE_INTERFACE,\r
- &mPrivateData.Protocols[Index].Protocols.Generic\r
- );\r
-\r
- ASSERT_EFI_ERROR (Status);\r
-}\r
-}\r
-\r
-EFI_STATUS\r
-QNCSmmInitHardware(\r
- VOID\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Initialize bits that aren't necessarily related to an SMI source.\r
-\r
-Dependencies:\r
-\r
- gSmst - SMM System Table; contains an entry for SMM CPU IO\r
-\r
-Returns:\r
-\r
- EFI_SUCCESS. Asserts, otherwise.\r
-\r
---*/\r
-{\r
- EFI_STATUS Status;\r
-\r
- //\r
- // Clear all SMIs\r
- //\r
- QNCSmmClearSmi();\r
-\r
- Status = QNCSmmEnableGlobalSmiBit ();\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- //\r
- // Be *really* sure to clear all SMIs\r
- //\r
- QNCSmmClearSmi ();\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-QNCSmmEnableGlobalSmiBit (\r
- VOID\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Enables the QNC to generate SMIs. Note that no SMIs will be generated\r
- if no SMI sources are enabled. Conversely, no enabled SMI source will\r
- generate SMIs if SMIs are not globally enabled. This is the main\r
- switchbox for SMI generation.\r
-\r
-Arguments:\r
-\r
- None\r
-\r
-Returns:\r
-\r
- EFI_SUCCESS.\r
- Asserts, otherwise.\r
-\r
---*/\r
-{\r
- UINT32 NewValue;\r
-\r
- //\r
- // Enable SMI globally\r
- //\r
- NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);\r
- NewValue |= SMI_EN;\r
- QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-QNCSmmClearSmi(\r
- VOID\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Clears the SMI after all SMI source have been processed.\r
- Note that this function will not work correctly (as it is\r
- written) unless all SMI sources have been processed.\r
- A revision of this function could manually clear all SMI\r
- status bits to guarantee success.\r
-\r
-Returns:\r
-\r
- EFI_SUCCESS.\r
- Asserts, otherwise.\r
-\r
---*/\r
-{\r
- BOOLEAN EosSet;\r
- BOOLEAN SciEn;\r
-\r
- UINT32 Pm1Cnt = 0;\r
- UINT16 Pm1Sts = 0;\r
- UINT32 Gpe0Sts = 0;\r
- UINT32 SmiSts = 0;\r
-\r
- //\r
- // Determine whether an ACPI OS is present (via the SCI_EN bit)\r
- //\r
- Pm1Cnt = IoRead32(PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);\r
- SciEn = (BOOLEAN)((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == B_QNC_PM1BLK_PM1C_SCIEN);\r
-\r
- if (SciEn == FALSE) {\r
-\r
- //\r
- // Clear any SMIs that double as SCIs (when SCI_EN==0)\r
- //\r
- 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
-\r
- Gpe0Sts = B_QNC_GPE0BLK_GPE0S_ALL;\r
-\r
- IoOr16((PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S), Pm1Sts);\r
- IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S), Gpe0Sts);\r
- }\r
-\r
- //\r
- // Clear all SMIs that are unaffected by SCI_EN\r
- //\r
- SmiSts = IoRead32((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS);\r
- SmiSts |= B_QNC_GPE0BLK_SMIS_ALL;\r
- IoWrite32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS), SmiSts);\r
-\r
- //\r
- // Try to clear the EOS bit. ASSERT on an error\r
- //\r
- EosSet = QNCSmmSetAndCheckEos();\r
- ASSERT (EosSet);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-BOOLEAN\r
-QNCSmmSetAndCheckEos(\r
- VOID\r
- )\r
-{\r
- //\r
- // Reset the QNC to generate subsequent SMIs\r
- //\r
- IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);\r
- return TRUE;\r
-}\r
-\r
-BOOLEAN\r
-QNCSmmGetSciEn(\r
- )\r
-{\r
- BOOLEAN SciEn;\r
- UINT32 Pm1Cnt;\r
-\r
- //\r
- // Determine whether an ACPI OS is present (via the SCI_EN bit)\r
- //\r
- Pm1Cnt = IoRead32(PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);\r
-\r
- SciEn = (BOOLEAN)((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == B_QNC_PM1BLK_PM1C_SCIEN);\r
-\r
- return SciEn;\r
-}\r
-\r
-//\r
-// These may or may not need to change w/ the QNC version; they're highly IA-32 dependent, though.\r
-//\r
-\r
-BOOLEAN\r
-ReadBitDesc (\r
- CONST QNC_SMM_BIT_DESC *BitDesc\r
- )\r
-{\r
- UINT64 Register;\r
- UINT32 PciBus;\r
- UINT32 PciDev;\r
- UINT32 PciFun;\r
- UINT32 PciReg;\r
- BOOLEAN BitWasOne;\r
-\r
- ASSERT (BitDesc != NULL );\r
- ASSERT (!IS_BIT_DESC_NULL( *BitDesc ) );\r
-\r
- Register = 0;\r
- BitWasOne = FALSE;\r
-\r
- switch (BitDesc->Reg.Type) {\r
-\r
- case ACPI_ADDR_TYPE:\r
- //\r
- // Double check that we correctly read in the acpi base address\r
- //\r
- ASSERT ((PcdGet16 (PcdPm1blkIoBaseAddress) != 0x0) && ((PcdGet16 (PcdPm1blkIoBaseAddress) & 0x1) != 0x1) );\r
-\r
- switch (BitDesc->SizeInBytes) {\r
-\r
- case 0:\r
- //\r
- // Chances are that this field didn't get initialized.\r
- // Check your assignments to bit descriptions.\r
- //\r
- ASSERT (FALSE );\r
- break;\r
-\r
- case 1:\r
- Register = (UINT64) IoRead8 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);\r
- break;\r
-\r
- case 2:\r
- Register = (UINT64) IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);\r
- break;\r
-\r
- case 4:\r
- Register = (UINT64) IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);\r
- break;\r
-\r
- default:\r
- //\r
- // Unsupported or invalid register size\r
- //\r
- ASSERT (FALSE );\r
- break;\r
- };\r
-\r
- if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {\r
- BitWasOne = TRUE;\r
- } else {\r
- BitWasOne = FALSE;\r
- }\r
- break;\r
-\r
- case GPE_ADDR_TYPE:\r
- //\r
- // Double check that we correctly read in the gpe base address\r
- //\r
- ASSERT (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) != 0x0) && (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) & 0x1) != 0x1) );\r
-\r
- switch (BitDesc->SizeInBytes) {\r
-\r
- case 0:\r
- //\r
- // Chances are that this field didn't get initialized.\r
- // Check your assignments to bit descriptions.\r
- //\r
- ASSERT (FALSE );\r
- break;\r
-\r
- case 1:\r
- Register = (UINT64) IoRead8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);\r
- break;\r
-\r
- case 2:\r
- Register = (UINT64) IoRead16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);\r
- break;\r
-\r
- case 4:\r
- Register = (UINT64) IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);\r
- break;\r
-\r
- default:\r
- //\r
- // Unsupported or invalid register size\r
- //\r
- ASSERT (FALSE );\r
- break;\r
- };\r
-\r
- if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {\r
- BitWasOne = TRUE;\r
- } else {\r
- BitWasOne = FALSE;\r
- }\r
- break;\r
-\r
- case MEMORY_MAPPED_IO_ADDRESS_TYPE:\r
- //\r
- // Read the register, and it with the bit to read\r
- //\r
-\r
- //\r
- // This code does not support reads greater then 64 bits\r
- //\r
- ASSERT (BitDesc->SizeInBytes <= 8);\r
- CopyMem (&Register, BitDesc->Reg.Data.Mmio, BitDesc->SizeInBytes);\r
- Register &= LShiftU64 (BIT0, BitDesc->Bit);\r
- if (Register) {\r
- BitWasOne = TRUE;\r
- } else {\r
- BitWasOne = FALSE;\r
- }\r
- break;\r
-\r
- case PCI_ADDR_TYPE:\r
- PciBus = BitDesc->Reg.Data.pci.Fields.Bus;\r
- PciDev = BitDesc->Reg.Data.pci.Fields.Dev;\r
- PciFun = BitDesc->Reg.Data.pci.Fields.Fnc;\r
- PciReg = BitDesc->Reg.Data.pci.Fields.Reg;\r
- switch (BitDesc->SizeInBytes) {\r
-\r
- case 0:\r
- //\r
- // Chances are that this field didn't get initialized.\r
- // Check your assignments to bit descriptions.\r
- ASSERT (FALSE );\r
- break;\r
-\r
- case 1:\r
- Register = (UINT64) PciRead8 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));\r
- break;\r
-\r
- case 2:\r
- Register = (UINT64) PciRead16 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));\r
- break;\r
-\r
- case 4:\r
- Register = (UINT64) PciRead32 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));\r
- break;\r
-\r
- default:\r
- //\r
- // Unsupported or invalid register size\r
- //\r
- ASSERT (FALSE );\r
- break;\r
- };\r
-\r
- if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {\r
- BitWasOne = TRUE;\r
- } else {\r
- BitWasOne = FALSE;\r
- }\r
- break;\r
-\r
- default:\r
- //\r
- // This address type is not yet implemented\r
- //\r
- ASSERT (FALSE );\r
- break;\r
- };\r
-\r
- return BitWasOne;\r
-}\r
-\r
-VOID\r
-WriteBitDesc (\r
- CONST QNC_SMM_BIT_DESC *BitDesc,\r
- CONST BOOLEAN ValueToWrite\r
- )\r
-{\r
- UINT64 Register;\r
- UINT64 AndVal;\r
- UINT64 OrVal;\r
- UINT32 PciBus;\r
- UINT32 PciDev;\r
- UINT32 PciFun;\r
- UINT32 PciReg;\r
-\r
- ASSERT (BitDesc != NULL);\r
- ASSERT (!IS_BIT_DESC_NULL(*BitDesc));\r
-\r
- AndVal = ~(BIT_ZERO << (BitDesc->Bit));\r
- OrVal = ((UINT32)ValueToWrite) << (BitDesc->Bit);\r
-\r
- switch (BitDesc->Reg.Type) {\r
-\r
- case ACPI_ADDR_TYPE:\r
- //\r
- // Double check that we correctly read in the acpi base address\r
- //\r
- ASSERT ((PcdGet16 (PcdPm1blkIoBaseAddress) != 0x0) && ((PcdGet16 (PcdPm1blkIoBaseAddress) & 0x1) != 0x1));\r
-\r
- switch (BitDesc->SizeInBytes) {\r
-\r
- case 0:\r
- //\r
- // Chances are that this field didn't get initialized.\r
- // Check your assignments to bit descriptions.\r
- //\r
- ASSERT (FALSE );\r
- break;\r
-\r
- case 1:\r
- IoAndThenOr8 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT8)AndVal, (UINT8)OrVal);\r
- break;\r
-\r
- case 2:\r
- IoAndThenOr16 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT16)AndVal, (UINT16)OrVal);\r
- break;\r
-\r
- case 4:\r
- IoAndThenOr32 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT32)AndVal, (UINT32)OrVal);\r
- break;\r
-\r
- default:\r
- //\r
- // Unsupported or invalid register size\r
- //\r
- ASSERT (FALSE );\r
- break;\r
- };\r
- break;\r
-\r
- case GPE_ADDR_TYPE:\r
- //\r
- // Double check that we correctly read in the gpe base address\r
- //\r
- ASSERT (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) != 0x0) && (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) & 0x1) != 0x1));\r
-\r
- switch (BitDesc->SizeInBytes) {\r
-\r
- case 0:\r
- //\r
- // Chances are that this field didn't get initialized.\r
- // Check your assignments to bit descriptions.\r
- //\r
- ASSERT (FALSE );\r
- break;\r
-\r
- case 1:\r
- IoAndThenOr8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT8)AndVal, (UINT8)OrVal);\r
- break;\r
-\r
- case 2:\r
- IoAndThenOr16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT16)AndVal, (UINT16)OrVal);\r
- break;\r
-\r
- case 4:\r
- IoAndThenOr32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT32)AndVal, (UINT32)OrVal);\r
- break;\r
-\r
- default:\r
- //\r
- // Unsupported or invalid register size\r
- //\r
- ASSERT (FALSE );\r
- break;\r
- };\r
- break;\r
-\r
- case MEMORY_MAPPED_IO_ADDRESS_TYPE:\r
- //\r
- // Read the register, or it with the bit to set, then write it back.\r
- //\r
-\r
- //\r
- // This code does not support writes greater then 64 bits\r
- //\r
- ASSERT (BitDesc->SizeInBytes <= 8);\r
- CopyMem (&Register, BitDesc->Reg.Data.Mmio, BitDesc->SizeInBytes);\r
- Register &= AndVal;\r
- Register |= OrVal;\r
- CopyMem (BitDesc->Reg.Data.Mmio, &Register, BitDesc->SizeInBytes);\r
- break;\r
-\r
- case PCI_ADDR_TYPE:\r
- PciBus = BitDesc->Reg.Data.pci.Fields.Bus;\r
- PciDev = BitDesc->Reg.Data.pci.Fields.Dev;\r
- PciFun = BitDesc->Reg.Data.pci.Fields.Fnc;\r
- PciReg = BitDesc->Reg.Data.pci.Fields.Reg;\r
- switch (BitDesc->SizeInBytes) {\r
-\r
- case 0:\r
- //\r
- // Chances are that this field didn't get initialized -- check your assignments\r
- // to bit descriptions.\r
- //\r
- ASSERT (FALSE );\r
- break;\r
-\r
- case 1:\r
- PciAndThenOr8 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT8) AndVal, (UINT8) OrVal);\r
- break;\r
-\r
- case 2:\r
- PciAndThenOr16 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT16) AndVal, (UINT16) OrVal);\r
- break;\r
-\r
- case 4:\r
- PciAndThenOr32 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT32) AndVal, (UINT32) OrVal);\r
- break;\r
-\r
- default:\r
- //\r
- // Unsupported or invalid register size\r
- //\r
- ASSERT (FALSE );\r
- break;\r
- };\r
- break;\r
-\r
- default:\r
- //\r
- // This address type is not yet implemented\r
- //\r
- ASSERT (FALSE );\r
- break;\r
- };\r
-}\r