From 42cba99a379661e55a4d10a15b6ba8dce6feeabe Mon Sep 17 00:00:00 2001 From: Guo Mang Date: Fri, 23 Dec 2016 11:01:56 +0800 Subject: BroxtonSiPkg: Add Reset Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang --- .../SouthCluster/Reset/RuntimeDxe/ScReset.c | 440 +++++++++++++++++++++ .../SouthCluster/Reset/RuntimeDxe/ScReset.h | 142 +++++++ .../SouthCluster/Reset/RuntimeDxe/ScReset.inf | 57 +++ 3 files changed, 639 insertions(+) create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Reset/RuntimeDxe/ScReset.c create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Reset/RuntimeDxe/ScReset.h create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Reset/RuntimeDxe/ScReset.inf (limited to 'Silicon') diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Reset/RuntimeDxe/ScReset.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Reset/RuntimeDxe/ScReset.c new file mode 100644 index 0000000000..36ac0e3d03 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Reset/RuntimeDxe/ScReset.c @@ -0,0 +1,440 @@ +/** @file + Reset Architectural Protocol implementation. + + Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.
+ + 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 "ScReset.h" +#include +#include +#include "CmosMap.h" +#include "ScAccess.h" +#include "HeciRegs.h" + +SC_RESET_INSTANCE *mResetInstance; + + +/** + Install and initialize reset protocols. + + @param[in] ImageHandle Image handle of the loaded driver + @param[in] SystemTable Pointer to the System Table + + @retval EFI_SUCCESS Thread can be successfully created + @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure + @retval EFI_DEVICE_ERROR Cannot create the timer service + +**/ +EFI_STATUS +EFIAPI +InitializeScReset ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE ResetHandle; +#if ((TIANO_RELEASE_VERSION != 0) && (EFI_SPECIFICATION_VERSION < 0x00020000)) + DXE_SC_PLATFORM_POLICY_PROTOCOL *ScPlatformPolicy; +#endif + EFI_EVENT Event; + EFI_PEI_HOB_POINTERS HobPtr; + SC_POLICY_HOB *ScPolicy; + SC_GENERAL_CONFIG *GeneralConfig; + + DEBUG ((DEBUG_INFO, "InitializeScReset() Start\n")); + ResetHandle = NULL; + ScPolicy = NULL; + + // + // Get SC Policy HOB. + // + Status = EFI_NOT_FOUND; + ZeroMem (&HobPtr, sizeof (EFI_PEI_HOB_POINTERS)); + HobPtr.Guid = GetFirstGuidHob (&gScPolicyHobGuid); + ASSERT (HobPtr.Guid != NULL); + + ScPolicy = GET_GUID_HOB_DATA (HobPtr.Guid); + Status = GetConfigBlock ((VOID *) ScPolicy, &gScGeneralConfigGuid, (VOID *) &GeneralConfig); + ASSERT_EFI_ERROR (Status); + + // + // Allocate Runtime memory for the ScExtendedReset protocol instance. + // + mResetInstance = AllocateRuntimePool (sizeof (SC_RESET_INSTANCE)); + if (mResetInstance == NULL) { + return EFI_OUT_OF_RESOURCES; + } + +#if ((TIANO_RELEASE_VERSION != 0) && (EFI_SPECIFICATION_VERSION < 0x00020000)) + // + // Get the desired platform setup policy. + // + Status = gBS->LocateProtocol (&gDxePlatformPolicyProtocolGuid, NULL, (VOID **) &ScPlatformPolicy); + ASSERT_EFI_ERROR (Status); + + // + // Check whether the CapsuleVariableName is filled. + // + if (ScPlatformPolicy->CapsuleVariableName != NULL) { + // + // Allocate a runtime space and copy string from CapsuleVariableName + // + mResetInstance->CapsuleVariableName = AllocateRuntimePool (StrSize (ScPlatformPolicy->CapsuleVariableName)); + CopyMem ( + mResetInstance->CapsuleVariableName, + ScPlatformPolicy->CapsuleVariableName, + StrSize (ScPlatformPolicy->CapsuleVariableName) + ); + } +#endif + // + // Install protocol interface + // + mResetInstance->Signature = RESET_SIGNATURE; + mResetInstance->Handle = NULL; + mResetInstance->ScExtendedResetProtocol.Reset = ScExtendedReset; + Status = gBS->InstallMultipleProtocolInterfaces ( + &mResetInstance->Handle, + &gEfiExtendedResetProtocolGuid, + &mResetInstance->ScExtendedResetProtocol, + NULL + ); + ASSERT_EFI_ERROR (Status); + mResetInstance->PmcBase = PMC_BASE_ADDRESS; + + mResetInstance->AcpiBar = (UINT16) PcdGet16 (PcdScAcpiIoPortBaseAddress); + + mResetInstance->ResetSelect = (UINT8) GeneralConfig->ResetSelect; + + // + // Make sure the Reset Architectural Protocol is not already installed in the system + // + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiResetArchProtocolGuid); + + // + // Hook the runtime service table + // + SystemTable->RuntimeServices->ResetSystem = (EFI_RESET_SYSTEM) IntelScResetSystem; + + // + // Now install the Reset RT AP on a new handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &ResetHandle, + &gEfiResetArchProtocolGuid, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Install a notification to convert the SCReset driver to Virtual Addr + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + ScResetVirtualddressChangeEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &Event + ); + ASSERT_EFI_ERROR (Status); + + // + // The Lib Deconstruct will automatically be called when entrypoint return error. + // + DEBUG ((DEBUG_INFO, "InitializeScReset() End\n")); + + return Status; +} + + +/** + Set flag to indicate the reset is controlled reset or uncontrolled reset. + +**/ +VOID +NotifyControlledReset( + VOID + ) +{ + // + // The following magic value in CMOS register is used by DXE module "NullMemoryTest" + // to differentiate a reset as Controlled or Uncontrolled. + // + IoWrite8 (CmosIo_72, EFI_CMOS_CLEAN_RESET); + IoWrite8 (CmosIo_73, B_MAGIC_CLEAN_RESET_VALUE); //Signal a controlled Reset +} + + +#if ((TIANO_RELEASE_VERSION != 0) && (EFI_SPECIFICATION_VERSION < 0x00020000)) +/** + If need be, do any special reset required for capsules. For this + implementation where we're called from the ResetSystem() api, + just set our capsule variable and return to let the caller + do a soft reset. + + @param[in] CapsuleDataPtr Pointer to the capsule block descriptors + +**/ +VOID +CapsuleReset ( + IN UINTN CapsuleDataPtr + ) +{ + UINT32 Data32; + UINT32 Eflags; + UINT16 AcpiBaseAddr; + + // + // Check the CapsuleVariableName, asset if it is not filled. + // + ASSERT (mResetInstance->CapsuleVariableName != NULL); + + // + // This implementation assumes we're using a variable for the capsule + // data pointer. + // + EfiSetVariable ( + mResetInstance->CapsuleVariableName, + &gEfiCapsuleVendorGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, ///< attributes + sizeof (UINTN), + (VOID *) &CapsuleDataPtr + ); + + // + // Read the ACPI Base address + // + AcpiBaseAddr = (UINT16) PcdGet16 (PcdScAcpiIoPortBaseAddress); + ASSERT (AcpiBaseAddr != 0); + + // + // Read the PM1_CNT register + // + Data32 = IoRead32 ((UINTN) (AcpiBaseAddr + R_ACPI_PM1_CNT)); + Data32 = (UINT32) ((Data32 & ~(B_ACPI_PM1_CNT_SLP_TYP + B_ACPI_PM1_CNT_SLP_EN)) | V_ACPI_PM1_CNT_S3); + Eflags = (UINT32) AsmReadEflags (); + + if ((Eflags & 0x200)) { + DisableInterrupts (); + } + + AsmWbinvd (); + AsmWriteCr0 (AsmReadCr0 () | 0x060000000); + + IoWrite32 ( + (UINTN) (AcpiBaseAddr + R_ACPI_PM1_CNT), + (UINT32) Data32 + ); + + Data32 = Data32 | B_ACPI_PM1_CNT_SLP_EN; + + IoWrite32 ( + (UINTN) (AcpiBaseAddr + R_ACPI_PM1_CNT), + (UINT32) Data32 + ); + + if ((Eflags & 0x200)) { + EnableInterrupts (); + } + // + // Should not return + // + EFI_DEADLOOP (); +} +#endif + + +/** + Generate system reset by Reset Control Register (IO Cf9h) + Note: This reset is hooked to RuntimeServices->ResetSystem and will be called + in OS environment and if any debug messages added then need to handle it + carefully, else debug build cause to BSOD. + Its recommended not to have debug messages over here. + + @param[in] ResetType Warm or cold + @param[in] ResetStatus Possible cause of reset + @param[in] DataSize Size of ResetData in bytes + @param[in] ResetData Optional Unicode string + +**/ +VOID +EFIAPI +IntelScResetSystem ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN VOID *ResetData OPTIONAL + ) +{ + UINT8 InitialData; + UINT8 OutputData; + UINT16 AcpiBase; + UINT16 Data16; + UINT32 Data32; + + NotifyControlledReset (); + + switch (ResetType) { + case EfiResetWarm: + InitialData = V_RST_CNT_HARDSTARTSTATE; + OutputData = mResetInstance->ResetSelect; + if (mResetInstance->ResetSelect == V_RST_CNT_FULLRESET) { + } + break; + + case EfiResetCold: + InitialData = V_RST_CNT_HARDSTARTSTATE; + OutputData = V_RST_CNT_FULLRESET; + break; + + case EfiResetShutdown: + AcpiBase = (UINT16) mResetInstance->AcpiBar; + + // + // Then, GPE0_EN should be disabled to avoid any GPI waking up the system from S5 + // + Data16 = 0; + + IoWrite16 ((UINTN) (AcpiBase + R_ACPI_GPE0a_EN), Data16); + + // + // Clear Sleep SMI Status + // + IoWrite16 (AcpiBase + R_SMI_STS, + (UINT16) (IoRead16 (AcpiBase + R_SMI_STS) | B_SMI_STS_ON_SLP_EN)); + // + // Clear Sleep Type Enable + // + IoWrite16 (AcpiBase + R_SMI_EN, + (UINT16) (IoRead16 (AcpiBase + R_SMI_EN) & (~B_SMI_EN_ON_SLP_EN))); + // + // Clear Power Button Status + // + IoWrite16(AcpiBase + R_ACPI_PM1_STS, B_ACPI_PM1_STS_PWRBTN); + + // + // Secondly, Power Button Status bit must be cleared + // + // Write a "1" to bit[8] of power button status register at + // (ABASE + PM1_STS) to clear this bit + // Clear it through SMI Status register + // + Data16 = B_SMI_STS_PM1_STS_REG; + IoWrite16 ((UINTN) (AcpiBase + R_SMI_STS), Data16); + + // + // Finally, transform system into S5 sleep state + // + Data32 = IoRead32 ((UINTN) (AcpiBase + R_ACPI_PM1_CNT)); + Data32 = (UINT32) ((Data32 & ~(B_ACPI_PM1_CNT_SLP_TYP + B_ACPI_PM1_CNT_SLP_EN)) | V_ACPI_PM1_CNT_S5); + + IoWrite32 ((UINTN) (AcpiBase + R_ACPI_PM1_CNT), Data32); + + Data32 = Data32 | B_ACPI_PM1_CNT_SLP_EN; + + IoWrite32 ((UINTN) (AcpiBase + R_ACPI_PM1_CNT), Data32); + // + // Should not return + // + CpuDeadLoop(); + return ; + + default: + return ; + } + + IoWrite8 ( + (UINTN) R_RST_CNT, + (UINT8) InitialData + ); + + IoWrite8 ( + (UINTN) R_RST_CNT, + (UINT8) OutputData + ); + + // + // Given we should have reset getting here would be bad + // + CpuDeadLoop(); + + ASSERT (FALSE); +} + + +/** + Execute SC Extended Reset from the host controller. + + @param[in] This Pointer to the EFI_SC_EXTENDED_RESET_PROTOCOL instance. + @param[in] ScExtendedResetTypes SC Extended Reset Types which includes PowerCycle, Globalreset. + + @retval EFI_SUCCESS Successfully completed. + @retval EFI_INVALID_PARAMETER If ResetType is invalid. + +**/ +EFI_STATUS +EFIAPI +ScExtendedReset ( + IN EFI_SC_EXTENDED_RESET_PROTOCOL *This, + IN SC_EXTENDED_RESET_TYPES ScExtendedResetTypes + ) +{ + // + // Check if the parameters are valid. + // + if ((ScExtendedResetTypes.PowerCycle == 0) && (ScExtendedResetTypes.GlobalReset == 0)) { + return EFI_INVALID_PARAMETER; + } + + NotifyControlledReset (); + + if (ScExtendedResetTypes.GlobalReset == 1) { + MmioOr32 (mResetInstance->PmcBase + R_PMC_PMIR, (UINT32) (B_PMC_PMIR_CF9GR)); + } + + IoWrite8 ((UINTN) R_RST_CNT, (UINT8) V_RST_CNT_FULLRESET); + + // + // Waiting for system reset + // + while (TRUE); + + return EFI_SUCCESS; +} + + +/** + Fixup internal data pointers so that the services can be called in virtual mode. + + @param[in] Event The event registered. + @param[in] Context Event context. Not used in this event handler. + +**/ +VOID +EFIAPI +ScResetVirtualddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EfiConvertPointer (0x0, (VOID **) &(mResetInstance->ScExtendedResetProtocol.Reset)); +#if ((TIANO_RELEASE_VERSION != 0) && (EFI_SPECIFICATION_VERSION < 0x00020000)) + EfiConvertPointer (0x0, (VOID **) &(mResetInstance->CapsuleVariableName)); +#endif + EfiConvertPointer (0x0, (VOID **) &(mResetInstance->AcpiBar)); + EfiConvertPointer (0x0, (VOID **) &(mResetInstance->PmcBase)); + EfiConvertPointer (0x0, (VOID **) &(mResetInstance)); +} + diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Reset/RuntimeDxe/ScReset.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Reset/RuntimeDxe/ScReset.h new file mode 100644 index 0000000000..0c90d11727 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Reset/RuntimeDxe/ScReset.h @@ -0,0 +1,142 @@ +/** @file + Header file definitions for SC reset. + + Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.
+ + 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. + +**/ + +#ifndef _SC_RESET_RT_H_ +#define _SC_RESET_RT_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ScAccess.h" +#include + +// +// Driver private data +// +#define RESET_SIGNATURE SIGNATURE_32 ('I', 'E', 'R', 'S') + +typedef struct { + UINT32 Signature; + EFI_HANDLE Handle; + EFI_SC_EXTENDED_RESET_PROTOCOL ScExtendedResetProtocol; +#if ((TIANO_RELEASE_VERSION != 0) && (EFI_SPECIFICATION_VERSION < 0x00020000)) + CHAR16 *CapsuleVariableName; +#endif + UINTN PmcBase; + UINTN AcpiBar; + UINT8 ResetSelect; +} SC_RESET_INSTANCE; + +#define RESET_INSTANCE_FROM_THIS(a) \ + CR ( \ + a, \ + SC_RESET_INSTANCE, \ + ScExtendedResetProtocol, \ + RESET_SIGNATURE \ + ) + +/** + Install and initialize reset protocols. + + @param[in] ImageHandle Image handle of the loaded driver + @param[in] SystemTable Pointer to the System Table + + @retval EFI_SUCCESS Thread can be successfully created + @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure + @retval EFI_DEVICE_ERROR Cannot create the timer service + +**/ +EFI_STATUS +EFIAPI +InitializeScReset ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Generate system reset by Reset Control Register (IO Cf9h) + + @param[in] ResetType Warm or cold + @param[in] ResetStatus Possible cause of reset + @param[in] DataSize Size of ResetData in bytes + @param[in] ResetData Optional Unicode string + +**/ +VOID +EFIAPI +IntelScResetSystem ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN VOID *ResetData OPTIONAL + ); + +#if ((TIANO_RELEASE_VERSION != 0) && (EFI_SPECIFICATION_VERSION < 0x00020000)) +/** + If need be, do any special reset required for capsules. For this + implementation where we're called from the ResetSystem() api, + just set our capsule variable and return to let the caller + do a soft reset. + + @param[in] CapsuleDataPtr Pointer to the capsule block descriptors + +**/ +VOID +CapsuleReset ( + IN UINTN CapsuleDataPtr + ); +#endif + +/** + Execute SC Extended Reset from the host controller. + + @param[in] This Pointer to the EFI_SC_EXTENDED_RESET_PROTOCOL instance. + @param[in] ScExtendedResetTypes SC Extended Reset Types which includes PowerCycle, Globalreset. + + @retval EFI_SUCCESS Successfully completed. + @retval EFI_INVALID_PARAMETER If ResetType is invalid. + +**/ +EFI_STATUS +EFIAPI +ScExtendedReset ( + IN EFI_SC_EXTENDED_RESET_PROTOCOL *This, + IN SC_EXTENDED_RESET_TYPES ScExtendedResetTypes + ); + +/** + Fixup internal data pointers so that the services can be called in virtual mode. + + @param[in] Event The event registered. + @param[in] Context Event context. Not used in this event handler. + +**/ +VOID +EFIAPI +ScResetVirtualddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ); +#endif + diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Reset/RuntimeDxe/ScReset.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Reset/RuntimeDxe/ScReset.inf new file mode 100644 index 0000000000..9e4a4dfcf1 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Reset/RuntimeDxe/ScReset.inf @@ -0,0 +1,57 @@ +## @file +# Sc Reset driver. +# +# Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.
+# +# 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. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ScReset + FILE_GUID = F5883FC5-F8EE-4e44-B386-6021FB320C9B + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeScReset + +[sources.common] + ScReset.c + ScReset.h + +[Packages] + MdePkg/MdePkg.dec + BroxtonSiPkg/BroxtonSiPkg.dec + BroxtonSiPkg/BroxtonSiPrivate.dec + +[LibraryClasses] + UefiDriverEntryPoint + MemoryAllocationLib + IoLib + DebugLib + UefiRuntimeLib + PcdLib + HobLib + ConfigBlockLib + +[Guids] + gEfiEventVirtualAddressChangeGuid ## UNDEFINED + gScPolicyHobGuid ## UNDEFINED + gScGeneralConfigGuid + +[Protocols] + gEfiResetArchProtocolGuid ## PRODUCES + gEfiExtendedResetProtocolGuid ## PRODUCES + +[Pcd] + gEfiBxtTokenSpaceGuid.PcdScAcpiIoPortBaseAddress ## SOMETIMES_CONSUMES + gEfiBxtTokenSpaceGuid.PcdPmcGcrBaseAddress ## SOMETIMES_CONSUMES + +[Depex] + TRUE -- cgit v1.2.3