mirror of https://github.com/acidanthera/audk.git
365 lines
9.8 KiB
C
365 lines
9.8 KiB
C
/** @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 GPE0BLK_Base;
|
|
|
|
//
|
|
// Get GPE0BLK_Base
|
|
//
|
|
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;
|
|
}
|