summaryrefslogtreecommitdiffstats
path: root/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c
diff options
context:
space:
mode:
Diffstat (limited to 'QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c')
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c366
1 files changed, 366 insertions, 0 deletions
diff --git a/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c b/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c
new file mode 100644
index 0000000000..72ba79767f
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDriver.c
@@ -0,0 +1,366 @@
+/** @file
+This module produces the SMM COntrol2 Protocol for QNC
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/SmmControl2.h>
+#include <IndustryStandard/Pci.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/PcdLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciLib.h>
+#include <IntelQNCDxe.h>
+#include <Library/QNCAccessLib.h>
+#include <Uefi/UefiBaseType.h>
+
+#define EFI_INTERNAL_POINTER 0x00000004
+
+extern EFI_GUID gEfiEventVirtualAddressChangeGuid;
+
+/**
+ Generates an SMI using the parameters passed in.
+
+ @param This A pointer to an instance of
+ EFI_SMM_CONTROL2_PROTOCOL
+ @param ArgumentBuffer The argument buffer
+ @param ArgumentBufferSize The size of the argument buffer
+ @param Periodic TRUE to indicate a periodical SMI
+ @param ActivationInterval Interval of the periodical SMI
+
+ @retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1
+ @return Return value from SmmTrigger().
+
+**/
+EFI_STATUS
+EFIAPI
+Activate (
+ IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
+ IN OUT UINT8 *CommandPort OPTIONAL,
+ IN OUT UINT8 *DataPort OPTIONAL,
+ IN BOOLEAN Periodic OPTIONAL,
+ IN EFI_SMM_PERIOD ActivationInterval OPTIONAL
+ );
+
+/**
+ Clears an SMI.
+
+ @param This Pointer to an instance of EFI_SMM_CONTROL2_PROTOCOL
+ @param Periodic TRUE to indicate a periodical SMI
+
+ @return Return value from SmmClear()
+
+**/
+EFI_STATUS
+EFIAPI
+Deactivate (
+ IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
+ IN BOOLEAN Periodic OPTIONAL
+ );
+
+///
+/// Handle for the SMM Control2 Protocol
+///
+EFI_HANDLE mSmmControl2Handle = NULL;
+
+///
+/// SMM COntrol2 Protocol instance
+///
+EFI_SMM_CONTROL2_PROTOCOL mSmmControl2 = {
+ Activate,
+ Deactivate,
+ 0
+};
+
+VOID
+EFIAPI
+SmmControlVirtualddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+/*++
+
+Routine Description:
+
+ Fixup internal data pointers so that the services can be called in virtual mode.
+
+Arguments:
+
+ Event The event registered.
+ Context Event context.
+
+Returns:
+
+ None.
+
+--*/
+{
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSmmControl2.Trigger));
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSmmControl2.Clear));
+}
+
+/**
+ Clear SMI related chipset status and re-enable SMI by setting the EOS bit.
+
+ @retval EFI_SUCCESS The requested operation has been carried out successfully
+ @retval EFI_DEVICE_ERROR The EOS bit could not be set.
+
+**/
+EFI_STATUS
+SmmClear (
+ VOID
+ )
+{
+ UINT16 PM1BLK_Base;
+ UINT16 GPE0BLK_Base;
+
+ //
+ // Get PM1BLK_Base & GPE0BLK_Base
+ //
+ PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress);
+ GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);
+
+ //
+ // Clear the Power Button Override Status Bit, it gates EOS from being set.
+ // In QuarkNcSocId - Bit is read only. Handled by external SMC, do nothing.
+ //
+
+ //
+ // Clear the APM SMI Status Bit
+ //
+ IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM);
+
+ //
+ // Set the EOS Bit
+ //
+ IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Generates an SMI using the parameters passed in.
+
+ @param This A pointer to an instance of
+ EFI_SMM_CONTROL_PROTOCOL
+ @param ArgumentBuffer The argument buffer
+ @param ArgumentBufferSize The size of the argument buffer
+ @param Periodic TRUE to indicate a periodical SMI
+ @param ActivationInterval Interval of the periodical SMI
+
+ @retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1
+ @retval EFI_SUCCESS SMI generated
+
+**/
+EFI_STATUS
+EFIAPI
+Activate (
+ IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
+ IN OUT UINT8 *CommandPort OPTIONAL,
+ IN OUT UINT8 *DataPort OPTIONAL,
+ IN BOOLEAN Periodic OPTIONAL,
+ IN EFI_SMM_PERIOD ActivationInterval OPTIONAL
+ )
+{
+ UINT16 GPE0BLK_Base;
+ UINT32 NewValue;
+
+ //
+ // Get GPE0BLK_Base
+ //
+ GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);
+
+ if (Periodic) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Clear any pending the APM SMI
+ //
+ if (EFI_ERROR (SmmClear())) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Enable the APMC SMI
+ //
+ IoOr32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIE, B_QNC_GPE0BLK_SMIE_APM);
+
+ //
+ // Enable SMI globally
+ //
+ NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
+ NewValue |= SMI_EN;
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
+
+
+ //
+ // Set APMC_STS
+ //
+ if (DataPort == NULL) {
+ IoWrite8 (PcdGet16 (PcdSmmDataPort), 0xFF);
+ } else {
+ IoWrite8 (PcdGet16 (PcdSmmDataPort), *DataPort);
+ }
+
+ //
+ // Generate the APMC SMI
+ //
+ if (CommandPort == NULL) {
+ IoWrite8 (PcdGet16 (PcdSmmActivationPort), 0xFF);
+ } else {
+ IoWrite8 (PcdGet16 (PcdSmmActivationPort), *CommandPort);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Clears an SMI.
+
+ @param This Pointer to an instance of EFI_SMM_CONTROL_PROTOCOL
+ @param Periodic TRUE to indicate a periodical SMI
+
+ @return Return value from SmmClear()
+
+**/
+EFI_STATUS
+EFIAPI
+Deactivate (
+ IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
+ IN BOOLEAN Periodic
+ )
+{
+ if (Periodic) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return SmmClear();
+}
+
+/**
+ This is the constructor for the SMM Control protocol.
+
+ This function installs EFI_SMM_CONTROL2_PROTOCOL.
+
+ @param ImageHandle Handle for the image of this driver
+ @param SystemTable Pointer to the EFI System Table
+
+ @retval EFI_UNSUPPORTED There's no Intel ICH on this platform
+ @return The status returned from InstallProtocolInterface().
+
+--*/
+EFI_STATUS
+SmmControl2Init (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+ UINT16 PM1BLK_Base;
+ UINT16 GPE0BLK_Base;
+ BOOLEAN SciEn;
+ UINT32 NewValue;
+
+ //
+ // Get PM1BLK_Base & GPE0BLK_Base
+ //
+ PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress);
+ GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);
+
+ //
+ // Install our protocol interfaces on the device's handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mSmmControl2Handle,
+ &gEfiSmmControl2ProtocolGuid, &mSmmControl2,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Determine whether an ACPI OS is present (via the SCI_EN bit)
+ //
+ SciEn = (BOOLEAN)((IoRead16 (PM1BLK_Base + R_QNC_PM1BLK_PM1C) & B_QNC_PM1BLK_PM1C_SCIEN) != 0);
+ if (!SciEn) {
+ //
+ // Clear any SMIs that double as SCIs (when SCI_EN==0)
+ //
+ IoWrite16 ((PM1BLK_Base + R_QNC_PM1BLK_PM1S), B_QNC_PM1BLK_PM1S_ALL);
+ IoWrite16 ((PM1BLK_Base + R_QNC_PM1BLK_PM1E), 0x00000000);
+ IoWrite32 ((PM1BLK_Base + R_QNC_PM1BLK_PM1C), 0x00000000);
+ IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_GPE0S), B_QNC_GPE0BLK_GPE0S_ALL);
+ IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_GPE0E), 0x00000000);
+ }
+
+ //
+ // Clear and disable all SMIs that are unaffected by SCI_EN
+ // Set EOS
+ //
+ IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIE), 0x00000000);
+ IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), (B_QNC_GPE0BLK_SMIS_EOS + B_QNC_GPE0BLK_SMIS_ALL));
+
+ //
+ // Enable SMI globally
+ //
+ NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
+ NewValue |= SMI_EN;
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
+
+ //
+ // Make sure to write this register last -- EOS re-enables SMIs for the QNC
+ //
+ IoAndThenOr32 (
+ GPE0BLK_Base + R_QNC_GPE0BLK_SMIE,
+ (UINT32)(~B_QNC_GPE0BLK_SMIE_ALL),
+ B_QNC_GPE0BLK_SMIE_APM
+ );
+
+ //
+ // Make sure EOS bit cleared
+ //
+ DEBUG_CODE_BEGIN ();
+ if (IoRead32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS) & B_QNC_GPE0BLK_SMIS_EOS) {
+ DEBUG ((
+ EFI_D_ERROR,
+ "******************************************************************************\n"
+ "BIG ERROR: SmmControl constructor couldn't properly initialize the ACPI table.\n"
+ " SmmControl->Clear will probably hang. \n"
+ " NOTE: SCI_EN = %d \n"
+ "******************************************************************************\n",
+ SciEn
+ ));
+
+ //
+ // If we want the system to stop, then keep the ASSERT(FALSE).
+ // Otherwise, comment it out.
+ //
+ ASSERT (FALSE);
+ }
+ DEBUG_CODE_END ();
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ SmmControlVirtualddressChangeEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}