]> git.proxmox.com Git - mirror_edk2.git/blobdiff - QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmHelpers.c
QuarkSocPkg: Add new package for Quark SoC X1000
[mirror_edk2.git] / QuarkSocPkg / QuarkNorthCluster / Smm / DxeSmm / QncSmmDispatcher / QNC / QNCSmmHelpers.c
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmHelpers.c b/QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNC/QNCSmmHelpers.c
new file mode 100644 (file)
index 0000000..9784359
--- /dev/null
@@ -0,0 +1,555 @@
+/** @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
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\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