]> git.proxmox.com Git - mirror_edk2.git/blobdiff - QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c
QuarkSocPkg: Add new package for Quark SoC X1000
[mirror_edk2.git] / QuarkSocPkg / QuarkNorthCluster / Smm / Dxe / SmmControlDxe / SmmControlDriver.c
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c b/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c
new file mode 100644 (file)
index 0000000..72ba797
--- /dev/null
@@ -0,0 +1,366 @@
+/** @file\r
+This module produces the SMM COntrol2 Protocol for QNC\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
+#include <PiDxe.h>\r
+#include <Protocol/SmmControl2.h>\r
+#include <IndustryStandard/Pci.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/PciLib.h>\r
+#include <IntelQNCDxe.h>\r
+#include <Library/QNCAccessLib.h>\r
+#include <Uefi/UefiBaseType.h>\r
+\r
+#define EFI_INTERNAL_POINTER  0x00000004\r
+\r
+extern EFI_GUID gEfiEventVirtualAddressChangeGuid;\r
+\r
+/**\r
+  Generates an SMI using the parameters passed in.\r
+\r
+  @param  This                A pointer to an instance of\r
+                              EFI_SMM_CONTROL2_PROTOCOL\r
+  @param  ArgumentBuffer      The argument buffer\r
+  @param  ArgumentBufferSize  The size of the argument buffer\r
+  @param  Periodic            TRUE to indicate a periodical SMI\r
+  @param  ActivationInterval  Interval of the periodical SMI\r
+\r
+  @retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1\r
+  @return Return value from SmmTrigger().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Activate (\r
+  IN CONST EFI_SMM_CONTROL2_PROTOCOL     *This,\r
+  IN OUT  UINT8                          *CommandPort       OPTIONAL,\r
+  IN OUT  UINT8                          *DataPort          OPTIONAL,\r
+  IN      BOOLEAN                        Periodic           OPTIONAL,\r
+  IN      EFI_SMM_PERIOD                 ActivationInterval OPTIONAL\r
+                  );\r
+\r
+/**\r
+  Clears an SMI.\r
+\r
+  @param  This      Pointer to an instance of EFI_SMM_CONTROL2_PROTOCOL\r
+  @param  Periodic  TRUE to indicate a periodical SMI\r
+\r
+  @return Return value from SmmClear()\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Deactivate (\r
+  IN CONST     EFI_SMM_CONTROL2_PROTOCOL  *This,\r
+  IN      BOOLEAN                         Periodic OPTIONAL\r
+  );\r
+\r
+///\r
+/// Handle for the SMM Control2 Protocol\r
+///\r
+EFI_HANDLE  mSmmControl2Handle = NULL;\r
+\r
+///\r
+/// SMM COntrol2 Protocol instance\r
+///\r
+EFI_SMM_CONTROL2_PROTOCOL mSmmControl2 = {\r
+  Activate,\r
+  Deactivate,\r
+  0\r
+};\r
+\r
+VOID\r
+EFIAPI\r
+SmmControlVirtualddressChangeEvent (\r
+  IN EFI_EVENT                  Event,\r
+  IN VOID                       *Context\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Fixup internal data pointers so that the services can be called in virtual mode.\r
+\r
+Arguments:\r
+\r
+  Event                         The event registered.\r
+  Context                       Event context.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSmmControl2.Trigger));\r
+  gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSmmControl2.Clear));\r
+}\r
+\r
+/**\r
+  Clear SMI related chipset status and re-enable SMI by setting the EOS bit.\r
+\r
+  @retval EFI_SUCCESS The requested operation has been carried out successfully\r
+  @retval EFI_DEVICE_ERROR  The EOS bit could not be set.\r
+\r
+**/\r
+EFI_STATUS\r
+SmmClear (\r
+  VOID\r
+  )\r
+{\r
+  UINT16                       PM1BLK_Base;\r
+  UINT16                       GPE0BLK_Base;\r
+\r
+  //\r
+  // Get PM1BLK_Base & GPE0BLK_Base\r
+  //\r
+  PM1BLK_Base  = PcdGet16 (PcdPm1blkIoBaseAddress);\r
+  GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);\r
+\r
+  //\r
+  // Clear the Power Button Override Status Bit, it gates EOS from being set.\r
+  // In QuarkNcSocId - Bit is read only. Handled by external SMC, do nothing.\r
+  //\r
+\r
+  //\r
+  // Clear the APM SMI Status Bit\r
+  //\r
+  IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM);\r
+\r
+  //\r
+  // Set the EOS Bit\r
+  //\r
+  IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Generates an SMI using the parameters passed in.\r
+\r
+  @param  This                A pointer to an instance of\r
+                              EFI_SMM_CONTROL_PROTOCOL\r
+  @param  ArgumentBuffer      The argument buffer\r
+  @param  ArgumentBufferSize  The size of the argument buffer\r
+  @param  Periodic            TRUE to indicate a periodical SMI\r
+  @param  ActivationInterval  Interval of the periodical SMI\r
+\r
+  @retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1\r
+  @retval EFI_SUCCESS            SMI generated\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Activate (\r
+  IN CONST EFI_SMM_CONTROL2_PROTOCOL     *This,\r
+  IN OUT  UINT8                          *CommandPort       OPTIONAL,\r
+  IN OUT  UINT8                          *DataPort          OPTIONAL,\r
+  IN      BOOLEAN                        Periodic           OPTIONAL,\r
+  IN      EFI_SMM_PERIOD                 ActivationInterval OPTIONAL\r
+  )\r
+{\r
+  UINT16        GPE0BLK_Base;\r
+  UINT32        NewValue;\r
+\r
+  //\r
+  // Get GPE0BLK_Base\r
+  //\r
+  GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);\r
+\r
+  if (Periodic) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Clear any pending the APM SMI\r
+  //\r
+  if (EFI_ERROR (SmmClear())) {\r
+    return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+  //\r
+  // Enable the APMC SMI\r
+  //\r
+  IoOr32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIE, B_QNC_GPE0BLK_SMIE_APM);\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
+\r
+  //\r
+  // Set APMC_STS\r
+  //\r
+  if (DataPort == NULL) {\r
+    IoWrite8 (PcdGet16 (PcdSmmDataPort), 0xFF);\r
+  } else {\r
+    IoWrite8 (PcdGet16 (PcdSmmDataPort), *DataPort);\r
+  }\r
+\r
+  //\r
+  // Generate the APMC SMI\r
+  //\r
+  if (CommandPort == NULL) {\r
+    IoWrite8 (PcdGet16 (PcdSmmActivationPort), 0xFF);\r
+  } else {\r
+    IoWrite8 (PcdGet16 (PcdSmmActivationPort), *CommandPort);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Clears an SMI.\r
+\r
+  @param  This      Pointer to an instance of EFI_SMM_CONTROL_PROTOCOL\r
+  @param  Periodic  TRUE to indicate a periodical SMI\r
+\r
+  @return Return value from SmmClear()\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Deactivate (\r
+  IN CONST EFI_SMM_CONTROL2_PROTOCOL     *This,\r
+  IN      BOOLEAN                   Periodic\r
+  )\r
+{\r
+  if (Periodic) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return SmmClear();\r
+}\r
+\r
+/**\r
+  This is the constructor for the SMM Control protocol.\r
+\r
+  This function installs EFI_SMM_CONTROL2_PROTOCOL.\r
+\r
+  @param  ImageHandle Handle for the image of this driver\r
+  @param  SystemTable Pointer to the EFI System Table\r
+\r
+  @retval EFI_UNSUPPORTED There's no Intel ICH on this platform\r
+  @return The status returned from InstallProtocolInterface().\r
+\r
+--*/\r
+EFI_STATUS\r
+SmmControl2Init (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  EFI_EVENT   Event;\r
+  UINT16      PM1BLK_Base;\r
+  UINT16      GPE0BLK_Base;\r
+  BOOLEAN     SciEn;\r
+  UINT32      NewValue;\r
+\r
+  //\r
+  // Get PM1BLK_Base & GPE0BLK_Base\r
+  //\r
+  PM1BLK_Base  = PcdGet16 (PcdPm1blkIoBaseAddress);\r
+  GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);\r
+\r
+  //\r
+  // Install our protocol interfaces on the device's handle\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &mSmmControl2Handle,\r
+                  &gEfiSmmControl2ProtocolGuid,  &mSmmControl2,\r
+                  NULL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Determine whether an ACPI OS is present (via the SCI_EN bit)\r
+  //\r
+  SciEn = (BOOLEAN)((IoRead16 (PM1BLK_Base + R_QNC_PM1BLK_PM1C) & B_QNC_PM1BLK_PM1C_SCIEN) != 0);\r
+  if (!SciEn) {\r
+    //\r
+    // Clear any SMIs that double as SCIs (when SCI_EN==0)\r
+    //\r
+    IoWrite16 ((PM1BLK_Base + R_QNC_PM1BLK_PM1S), B_QNC_PM1BLK_PM1S_ALL);\r
+    IoWrite16 ((PM1BLK_Base + R_QNC_PM1BLK_PM1E), 0x00000000);\r
+    IoWrite32 ((PM1BLK_Base + R_QNC_PM1BLK_PM1C),  0x00000000);\r
+    IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_GPE0S), B_QNC_GPE0BLK_GPE0S_ALL);\r
+    IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_GPE0E), 0x00000000);\r
+  }\r
+\r
+  //\r
+  // Clear and disable all SMIs that are unaffected by SCI_EN\r
+  // Set EOS\r
+  //\r
+  IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIE), 0x00000000);\r
+  IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), (B_QNC_GPE0BLK_SMIS_EOS + B_QNC_GPE0BLK_SMIS_ALL));\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
+  //\r
+  // Make sure to write this register last -- EOS re-enables SMIs for the QNC\r
+  //\r
+  IoAndThenOr32 (\r
+    GPE0BLK_Base + R_QNC_GPE0BLK_SMIE,\r
+    (UINT32)(~B_QNC_GPE0BLK_SMIE_ALL),\r
+    B_QNC_GPE0BLK_SMIE_APM\r
+    );\r
+\r
+  //\r
+  // Make sure EOS bit cleared\r
+  //\r
+  DEBUG_CODE_BEGIN ();\r
+  if (IoRead32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS) & B_QNC_GPE0BLK_SMIS_EOS) {\r
+    DEBUG ((\r
+      EFI_D_ERROR,\r
+      "******************************************************************************\n"\r
+      "BIG ERROR: SmmControl constructor couldn't properly initialize the ACPI table.\n"\r
+      "           SmmControl->Clear will probably hang.                              \n"\r
+      "              NOTE: SCI_EN = %d                                               \n"\r
+      "******************************************************************************\n",\r
+      SciEn\r
+      ));\r
+\r
+    //\r
+    // If we want the system to stop, then keep the ASSERT(FALSE).\r
+    // Otherwise, comment it out.\r
+    //\r
+    ASSERT (FALSE);\r
+  }\r
+  DEBUG_CODE_END ();\r
+\r
+  Status = gBS->CreateEventEx (\r
+                EVT_NOTIFY_SIGNAL,\r
+                TPL_NOTIFY,\r
+                SmmControlVirtualddressChangeEvent,\r
+                NULL,\r
+                &gEfiEventVirtualAddressChangeGuid,\r
+                &Event\r
+                );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Status;\r
+}\r