summaryrefslogtreecommitdiff
path: root/Silicon/Intel/LewisburgPkg/Library/PeiDxeSmmPchCycleDecodingLib/PchCycleDecodingLib.c
diff options
context:
space:
mode:
Diffstat (limited to 'Silicon/Intel/LewisburgPkg/Library/PeiDxeSmmPchCycleDecodingLib/PchCycleDecodingLib.c')
-rw-r--r--Silicon/Intel/LewisburgPkg/Library/PeiDxeSmmPchCycleDecodingLib/PchCycleDecodingLib.c1176
1 files changed, 1176 insertions, 0 deletions
diff --git a/Silicon/Intel/LewisburgPkg/Library/PeiDxeSmmPchCycleDecodingLib/PchCycleDecodingLib.c b/Silicon/Intel/LewisburgPkg/Library/PeiDxeSmmPchCycleDecodingLib/PchCycleDecodingLib.c
new file mode 100644
index 0000000000..3629bc5157
--- /dev/null
+++ b/Silicon/Intel/LewisburgPkg/Library/PeiDxeSmmPchCycleDecodingLib/PchCycleDecodingLib.c
@@ -0,0 +1,1176 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that 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 <Base.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MmPciBaseLib.h>
+#include <PchAccess.h>
+#include <Library/PchInfoLib.h>
+#include <Library/PchPcrLib.h>
+#include <Library/PchP2sbLib.h>
+#include <Library/PchCycleDecodingLib.h>
+
+/**
+ Set PCH ACPI base address.
+ The Address should not be 0 and should be 256 bytes alignment, and it is IO space, so must not exceed 0xFFFF.
+ This cycle decoding is allowed to set when DMIC.SRL is 0.
+ Programming steps:
+ 1. clear PMC PCI offset 44h [7] to diable ACPI base address first before changing base address.
+ 2. program PMC PCI offset 40h [15:2] to ACPI base address.
+ 3. set PMC PCI offset 44h [7] to enable ACPI base address.
+ 4. program "ACPI Base Address" PCR[DMI] + 27B4h[23:18, 15:2, 0] to [0x3F, PMC PCI Offset 40h bit[15:2], 1].
+ 5. Program "ACPI Base Destination ID"
+ For SPT-LP: Program PCR[DMI] + 27B8h[31:0] to 0x23A0
+ For SPT-H: Program PCR[DMI] + 27B8h[31:0] to 0x23A8
+
+ @param[in] Address Address for ACPI base address.
+
+ @retval EFI_SUCCESS Successfully completed.
+ @retval EFI_INVALID_PARAMETER Invalid base address passed.
+ @retval EFI_UNSUPPORTED DMIC.SRL is set.
+**/
+EFI_STATUS
+EFIAPI
+PchAcpiBaseSet (
+ IN UINT16 Address
+ )
+{
+ UINTN PmcBase;
+ UINT32 Dmic;
+ UINT32 Data32;
+ PCH_SERIES PchSeries;
+
+ PchSeries = GetPchSeries ();
+
+ if (((Address & 0x00FF) != 0) ||
+ (Address == 0))
+ {
+ DEBUG((DEBUG_ERROR, "PchAcpiBaseSet Error. Invalid Address: %x.\n", Address));
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+ PchPcrRead32 (PID_DMI, R_PCH_PCR_DMI_DMIC, &Dmic);
+ if ((Dmic & B_PCH_PCR_DMI_DMIC_SRL) != 0) {
+ DEBUG((DEBUG_ERROR, "PchAcpiBaseSet Error. DMIC.SRL is set.\n"));
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ PmcBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_PMC,
+ PCI_FUNCTION_NUMBER_PCH_PMC
+ );
+ if (MmioRead16 (PmcBase) == 0xFFFF) {
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Disable ABASE in PMC Device first before changing base address.
+ //
+ MmioAnd8 (
+ PmcBase + R_PCH_PMC_ACPI_CNT,
+ (UINT8) ~B_PCH_PMC_ACPI_CNT_ACPI_EN
+ );
+ //
+ // Program ABASE in PMC Device
+ //
+ MmioAndThenOr16 (
+ PmcBase + R_PCH_PMC_ACPI_BASE,
+ (UINT16) (~B_PCH_PMC_ACPI_BASE_BAR),
+ Address
+ );
+ //
+ // Enable ABASE in PMC Device
+ //
+ MmioOr8 (
+ PmcBase + R_PCH_PMC_ACPI_CNT,
+ B_PCH_PMC_ACPI_CNT_ACPI_EN
+ );
+ //
+ // Program "ACPI Base Address" PCR[DMI] + 27B4h[23:18, 15:2, 0] to [0x3F, PMC PCI Offset 40h bit[15:2], 1]
+ //
+ PchPcrWrite32 (
+ PID_DMI, R_PCH_PCR_DMI_ACPIBA,
+ (0x00FC0001 + Address)
+ );
+ //
+ // Program "ACPI Base Destination ID"
+ // For SPT-LP:
+ // Program PCR[DMI] + 27B8h[31:0] to 0x23A0
+ // For SPT-H:
+ // Program PCR[DMI] + 27B8h[31:0] to 0x23A8
+ //
+ if(PchSeries == PchLp){
+ Data32 = 0x23A0;
+ } else {
+ Data32 = 0x23A8;
+ }
+ PchPcrWrite32 (
+ PID_DMI, R_PCH_PCR_DMI_ACPIBDID,
+ Data32
+ );
+ return EFI_SUCCESS;
+}
+
+/**
+ Get PCH ACPI base address.
+
+ @param[out] Address Address of ACPI base address.
+
+ @retval EFI_SUCCESS Successfully completed.
+ @retval EFI_INVALID_PARAMETER Invalid pointer passed.
+**/
+EFI_STATUS
+EFIAPI
+PchAcpiBaseGet (
+ OUT UINT16 *Address
+ )
+{
+ UINTN PmcBase;
+
+ if (Address == NULL) {
+ DEBUG((DEBUG_ERROR, "PchAcpiBaseGet Error. Invalid pointer.\n"));
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PmcBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_PMC,
+ PCI_FUNCTION_NUMBER_PCH_PMC
+ );
+ if (MmioRead16 (PmcBase) == 0xFFFF) {
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+ *Address = MmioRead16 (PmcBase + R_PCH_PMC_ACPI_BASE) & B_PCH_PMC_ACPI_BASE_BAR;
+ return EFI_SUCCESS;
+}
+
+/**
+ Set PCH PWRM base address.
+ This cycle decoding is allowed to set when DMIC.SRL is 0.
+ Programming steps:
+ 1. clear PMC PCI offset 44h [8] to diable PWRM base address first before changing PWRM base address.
+ 2. program PMC PCI offset 48h [31:16] to PM base address.
+ 3. set PMC PCI offset 44h [8] to enable PWRM base address.
+ 4. program "PM Base Address Memory Range Base" PCR[DMI] + 27ACh[15:0] to the same value programmed in PMC PCI Offset 48h bit[31:16], this has an implication of making sure the PWRMBASE to be 64KB aligned.
+ program "PM Base Address Memory Range Limit" PCR[DMI] + 27ACh[31:16] to the value programmed in PMC PCI Offset 48h bit[31:16], this has an implication of making sure the memory allocated to PWRMBASE to be 64KB in size.
+ 5. Program "PM Base Control"
+ For SPT-LP: Program PCR[DMI] + 27B0h[31, 30:0] to [1, 0x23A0]
+ For SPT-H: Program PCR[DMI] + 27B0h[31, 30:0] to [1, 0x23A8]
+
+ @param[in] Address Address for PWRM base address.
+
+ @retval EFI_SUCCESS Successfully completed.
+ @retval EFI_INVALID_PARAMETER Invalid base address passed.
+ @retval EFI_UNSUPPORTED DMIC.SRL is set.
+**/
+EFI_STATUS
+EFIAPI
+PchPwrmBaseSet (
+ IN UINT32 Address
+ )
+{
+ UINTN PmcBase;
+ UINT32 Dmic;
+ UINT32 Data32;
+ PCH_SERIES PchSeries;
+
+ PchSeries = GetPchSeries ();
+
+ if (((Address & (~B_PCH_PMC_PWRM_BASE_BAR)) != 0) ||
+ (Address == 0))
+ {
+ DEBUG((DEBUG_ERROR, "PchPwrmBaseSet Error. Invalid Address: %x.\n", Address));
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+ PchPcrRead32 (PID_DMI, R_PCH_PCR_DMI_DMIC, &Dmic);
+ if ((Dmic & B_PCH_PCR_DMI_DMIC_SRL) != 0) {
+ DEBUG((DEBUG_ERROR, "PchPwrmBaseSet Error. DMIC.SRL is set.\n"));
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ PmcBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_PMC,
+ PCI_FUNCTION_NUMBER_PCH_PMC
+ );
+ if (MmioRead16 (PmcBase) == 0xFFFF) {
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Disable PWRMBASE in PMC Device first before changing PWRM base address.
+ //
+ MmioAnd16 (
+ PmcBase + R_PCH_PMC_ACPI_CNT,
+ (UINT16) ~B_PCH_PMC_ACPI_CNT_PWRM_EN
+ );
+ //
+ // Program PWRMBASE in PMC Device
+ //
+ MmioAndThenOr32 (
+ PmcBase + R_PCH_PMC_PWRM_BASE,
+ (UINT32) (~B_PCH_PMC_PWRM_BASE_BAR),
+ Address
+ );
+ //
+ // Enable PWRMBASE in PMC Device
+ //
+ MmioOr16 (
+ PmcBase + R_PCH_PMC_ACPI_CNT,
+ B_PCH_PMC_ACPI_CNT_PWRM_EN
+ );
+ //
+ // Program "PM Base Address Memory Range Base" PCR[DMI] + 27ACh[15:0] to the same value programmed in PMC PCI Offset 48h bit[31:16], this has an implication of making sure the PWRMBASE to be 64KB aligned.
+ // Program "PM Base Address Memory Range Limit" PCR[DMI] + 27ACh[31:16] to the value programmed in PMC PCI Offset 48h bit[31:16], this has an implication of making sure the memory allocated to PWRMBASE to be 64KB in size.
+ //
+ PchPcrWrite32 (
+ PID_DMI, R_PCH_PCR_DMI_PMBASEA,
+ ((Address & 0xFFFF0000) | (Address >> 16))
+ );
+ //
+ // Program "PM Base Control"
+ // For SPT-LP:
+ // Program PCR[DMI] + 27B0h[31, 30:0] to [1, 0x23A0]
+ // For SPT-H:
+ // Program PCR[DMI] + 27B0h[31, 30:0] to [1, 0x23A8]
+ //
+ if(PchSeries == PchLp){
+ Data32 = 0x800023A0;
+ } else {
+ Data32 = 0x800023A8;
+ }
+ PchPcrWrite32 (
+ PID_DMI, R_PCH_PCR_DMI_PMBASEC,
+ Data32
+ );
+ return EFI_SUCCESS;
+}
+
+/**
+ Get PCH PWRM base address.
+
+ @param[out] Address Address of PWRM base address.
+
+ @retval EFI_SUCCESS Successfully completed.
+ @retval EFI_INVALID_PARAMETER Invalid pointer passed.
+**/
+EFI_STATUS
+EFIAPI
+PchPwrmBaseGet (
+ OUT UINT32 *Address
+ )
+{
+ UINTN PmcBase;
+
+ if (Address == NULL) {
+ DEBUG((DEBUG_ERROR, "PchPwrmBaseGet Error. Invalid pointer.\n"));
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PmcBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_PMC,
+ PCI_FUNCTION_NUMBER_PCH_PMC
+ );
+ if (MmioRead16 (PmcBase) == 0xFFFF) {
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+ *Address = MmioRead32 (PmcBase + R_PCH_PMC_PWRM_BASE) & B_PCH_PMC_PWRM_BASE_BAR;
+ return EFI_SUCCESS;
+}
+
+/**
+ Set PCH TCO base address.
+ This cycle decoding is allowed to set when DMIC.SRL is 0.
+ Programming steps:
+ 1. set Smbus PCI offset 54h [8] to enable TCO base address.
+ 2. program Smbus PCI offset 50h [15:5] to TCO base address.
+ 3. set Smbus PCI offset 54h [8] to enable TCO base address.
+ 4. program "TCO Base Address" PCR[DMI] + 2778h[15:5, 1] to [Smbus PCI offset 50h[15:5], 1].
+
+ @param[in] Address Address for TCO base address.
+
+ @retval EFI_SUCCESS Successfully completed.
+ @retval EFI_INVALID_PARAMETER Invalid base address passed.
+ @retval EFI_UNSUPPORTED DMIC.SRL is set.
+**/
+EFI_STATUS
+EFIAPI
+PchTcoBaseSet (
+ IN UINT16 Address
+ )
+{
+ UINTN SmbusBase;
+ UINT32 Dmic;
+
+ if ((Address & ~B_PCH_SMBUS_TCOBASE_BAR) != 0) {
+ DEBUG((DEBUG_ERROR, "PchTcoBaseSet Error. Invalid Address: %x.\n", Address));
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+ PchPcrRead32 (PID_DMI, R_PCH_PCR_DMI_DMIC, &Dmic);
+ if ((Dmic & B_PCH_PCR_DMI_DMIC_SRL) != 0) {
+ DEBUG((DEBUG_ERROR, "PchTcoBaseSet Error. DMIC.SRL is set.\n"));
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ SmbusBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_SMBUS,
+ PCI_FUNCTION_NUMBER_PCH_SMBUS
+ );
+ if (MmioRead16 (SmbusBase) == 0xFFFF) {
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Verify TCO base is not locked.
+ //
+ if ((MmioRead8 (SmbusBase + R_PCH_SMBUS_TCOCTL) & B_PCH_SMBUS_TCOCTL_TCO_BASE_LOCK) != 0) {
+ ASSERT (FALSE);
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Disable TCO in SMBUS Device first before changing base address.
+ //
+ MmioAnd8 (
+ SmbusBase + R_PCH_SMBUS_TCOCTL + 1,
+ (UINT8) ~(B_PCH_SMBUS_TCOCTL_TCO_BASE_EN >> 8)
+ );
+ //
+ // Program TCO in SMBUS Device
+ //
+ MmioAndThenOr16 (
+ SmbusBase + R_PCH_SMBUS_TCOBASE,
+ (UINT16) (~B_PCH_SMBUS_TCOBASE_BAR),
+ Address
+ );
+ //
+ // Enable TCO in SMBUS Device
+ //
+ MmioOr8 (
+ SmbusBase + R_PCH_SMBUS_TCOCTL + 1,
+ (B_PCH_SMBUS_TCOCTL_TCO_BASE_EN >> 8)
+ );
+ //
+ // Program "TCO Base Address" PCR[DMI] + 2778h[15:5, 1] to [SMBUS PCI offset 50h[15:5], 1].
+ //
+ PchPcrWrite16 (
+ PID_DMI, R_PCH_PCR_DMI_TCOBASE,
+ (Address | BIT1)
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get PCH TCO base address.
+
+ @param[out] Address Address of TCO base address.
+
+ @retval EFI_SUCCESS Successfully completed.
+ @retval EFI_INVALID_PARAMETER Invalid pointer passed.
+**/
+EFI_STATUS
+EFIAPI
+PchTcoBaseGet (
+ OUT UINT16 *Address
+ )
+{
+ if (Address == NULL) {
+ DEBUG((DEBUG_ERROR, "PchTcoBaseGet Error. Invalid pointer.\n"));
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Read "TCO Base Address" PCR[DMI] + 2778h[15:5]
+ // Don't read TCO base address from SMBUS PCI register since SMBUS might be disabled.
+ //
+ PchPcrRead16 (
+ PID_DMI, R_PCH_PCR_DMI_TCOBASE,
+ Address
+ );
+ *Address &= B_PCH_PCR_DMI_TCOBASE_TCOBA;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set PCH LPC/eSPI generic IO range.
+ For generic IO range, the base address must align to 4 and less than 0xFFFF, and the length must be power of 2
+ and less than or equal to 256. Moreover, the address must be length aligned.
+ This function basically checks the address and length, which should not overlap with all other generic ranges.
+ If no more generic range register available, it returns out of resource error.
+ This cycle decoding is allowed to set when DMIC.SRL is 0.
+ Some IO ranges below 0x100 have fixed target. The target might be ITSS,RTC,LPC,PMC or terminated inside P2SB
+ but all predefined and can't be changed. IO range below 0x100 will be rejected in this function except below ranges:
+ 0x00-0x1F,
+ 0x44-0x4B,
+ 0x54-0x5F,
+ 0x68-0x6F,
+ 0x80-0x8F,
+ 0xC0-0xFF
+ Steps of programming generic IO range:
+ 1. Program LPC/eSPI PCI Offset 84h ~ 93h of Mask, Address, and Enable.
+ 2. Program LPC/eSPI Generic IO Range #, PCR[DMI] + 2730h ~ 273Fh to the same value programmed in LPC/eSPI PCI Offset 84h~93h.
+
+ @param[in] Address Address for generic IO range base address.
+ @param[in] Length Length of generic IO range.
+
+ @retval EFI_SUCCESS Successfully completed.
+ @retval EFI_INVALID_PARAMETER Invalid base address or length passed.
+ @retval EFI_OUT_OF_RESOURCES No more generic range available.
+ @retval EFI_UNSUPPORTED DMIC.SRL is set.
+**/
+EFI_STATUS
+EFIAPI
+PchLpcGenIoRangeSet (
+ IN UINT16 Address,
+ IN UINTN Length
+ , IN UINT8 SlaveDevice
+ )
+{
+ EFI_STATUS Status;
+ PCH_LPC_GEN_IO_RANGE_LIST LpcGenIoRangeList;
+ UINTN LpcBase;
+ UINTN Index;
+ UINTN BaseAddr;
+ UINTN MaskLength;
+ UINTN TempMaxAddr;
+ UINT32 Data32;
+ UINTN ArraySize;
+ static struct EXCEPT_RANGE {
+ UINT8 Start;
+ UINT8 Length;
+ } ExceptRanges[] = { {0x00, 0x20}, {0x44, 0x08}, {0x54, 0x0C}, {0x68, 0x08}, {0x80, 0x10}, {0xC0, 0x40} };
+
+ Index = 0;
+ //
+ // Note: Inside this function, don't use debug print since it's could used before debug print ready.
+ //
+
+ //
+ // For generic IO range, the base address must align to 4 and less than 0xFFFF,
+ // the length must be power of 2 and less than or equal to 256, and the address must be length aligned.
+ // IO range below 0x100 will be rejected in this function except below ranges:
+ // 0x00-0x1F,
+ // 0x44-0x4B,
+ // 0x54-0x5F,
+ // 0x68-0x6F,
+ // 0x80-0x8F,
+ // 0xC0-0xFF
+ //
+ if (((Length & (Length - 1)) != 0) ||
+ ((Address & (UINT16)~B_PCH_LPC_GENX_DEC_IOBAR) != 0) ||
+ (Length > 256))
+ {
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Address < 0x100) {
+ ArraySize = sizeof (ExceptRanges) / sizeof (struct EXCEPT_RANGE);
+ for (Index = 0; Index < ArraySize; Index++) {
+ if ((Address >= ExceptRanges[Index].Start) &&
+ ((Address + Length) <= ((UINTN)ExceptRanges[Index].Start + (UINTN)ExceptRanges[Index].Length)))
+ {
+ break;
+ }
+ }
+ if (Index >= ArraySize) {
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // check if range overlap
+ //
+ Status = PchLpcGenIoRangeGet (&LpcGenIoRangeList, SlaveDevice);
+ if (EFI_ERROR (Status)) {
+ ASSERT (FALSE);
+ return Status;
+ }
+ if (SlaveDevice == LPC_ESPI_FIRST_SLAVE) {
+ for (Index = 0; Index < PCH_LPC_GEN_IO_RANGE_MAX; Index++) {
+ BaseAddr = LpcGenIoRangeList.Range[Index].BaseAddr;
+ MaskLength = LpcGenIoRangeList.Range[Index].Length;
+ if (BaseAddr == 0) {
+ continue;
+ }
+ if (((Address >= BaseAddr) && (Address < (BaseAddr + MaskLength))) ||
+ (((Address + Length) > BaseAddr) && ((Address + Length) <= (BaseAddr + MaskLength))))
+ {
+ if ((Address >= BaseAddr) && (Length <= MaskLength)) {
+ //
+ // return SUCCESS while range is covered.
+ //
+ return EFI_SUCCESS;
+ }
+
+ if ((Address + Length) > (BaseAddr + MaskLength)) {
+ TempMaxAddr = Address + Length;
+ } else {
+ TempMaxAddr = BaseAddr + MaskLength;
+ }
+ if (Address > BaseAddr) {
+ Address = (UINT16) BaseAddr;
+ }
+ Length = TempMaxAddr - Address;
+ break;
+ }
+ }
+ //
+ // If no range overlap
+ //
+ if (Index >= PCH_LPC_GEN_IO_RANGE_MAX) {
+ //
+ // Find a empty register
+ //
+ for (Index = 0; Index < PCH_LPC_GEN_IO_RANGE_MAX; Index++) {
+ BaseAddr = LpcGenIoRangeList.Range[Index].BaseAddr;
+ if (BaseAddr == 0) {
+ break;
+ }
+ }
+ if (Index >= PCH_LPC_GEN_IO_RANGE_MAX) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ } else {
+ BaseAddr = LpcGenIoRangeList.Range[0].BaseAddr;
+ MaskLength = LpcGenIoRangeList.Range[0].Length;
+ if (BaseAddr != 0) {
+ if (((Address >= BaseAddr) && (Address < (BaseAddr + MaskLength))) ||
+ (((Address + Length) > BaseAddr) && ((Address + Length) <= (BaseAddr + MaskLength))))
+ {
+ if ((Address >= BaseAddr) && (Length <= MaskLength)) {
+ //
+ // return SUCCESS while range is covered.
+ //
+ return EFI_SUCCESS;
+ } else {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ }
+ }
+ //
+ // This cycle decoding is only allowed to set when DMIC.SRL is 0.
+ //
+ PchPcrRead32 (PID_DMI, R_PCH_PCR_DMI_DMIC, &Data32);
+ if ((Data32 & B_PCH_PCR_DMI_DMIC_SRL) != 0) {
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Program LPC/eSPI generic IO range register accordingly.
+ //
+ LpcBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC
+ );
+ Data32 = (UINT32) (((Length - 1) << 16) & B_PCH_LPC_GENX_DEC_IODRA);
+ Data32 |= (UINT32) Address;
+ Data32 |= B_PCH_LPC_GENX_DEC_EN;
+
+ if (SlaveDevice == LPC_ESPI_FIRST_SLAVE) {
+ //
+ // Program LPC/eSPI PCI Offset 84h ~ 93h of Mask, Address, and Enable.
+ //
+ MmioWrite32 (
+ LpcBase + R_PCH_LPC_GEN1_DEC + Index * 4,
+ Data32
+ );
+ //
+ // Program LPC Generic IO Range #, PCR[DMI] + 2730h ~ 273Fh to the same value programmed in LPC/eSPI PCI Offset 84h~93h.
+ //
+ PchPcrWrite32 (
+ PID_DMI, (UINT16) (R_PCH_PCR_DMI_LPCLGIR1 + Index * 4),
+ Data32
+ );
+ } else {
+ ASSERT(FALSE);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Get PCH LPC/eSPI generic IO range list.
+ This function returns a list of base address, length, and enable for all LPC/eSPI generic IO range regsiters.
+
+ @param[out] LpcGenIoRangeList Return all LPC/eSPI generic IO range register status.
+
+ @retval EFI_SUCCESS Successfully completed.
+ @retval EFI_INVALID_PARAMETER Invalid base address passed.
+**/
+EFI_STATUS
+EFIAPI
+PchLpcGenIoRangeGet (
+ OUT PCH_LPC_GEN_IO_RANGE_LIST *LpcGenIoRangeList
+ , IN UINT8 SlaveDevice
+ )
+{
+ UINTN Index;
+ UINTN LpcBase;
+ UINT32 Data32;
+
+ //
+ // Note: Inside this function, don't use debug print since it's could used before debug print ready.
+ //
+
+ if (LpcGenIoRangeList == NULL) {
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ LpcBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC
+ );
+
+ if (SlaveDevice == LPC_ESPI_FIRST_SLAVE) {
+ for (Index = 0; Index < PCH_LPC_GEN_IO_RANGE_MAX; Index++) {
+ Data32 = MmioRead32 (LpcBase + R_PCH_LPC_GEN1_DEC + Index * 4);
+ LpcGenIoRangeList->Range[Index].BaseAddr = Data32 & B_PCH_LPC_GENX_DEC_IOBAR;
+ LpcGenIoRangeList->Range[Index].Length = ((Data32 & B_PCH_LPC_GENX_DEC_IODRA) >> 16) + 4;
+ LpcGenIoRangeList->Range[Index].Enable = Data32 & B_PCH_LPC_GENX_DEC_EN;
+ }
+ } else {
+ ASSERT(FALSE);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Set PCH LPC/eSPI memory range decoding.
+ This cycle decoding is allowed to set when DMIC.SRL is 0.
+ Programming steps:
+ 1. Program LPC/eSPI PCI Offset 98h [0] to [0] to disable memory decoding first before changing base address.
+ 2. Program LPC/eSPI PCI Offset 98h [31:16, 0] to [Address, 1].
+ 3. Program LPC/eSPI Memory Range, PCR[DMI] + 2740h to the same value programmed in LPC/eSPI PCI Offset 98h.
+
+ @param[in] Address Address for memory base address.
+
+ @retval EFI_SUCCESS Successfully completed.
+ @retval EFI_INVALID_PARAMETER Invalid base address or length passed.
+ @retval EFI_OUT_OF_RESOURCES No more generic range available.
+ @retval EFI_UNSUPPORTED DMIC.SRL is set.
+**/
+EFI_STATUS
+EFIAPI
+PchLpcMemRangeSet (
+ IN UINT32 Address
+ , IN UINT8 SlaveDevice
+ )
+{
+ UINTN LpcBase;
+ UINT32 Dmic;
+ UINTN LpcReg;
+ UINT16 DmiReg;
+
+ if ((Address & (~B_PCH_LPC_LGMR_MA)) != 0) {
+ DEBUG((DEBUG_ERROR, "PchLpcMemRangeSet Error. Invalid Address: %x.\n", Address));
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+ PchPcrRead32 (PID_DMI, R_PCH_PCR_DMI_DMIC, &Dmic);
+ if ((Dmic & B_PCH_PCR_DMI_DMIC_SRL) != 0) {
+ DEBUG((DEBUG_ERROR, "PchLpcMemRangeSet Error. DMIC.SRL is set.\n"));
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ LpcBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC
+ );
+ if (SlaveDevice == ESPI_SECONDARY_SLAVE) {
+ ASSERT(FALSE);
+ } else {
+ LpcReg = LpcBase + R_PCH_LPC_LGMR;
+ DmiReg = R_PCH_PCR_DMI_LPCGMR;
+ }
+ //
+ // Program LPC/eSPI PCI Offset 98h [0] (LPC/ePSI first slave) or A8h [0] (eSPI secondary slave) to [0] to disable memory decoding first before changing base address.
+ //
+ MmioAnd32 (
+ LpcReg,
+ (UINT32) ~B_PCH_LPC_LGMR_LMRD_EN
+ );
+ //
+ // Program LPC/eSPI PCI Offset 98h [31:16, 0] (LPC/ eSPI first slave) or A8h [31:16, 0] (eSPI secondary slave) to [Address, 1].
+ //
+ MmioWrite32 (
+ LpcReg,
+ (Address | B_PCH_LPC_LGMR_LMRD_EN)
+ );
+ //
+ // Program LPC Memory Range, PCR[DMI] + 2740h (LPC/eSPI first slave) or 27C0h (eSPI secondary slave) to the same value programmed in LPC/eSPI PCI Offset 98h.
+ //
+ PchPcrWrite32 (
+ PID_DMI, DmiReg,
+ (Address | B_PCH_LPC_LGMR_LMRD_EN)
+ );
+ return EFI_SUCCESS;
+}
+
+/**
+ Get PCH LPC/eSPI memory range decoding address.
+
+ @param[out] Address Address of LPC/eSPI memory decoding base address.
+
+ @retval EFI_SUCCESS Successfully completed.
+ @retval EFI_INVALID_PARAMETER Invalid base address passed.
+**/
+EFI_STATUS
+EFIAPI
+PchLpcMemRangeGet (
+ OUT UINT32 *Address
+ , IN UINT8 SlaveDevice
+ )
+{
+ UINTN LpcBase;
+
+ if (Address == NULL) {
+ DEBUG((DEBUG_ERROR, "PchLpcMemRangeGet Error. Invalid pointer.\n"));
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ LpcBase = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC
+ );
+ if (SlaveDevice == LPC_ESPI_FIRST_SLAVE) {
+ *Address = MmioRead32 (LpcBase + R_PCH_LPC_LGMR) & B_PCH_LPC_LGMR_MA;
+ } else {
+ ASSERT(FALSE);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Set PCH BIOS range deocding.
+ This will check General Control and Status bit 10 (GCS.BBS) to identify SPI or LPC/eSPI and program BDE register accordingly.
+ Please check EDS for detail of BiosDecodeEnable bit definition.
+ bit 15: F8-FF Enable
+ bit 14: F0-F8 Enable
+ bit 13: E8-EF Enable
+ bit 12: E0-E8 Enable
+ bit 11: D8-DF Enable
+ bit 10: D0-D7 Enable
+ bit 9: C8-CF Enable
+ bit 8: C0-C7 Enable
+ bit 7: Legacy F Segment Enable
+ bit 6: Legacy E Segment Enable
+ bit 5: Reserved
+ bit 4: Reserved
+ bit 3: 70-7F Enable
+ bit 2: 60-6F Enable
+ bit 1: 50-5F Enable
+ bit 0: 40-4F Enable
+ This cycle decoding is allowed to set when DMIC.SRL is 0.
+ Programming steps:
+ 1. if GCS.BBS is 0 (SPI), program SPI offset D8h to BiosDecodeEnable.
+ if GCS.BBS is 1 (LPC/eSPi), program LPC offset D8h to BiosDecodeEnable.
+ 2. program LPC BIOS Decode Enable, PCR[DMI] + 2744h to the same value programmed in LPC or SPI Offset D8h.
+
+ @param[in] BiosDecodeEnable Bios decode enable setting.
+
+ @retval EFI_SUCCESS Successfully completed.
+ @retval EFI_UNSUPPORTED DMIC.SRL is set.
+**/
+EFI_STATUS
+EFIAPI
+PchBiosDecodeEnableSet (
+ IN UINT16 BiosDecodeEnable
+ )
+{
+ UINTN BaseAddr;
+ UINT32 DmiGcsBbs;
+ UINT32 Dmic;
+
+ PchPcrRead32 (PID_DMI, R_PCH_PCR_DMI_DMIC, &Dmic);
+ if ((Dmic & B_PCH_PCR_DMI_DMIC_SRL) != 0) {
+ DEBUG((DEBUG_ERROR, "PchBiosDecodeEnableSet Error. DMIC.SRL is set.\n"));
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ PchPcrRead32 (PID_DMI, R_PCH_PCR_DMI_GCS, &DmiGcsBbs);
+ DmiGcsBbs &= B_PCH_PCR_DMI_BBS;
+ //
+ // Check General Control and Status (GCS) [10]
+ // '0': SPI
+ // '1': LPC/eSPI
+ //
+ if (DmiGcsBbs == 0) {
+ BaseAddr = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_SPI,
+ PCI_FUNCTION_NUMBER_PCH_SPI
+ );
+ //
+ // if GCS.BBS is 0 (SPI), program SPI offset D8h to BiosDecodeEnable.
+ //
+ MmioWrite16 (BaseAddr + R_PCH_SPI_BDE, BiosDecodeEnable);
+ } else {
+ BaseAddr = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC
+ );
+ //
+ // if GCS.BBS is 1 (LPC/eSPi), program LPC offset D8h to BiosDecodeEnable.
+ //
+ MmioWrite16 (BaseAddr + R_PCH_LPC_BDE, BiosDecodeEnable);
+ }
+
+ //
+ // program LPC BIOS Decode Enable, PCR[DMI] + 2744h to the same value programmed in LPC or SPI Offset D8h.
+ //
+ PchPcrWrite16 (PID_DMI, R_PCH_PCR_DMI_LPCBDE, BiosDecodeEnable);
+ return EFI_SUCCESS;
+}
+
+/**
+ Set PCH LPC/eSPI IO decode ranges.
+ Program LPC/eSPI I/O Decode Ranges, PCR[DMI] + 2770h[15:0] to the same value programmed in LPC/eSPI PCI offset 80h.
+ Please check EDS for detail of LPC/eSPI IO decode ranges bit definition.
+ Bit 12: FDD range
+ Bit 9:8: LPT range
+ Bit 6:4: ComB range
+ Bit 2:0: ComA range
+
+ @param[in] LpcIoDecodeRanges LPC/eSPI IO decode ranges bit settings.
+
+ @retval EFI_SUCCESS Successfully completed.
+ @retval EFI_UNSUPPORTED DMIC.SRL is set.
+**/
+EFI_STATUS
+EFIAPI
+PchLpcIoDecodeRangesSet (
+ IN UINT16 LpcIoDecodeRanges
+ )
+{
+ UINTN LpcBaseAddr;
+ UINT32 Dmic;
+
+ //
+ // Note: Inside this function, don't use debug print since it's could used before debug print ready.
+ //
+
+ LpcBaseAddr = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC
+ );
+ //
+ // check if setting is identical
+ //
+ if (LpcIoDecodeRanges == MmioRead16 (LpcBaseAddr + R_PCH_LPC_IOD)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // This cycle decoding is only allowed to set when DMIC.SRL is 0.
+ //
+ PchPcrRead32 (PID_DMI, R_PCH_PCR_DMI_DMIC, &Dmic);
+ if ((Dmic & B_PCH_PCR_DMI_DMIC_SRL) != 0) {
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // program LPC/eSPI PCI offset 80h.
+ //
+ MmioWrite16 (LpcBaseAddr + R_PCH_LPC_IOD, LpcIoDecodeRanges);
+
+ //
+ // program LPC I/O Decode Ranges, PCR[DMI] + 2770h[15:0] to the same value programmed in LPC/eSPI PCI offset 80h.
+ //
+ PchPcrWrite16 (PID_DMI, R_PCH_PCR_DMI_LPCIOD, LpcIoDecodeRanges);
+ return EFI_SUCCESS;
+}
+
+/**
+ Set PCH LPC/eSPI IO enable decoding.
+ Setup LPC/eSPI I/O Enables, PCR[DMI] + 2774h[15:0] to the same value program in LPC/eSPI PCI offset 82h.
+ Note: Bit[15:10] of the source decode register is Read-Only. The IO range indicated by the Enables field
+ in LPC/eSPI PCI offset 82h[13:10] is always forwarded by DMI to subtractive agent for handling.
+ Please check EDS for detail of Lpc/eSPI IO decode ranges bit definition.
+
+ @param[in] LpcIoEnableDecoding LPC/eSPI IO enable decoding bit settings.
+
+ @retval EFI_SUCCESS Successfully completed.
+ @retval EFI_UNSUPPORTED DMIC.SRL is set.
+**/
+EFI_STATUS
+EFIAPI
+PchLpcIoEnableDecodingSet (
+ IN UINT16 LpcIoEnableDecoding
+ , IN UINT8 SlaveDevice
+ )
+{
+ UINTN LpcBaseAddr;
+ UINT32 Dmic;
+ UINTN LpcReg;
+
+ if (SlaveDevice == LPC_ESPI_FIRST_SLAVE) {
+ LpcReg = R_PCH_LPC_IOE;
+ } else {
+ ASSERT(FALSE);
+ }
+
+ //
+ // Note: Inside this function, don't use debug print since it's could used before debug print ready.
+ //
+
+ LpcBaseAddr = MmPciBase (
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC
+ );
+ if (LpcIoEnableDecoding == MmioRead16 (LpcBaseAddr + LpcReg)) {
+ return EFI_SUCCESS;
+ }
+ //
+ // This cycle decoding is only allowed to set when DMIC.SRL is 0.
+ //
+ PchPcrRead32 (PID_DMI, R_PCH_PCR_DMI_DMIC, &Dmic);
+ if ((Dmic & B_PCH_PCR_DMI_DMIC_SRL) != 0) {
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // program PCI offset 82h for LPC/eSPI CS#0 or offset A0h for eSPI CS#1.
+ //
+ MmioWrite16 (LpcBaseAddr + LpcReg, LpcIoEnableDecoding);
+
+ if (SlaveDevice == ESPI_SECONDARY_SLAVE) {
+ //
+ // For eSPI CS#1 device program PCI offset 82h respectively
+ //
+ MmioWrite16 (LpcBaseAddr + R_PCH_LPC_IOE, (LpcIoEnableDecoding | MmioRead16(LpcBaseAddr + R_PCH_LPC_IOE)));
+ }
+
+ //
+ // program LPC I/O Decode Ranges, PCR[DMI] + 2774h[15:0] to the same value programmed in LPC/eSPI PCI offset 82h.
+ //
+ PchPcrWrite16 (PID_DMI, R_PCH_PCR_DMI_LPCIOE, LpcIoEnableDecoding);
+ return EFI_SUCCESS;
+}
+
+
+//
+// PCH-LP RPR destination ID table
+//
+UINT16 PchLpRprDidTable[] = {
+ 0x2188, // Dest ID of RP1
+ 0x2189, // Dest ID of RP2
+ 0x218A, // Dest ID of RP3
+ 0x218B, // Dest ID of RP4
+ 0x2198, // Dest ID of RP5
+ 0x2199, // Dest ID of RP6
+ 0x219A, // Dest ID of RP7
+ 0x219B, // Dest ID of RP8
+ 0x21A8, // Dest ID of RP9
+ 0x21A9, // Dest ID of RP10
+ 0x21AA, // Dest ID of RP11
+ 0x21AB // Dest ID of RP12
+};
+
+//
+// PCH-H RPR destination ID table
+//
+UINT16 PchHRprDidTable[] = {
+ 0x2180, // Dest ID of RP1
+ 0x2181, // Dest ID of RP2
+ 0x2182, // Dest ID of RP3
+ 0x2183, // Dest ID of RP4
+ 0x2188, // Dest ID of RP5
+ 0x2189, // Dest ID of RP6
+ 0x218A, // Dest ID of RP7
+ 0x218B, // Dest ID of RP8
+ 0x2198, // Dest ID of RP9
+ 0x2199, // Dest ID of RP10
+ 0x219A, // Dest ID of RP11
+ 0x219B, // Dest ID of RP12
+ 0x21A8, // Dest ID of RP13
+ 0x21A9, // Dest ID of RP14
+ 0x21AA, // Dest ID of RP15
+ 0x21AB, // Dest ID of RP16
+ 0x21B8, // Dest ID of RP17
+ 0x21B9, // Dest ID of RP18
+ 0x21BA, // Dest ID of RP19
+ 0x21BB, // Dest ID of RP20
+};
+
+/**
+ Set PCH IO port 80h cycle decoding to PCIE root port.
+ System BIOS is likely to do this very soon after reset before PCI bus enumeration.
+ This cycle decoding is allowed to set when DMIC.SRL is 0.
+ Programming steps:
+ 1. Program "RPR Destination ID", PCR[DMI] + 274Ch[31:16] to the Dest ID of RP.
+ 2. Program "Reserved Page Route", PCR[DMI] + 274Ch[11] to '1'. Use byte write on GCS+1 and leave the BILD bit which is RWO.
+
+ @param[in] RpPhyNumber PCIE root port physical number.
+
+ @retval EFI_SUCCESS Successfully completed.
+**/
+EFI_STATUS
+EFIAPI
+PchIoPort80DecodeSet (
+ IN UINTN RpPhyNumber
+ )
+{
+ UINT32 Dmic;
+ UINT16 *PchRprDidTable;
+
+ PchPcrRead32 (PID_DMI, R_PCH_PCR_DMI_DMIC, &Dmic);
+ if ((Dmic & B_PCH_PCR_DMI_DMIC_SRL) != 0) {
+ DEBUG((DEBUG_ERROR, "PchIoPort80DecodeSet Error. DMIC.SRL is set.\n"));
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ ///
+ /// IO port 80h is typically used by decoder/LED hardware for debug purposes.
+ /// By default PCH will forward IO port 80h cycles to LPC bus. The Reserved Page Route (RPR) bit
+ /// of General Control and Status register, located at PCR[DMI] + 274Ch[11] , allows software to
+ /// re-direct IO port 80h cycles to PCIe bus so that a target (for example, a debug card) on
+ /// PCIe bus can receive and claim these cycles.
+ /// The "RPR Destination ID", PCR[DMI] + 274Ch[31:16] need to be set accordingly to point
+ /// to the root port that decode this range. Reading from Port 80h may not return valid values
+ /// if the POST-card itself do not shadow the writes. Unlike LPC, PCIe does not shadow the Port 80 writes.
+ ///
+
+ if (GetPchSeries () == PchLp) {
+ PchRprDidTable = PchLpRprDidTable;
+ } else {
+ PchRprDidTable = PchHRprDidTable;
+ }
+
+ //
+ // Program "RPR Destination ID", PCR[DMI] + 274Ch[31:16] to the Dest ID of RP.
+ //
+ PchPcrWrite16 (PID_DMI, R_PCH_PCR_DMI_GCS + 2, PchRprDidTable[RpPhyNumber]);
+ //
+ // Program "Reserved Page Route", PCR[DMI] + 274Ch[11] to '1'.
+ // Use byte write on GCS+1 and leave the BILD bit which is RWO.
+ //
+ PchPcrAndThenOr8 (PID_DMI, R_PCH_PCR_DMI_GCS + 1, 0xFF, (B_PCH_PCR_DMI_RPR >> 8));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get IO APIC regsiters base address.
+ It returns IO APIC INDEX, DATA, and EOI regsiter address once the parameter is not NULL.
+ This function will be unavailable after P2SB is hidden by PSF.
+
+ @param[out] IoApicIndex Buffer of IO APIC INDEX regsiter address
+ @param[out] IoApicData Buffer of IO APIC DATA regsiter address
+
+ @retval EFI_SUCCESS Successfully completed.
+**/
+EFI_STATUS
+PchIoApicBaseGet (
+ OPTIONAL OUT UINT32 *IoApicIndex,
+ OPTIONAL OUT UINT32 *IoApicData
+ )
+{
+ EFI_STATUS Status;
+ UINT16 RegIoac;
+ UINT32 RangeSelect;
+
+ Status = PchP2sbCfgGet16 (R_PCH_P2SB_IOAC, &RegIoac);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RangeSelect = (RegIoac & B_PCH_P2SB_IOAC_ASEL) << N_PCH_IO_APIC_ASEL;
+
+ if (IoApicIndex != NULL) {
+ *IoApicIndex = R_PCH_IO_APIC_INDEX + RangeSelect;
+ }
+ if (IoApicData != NULL) {
+ *IoApicData = R_PCH_IO_APIC_DATA + RangeSelect;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get HPET base address.
+ This function will be unavailable after P2SB is hidden by PSF.
+
+ @param[out] HpetBase Buffer of HPET base address
+
+ @retval EFI_SUCCESS Successfully completed.
+ @retval EFI_INVALID_PARAMETER Invalid offset passed.
+**/
+EFI_STATUS
+PchHpetBaseGet (
+ OUT UINT32 *HpetBase
+ )
+{
+ EFI_STATUS Status;
+ UINT8 RegHptc;
+
+ if (HpetBase == NULL) {
+ DEBUG((DEBUG_ERROR, "PchHpetBaseGet Error. Invalid pointer.\n"));
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = PchP2sbCfgGet8 (R_PCH_P2SB_HPTC, &RegHptc);
+
+ switch (RegHptc & B_PCH_P2SB_HPTC_AS) {
+ case 0:
+ *HpetBase = V_PCH_HPET_BASE0;
+ break;
+ case 1:
+ *HpetBase = V_PCH_HPET_BASE1;
+ break;
+ case 2:
+ *HpetBase = V_PCH_HPET_BASE2;
+ break;
+ case 3:
+ *HpetBase = V_PCH_HPET_BASE3;
+ break;
+ default:
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+