summaryrefslogtreecommitdiff
path: root/ReferenceCode/Chipset/LynxPoint/PchInit/Dxe/PchSerialIo.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Chipset/LynxPoint/PchInit/Dxe/PchSerialIo.c')
-rw-r--r--ReferenceCode/Chipset/LynxPoint/PchInit/Dxe/PchSerialIo.c997
1 files changed, 997 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/LynxPoint/PchInit/Dxe/PchSerialIo.c b/ReferenceCode/Chipset/LynxPoint/PchInit/Dxe/PchSerialIo.c
new file mode 100644
index 0000000..16e23a6
--- /dev/null
+++ b/ReferenceCode/Chipset/LynxPoint/PchInit/Dxe/PchSerialIo.c
@@ -0,0 +1,997 @@
+/** @file
+ Initializes the PCH Serial IO Controllers.
+
+@copyright
+ Copyright (c) 2012 - 2013 Intel Corporation. All rights reserved
+ This software and associated documentation (if any) is furnished
+ under a license and may only be used or copied in accordance
+ with the terms of the license. Except as permitted by such
+ license, no part of this software or documentation may be
+ reproduced, stored in a retrieval system, or transmitted in any
+ form or by any means without the express written consent of
+ Intel Corporation.
+
+ This file contains an 'Intel Peripheral Driver' and uniquely
+ identified as "Intel Reference Module" and is
+ licensed for Intel CPUs and chipsets under the terms of your
+ license agreement with Intel or your vendor. This file may
+ be modified by the user, subject to additional terms of the
+ license agreement
+
+**/
+#include "PchInit.h"
+
+#ifdef SERIAL_IO_FLAG
+#include "PchAslUpdateLib.h"
+
+#include EFI_PROTOCOL_DEPENDENCY (AcpiTable)
+
+
+
+#define SERIAL_IO_ADDRESS_AREA 0xFE101000;
+
+//
+// Resource Group Header
+//
+typedef struct {
+ UINT32 ResourceGroupLength;
+ UINT32 VendorId;
+ UINT32 SubVendorId;
+ UINT16 DeviceId;
+ UINT16 SubDeviceId;
+ UINT16 Revision;
+ UINT16 Reserved;
+ UINT32 SharedInfoLength;
+} EFI_ACPI_5_0_CSRT_RESOURCE_GROUP_HEADER;
+
+//
+// Resource Group1 Share Info
+//
+typedef struct {
+ UINT16 MajorVersion1;
+ UINT16 MinorVersion0;
+ UINT32 MmioBaseL;
+ UINT32 MmioBaseH;
+ UINT32 InterruptGSI;
+ UINT8 InterruptPolarity;
+ UINT8 InterruptMode;
+ UINT8 NumberofChannels;
+ UINT8 DMAAddressWidth;
+ UINT16 BaseRequestLine;
+ UINT16 NumberofHandshakeSignals;
+ UINT32 MaximumBlockTransferSize;
+} EFI_ACPI_5_0_RESOURCE_GROUP1_SHARED_INFO;
+
+//
+// Resource Descriptor Header
+//
+typedef struct {
+ UINT32 ResourceDescriptorLength;
+ UINT16 ResourceType;
+ UINT16 ResourceSubType;
+ UINT32 UID;
+} EFI_ACPI_5_0_CSRT_RESOURCE_DESCRIPTOR_HEADER;
+
+//
+// Core System Resources Table Structure (CSRT)
+//
+typedef struct {
+ EFI_ACPI_DESCRIPTION_HEADER Header;
+ EFI_ACPI_5_0_CSRT_RESOURCE_GROUP_HEADER ResourceGroup1;
+ EFI_ACPI_5_0_RESOURCE_GROUP1_SHARED_INFO ResourceGroup1SharedInfo;
+ EFI_ACPI_5_0_CSRT_RESOURCE_DESCRIPTOR_HEADER ControllerResourceDescriptor1;
+ EFI_ACPI_5_0_CSRT_RESOURCE_DESCRIPTOR_HEADER ChannelResourceDescriptor1[8];
+} EFI_ACPI_5_0_CORE_SYSTEM_RESOURCES_TABLE;
+
+typedef enum {
+ INDEX_DMA,
+ INDEX_I2C0,
+ INDEX_I2C1,
+ INDEX_SPI0,
+ INDEX_SPI1,
+ INDEX_UART0,
+ INDEX_UART1,
+ INDEX_SDIO,
+ MAX_SIO_INDEX
+} SIO_DEVICE;
+
+typedef struct {
+ UINT8 DevNum;
+ UINT8 FuncNum;
+ UINT32 DisableAddr;
+ UINT32 AcpiSwitchAddr;
+ UINT32 DeviceModeSwitchBit; // turns device into ACPI mode by hiding its PCI config space
+ UINT32 IrqModeSwitchBit; // turns device's interrupts into ACPI mode
+ UINT32 Signature;
+ UINT8 IrqPin;
+ UINT32 Bar0;
+ UINT32 Bar1;
+} SERIAL_IO_DEVICE_DESCRIPTOR;
+
+#define SERIAL_IO_DEVICE_QUANTITY 8
+
+SERIAL_IO_DEVICE_DESCRIPTOR SerialIoDevice [SERIAL_IO_DEVICE_QUANTITY] =
+{ {21, 0, 0xCE00AA07, 0xCB000240, BIT20, BIT21, EFI_SIGNATURE_32('S','D','M','A'), 2, 0xFE101000, 0xFE102000},
+ {21, 1, 0xCE00AA47, 0xCB000248, BIT20, BIT21, EFI_SIGNATURE_32('I','2','C','0'), 3, 0xFE103000, 0xFE104000},
+ {21, 2, 0xCE00AA87, 0xCB000250, BIT20, BIT21, EFI_SIGNATURE_32('I','2','C','1'), 3, 0xFE105000, 0xFE106000},
+ {21, 3, 0xCE00AAC7, 0xCB000258, BIT20, BIT21, EFI_SIGNATURE_32('S','P','I','0'), 3, 0xFE107000, 0xFE108000},
+ {21, 4, 0xCE00AB07, 0xCB000260, BIT20, BIT21, EFI_SIGNATURE_32('S','P','I','1'), 3, 0xFE109000, 0xFE10A000},
+ {21, 5, 0xCE00AB47, 0xCB000268, BIT20, BIT21, EFI_SIGNATURE_32('U','A','0','0'), 4, 0xFE10B000, 0xFE10C000},
+ {21, 6, 0xCE00AB87, 0xCB000270, BIT20, BIT21, EFI_SIGNATURE_32('U','A','0','1'), 4, 0xFE10D000, 0xFE10E000},
+ {23, 0, 0xCE00AE07, 0xCB000000, BIT4, BIT5, EFI_SIGNATURE_32('S','D','H','C'), 1, 0xFE110000, 0xFE112000}
+};
+
+EFI_STATUS
+InstallDmaAcpiTable (
+ IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy
+);
+
+BOOLEAN IsSerialIoDeviceEnabled (
+ SIO_DEVICE Device
+ )
+{
+ UINTN RegBase;
+ UINT32 VendorDeviceId;
+
+ RegBase = MmPciAddress (0, 0, SerialIoDevice[Device].DevNum, SerialIoDevice[Device].FuncNum, 0);
+ VendorDeviceId = MmioRead32 (RegBase + R_PCH_LP_SERIAL_IO_VENDOR_ID);
+ if (VendorDeviceId == 0xFFFFFFFF) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+/**
+ Disable Serial IO Controllers based on PchPlatformPolicy.
+
+ @param[in] PchPlatformPolicy The PCH Platform Policy protocol instance
+ @param[in] RootComplexBar RootComplexBar address of this PCH device
+
+ @retval None
+**/
+VOID
+DisableSerialIoControllers (
+ IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy,
+ IN UINT32 RootComplexBar
+ )
+{
+ UINT8 FunctionEnable[SERIAL_IO_DEVICE_QUANTITY];
+ UINTN Address;
+ UINT8 i;
+ BOOLEAN Func0Missing;
+
+ //
+ // Higher functions of a PCI device can't exist if there's no Function0
+ // This issue only applies in PCI mode, not in ACPI.
+ //
+ Func0Missing = PchPlatformPolicy->DeviceEnabling->SerialIoDma == PCH_DEVICE_DISABLE &&
+ PchPlatformPolicy->SerialIoConfig->SerialIoMode == PchSerialIoIsPci;
+
+ //
+ // DMA is useless without at least one SerialIo device
+ //
+ FunctionEnable[INDEX_DMA] = PchPlatformPolicy->DeviceEnabling->SerialIoDma &&
+ ( PchPlatformPolicy->DeviceEnabling->SerialIoI2c0 ||
+ PchPlatformPolicy->DeviceEnabling->SerialIoI2c1 ||
+ PchPlatformPolicy->DeviceEnabling->SerialIoSpi0 ||
+ PchPlatformPolicy->DeviceEnabling->SerialIoSpi1 ||
+ PchPlatformPolicy->DeviceEnabling->SerialIoUart0 ||
+ PchPlatformPolicy->DeviceEnabling->SerialIoUart1 ||
+ PchPlatformPolicy->DeviceEnabling->SerialIoSdio );
+
+ FunctionEnable[INDEX_I2C0] = PchPlatformPolicy->DeviceEnabling->SerialIoI2c0 && !Func0Missing;
+ FunctionEnable[INDEX_I2C1] = PchPlatformPolicy->DeviceEnabling->SerialIoI2c1 && !Func0Missing;
+ FunctionEnable[INDEX_SPI0] = PchPlatformPolicy->DeviceEnabling->SerialIoSpi0 && !Func0Missing;
+ FunctionEnable[INDEX_SPI1] = PchPlatformPolicy->DeviceEnabling->SerialIoSpi1 && !Func0Missing;
+ FunctionEnable[INDEX_UART0] = PchPlatformPolicy->DeviceEnabling->SerialIoUart0 && !Func0Missing;
+ FunctionEnable[INDEX_UART1] = PchPlatformPolicy->DeviceEnabling->SerialIoUart1 && !Func0Missing;
+ //
+ // SDIO doesn't care about DMA missing - it has its own device number
+ //
+ FunctionEnable[INDEX_SDIO] = PchPlatformPolicy->DeviceEnabling->SerialIoSdio;
+
+ DEBUG ((EFI_D_INFO, "DisableSerialIoControllers() Start\n"));
+
+ ///
+ /// PCH BIOS Spec Rev 0.7.0 Section 23.2 Disabling Serial IO Controllers
+ /// By default all controllers are enabled in hardware.
+ ///
+
+ for (i = 0; i < SERIAL_IO_DEVICE_QUANTITY; i++) {
+ if (FunctionEnable[i] == PCH_DEVICE_DISABLE) {
+ ///
+ /// Step 1
+ /// Set the Dx:Fx:84h[1:0] = 11b
+ ///
+ Address = MmPciAddress (0, 0, SerialIoDevice[i].DevNum, SerialIoDevice[i].FuncNum, R_PCH_LP_SERIAL_IO_PME_CTRL_STS);
+ MmioAndThenOr32WithScript(Address, (UINT32)~(B_PCH_LP_SERIAL_IO_PME_CTRL_STS_PWR_ST), BIT1 | BIT0 );
+ ///
+ /// Step 2
+ /// Program IOBP register CE00Axx7h[8] = 1b
+ ///
+ ProgramIobpWithScript (RootComplexBar, SerialIoDevice[i].DisableAddr, (UINT32)~(BIT8), BIT8);
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "DisableSerialIoControllers() End\n"));
+}
+
+UINT8
+GetSerialIoIrqNumber(
+ UINT8 DeviceNumber,
+ UINT8 InterruptPin,
+ UINT8 InterruptMode
+)
+{
+ UINT32 IrqRoute;
+ UINT8 InterruptRoute;
+ UINT32 RootComplexBar;
+ UINT32 IrqRoutingRegister;
+
+ if (InterruptMode == PchSerialIoIsAcpi) {
+ //
+ // ACPI IRQs are wired to irq pins 5,6,7,13
+ //
+ switch(InterruptPin) {
+ case 0x1:
+ return 5;
+ break;
+ case 0x2:
+ return 6;
+ break;
+ case 0x3:
+ return 7;
+ break;
+ case 0x4:
+ return 13;
+ break;
+ case 0x0:
+ default:
+ return 0;
+ }
+ } else {
+ if(InterruptPin > 0) {
+ //
+ // PCI INTs are first routed to PIRQs according to R_PCH_RCRB_D21IR / R_PCH_RCRB_D23IR register
+ //
+ RootComplexBar = MmioRead32 (
+ MmPciAddress (0,
+ 0,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ R_PCH_LPC_RCBA)
+ ) & B_PCH_LPC_RCBA_BAR;
+
+ if (DeviceNumber == 21) {
+ IrqRoutingRegister = R_PCH_RCRB_D21IR;
+ } else if (DeviceNumber == 23) {
+ IrqRoutingRegister = R_PCH_RCRB_D23IR;
+ } else {
+ ASSERT(FALSE);
+ return 0;
+ }
+ IrqRoute = MmioRead32 (RootComplexBar + IrqRoutingRegister);
+
+ InterruptRoute = ( IrqRoute >> (4* (InterruptPin-1) ) ) & 0x7;
+
+ //
+ // ...and PIRQs are wired to irq pins 16..23
+ // A 16, B 17, C 18, D 19, E 20, F 21, G 22, H 23
+ //
+ return (InterruptRoute + 16);
+ } else {
+ return 0;
+ }
+ }
+}
+
+
+/**
+ Update ASL definitions for SerialIo devices.
+
+ @param[in] PchPlatformPolicy The PCH Platform Policy protocol instance
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+UpdateSerialIoAcpiData (
+ IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy,
+ IN UINT32 RootComplexBar
+ )
+{
+
+ EFI_STATUS Status;
+ UINTN RegBase;
+ UINT32 Data32;
+ UINT16 GpioBase;
+ UINT8 i;
+
+ Status = InitializePchAslUpdateLib();
+
+ if(EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // ACPI code update for all devices
+ //
+ for (i=0; i<SERIAL_IO_DEVICE_QUANTITY; i++) {
+
+ if (!IsSerialIoDeviceEnabled(i)) {
+ continue;
+ }
+
+ RegBase = MmPciAddress (0, 0, SerialIoDevice[i].DevNum, SerialIoDevice[i].FuncNum, 0);
+
+ Data32 = (MmioRead32(RegBase + R_PCH_LP_SERIAL_IO_BAR0) & B_PCH_LP_SERIAL_IO_BAR0_BAR);
+ UpdateResourceTemplateAslCode(SerialIoDevice[i].Signature,
+ EFI_SIGNATURE_32 ('R', 'B', 'U', 'F'),
+ AML_MEMORY32_FIXED_OP,
+ 1,
+ 0x04,
+ &Data32,
+ sizeof(Data32)
+ );
+ }
+
+ //
+ // Update GPIO device ACPI variables
+ //
+ RegBase = MmPciAddress (0, 0, PCI_DEVICE_NUMBER_PCH_LPC, PCI_FUNCTION_NUMBER_PCH_LPC, 0);
+
+ GpioBase = (MmioRead16(RegBase + R_PCH_LPC_GPIO_BASE) & B_PCH_LPC_GPIO_BASE_BAR);
+
+ //
+ // Update _MIN[32:0] of the DWord Address Space Descriptor with GPIO BAR0
+ //
+ Data32 = (UINT32)GpioBase;
+ UpdateResourceTemplateAslCode((EFI_SIGNATURE_32 ('G', 'P', 'I', '0')),
+ (EFI_SIGNATURE_32 ('R', 'B', 'U', 'F')),
+ AML_DWORD_OP,
+ 1,
+ 0x0A,
+ &Data32,
+ sizeof(Data32)
+ );
+
+ //
+ // Update _MAX[32:0] of the DWord Address Space Descriptor with GPIO BAR0 + 3FFh
+ //
+ Data32 = (UINT32)GpioBase + 0x3FF;
+ UpdateResourceTemplateAslCode((EFI_SIGNATURE_32 ('G', 'P', 'I', '0')),
+ (EFI_SIGNATURE_32 ('R', 'B', 'U', 'F')),
+ AML_DWORD_OP,
+ 1,
+ 0x0E,
+ &Data32,
+ sizeof(Data32)
+ );
+
+
+ return Status;
+}
+
+/**
+ Hide PCI config space of Serial IO Controllers and do any final initialization.
+
+ @param[in] PchPlatformPolicy The PCH Platform Policy protocol instance
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+PutSerialIoInAcpiMode (
+ IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy,
+ IN UINT32 RootComplexBar
+ )
+{
+ EFI_STATUS Status;
+ UINTN Bar1;
+ UINTN RegBase;
+ UINT32 Data32;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ UINT8 i;
+
+ Status = EFI_SUCCESS;
+
+ Status = InitializePchAslUpdateLib();
+
+ if(EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // ACPI code update for all devices
+ //
+ for (i=0; i<SERIAL_IO_DEVICE_QUANTITY; i++) {
+
+ if (!IsSerialIoDeviceEnabled(i)) {
+ continue;
+ }
+
+ RegBase = MmPciAddress (0, 0, SerialIoDevice[i].DevNum, SerialIoDevice[i].FuncNum, 0);
+
+ Data32 = (MmioRead32(RegBase + R_PCH_LP_SERIAL_IO_BAR1) & B_PCH_LP_SERIAL_IO_BAR1_BAR);
+ UpdateResourceTemplateAslCode(EFI_SIGNATURE_32 ('S', 'I', 'R', 'C'),
+ EFI_SIGNATURE_32 ('B', 'U', 'F', ('1'+i)),
+ AML_MEMORY32_FIXED_OP,
+ 1,
+ 0x04,
+ &Data32,
+ sizeof(Data32)
+ );
+
+ Data32 = GetSerialIoIrqNumber(SerialIoDevice[i].DevNum, SerialIoDevice[i].IrqPin, PchPlatformPolicy->SerialIoConfig->SerialIoInterruptMode);
+ UpdateResourceTemplateAslCode(SerialIoDevice[i].Signature,
+ EFI_SIGNATURE_32 ('R', 'B', 'U', 'F'),
+ AML_INTERRUPT_DESC_OP,
+ 1,
+ 0x05,
+ &Data32,
+ sizeof(UINT8)
+ );
+
+ }
+
+ //
+ // Install DMA CSRT ACPI table as per ACPI5.0 spec
+ //
+ if(PchPlatformPolicy->DeviceEnabling->SerialIoDma == PCH_DEVICE_ENABLE) {
+ InstallDmaAcpiTable(PchPlatformPolicy);
+ }
+
+ ///
+ /// PCH BIOS Spec Rev 0.7.0 Section 23.6 Enable Serial IO PCI Controllers ACPI Mode
+ ///
+
+ for (i = 0; i < SERIAL_IO_DEVICE_QUANTITY; i++) {
+ ///
+ /// Check if SerialIo device is present
+ ///
+ if (!IsSerialIoDeviceEnabled(i)) {
+ continue;
+ }
+
+ ///
+ /// Get BAR1 Address
+ ///
+ Bar1 = MmioRead32(
+ MmPciAddress (0,
+ PchPlatformPolicy->BusNumber,
+ SerialIoDevice[i].DevNum,
+ SerialIoDevice[i].FuncNum,
+ R_PCH_LP_SERIAL_IO_BAR1)
+ ) & B_PCH_LP_SERIAL_IO_BAR1_BAR;
+
+ ///
+ /// Step 1
+ /// Program Dx:Fx:04h[2:1] = 11b
+ /// (skipped - this was performed while assigning BARs)
+ ///
+
+ ///
+ /// Step 2
+ /// Program Dx:Fx to ACPI Mode
+ ///
+ Data32And = 0xFFFFFFFF;
+ Data32Or = SerialIoDevice[i].DeviceModeSwitchBit;
+ ProgramIobpWithScript (RootComplexBar, SerialIoDevice[i].AcpiSwitchAddr, Data32And, Data32Or);
+
+ ///
+ /// Set D3Hot Power State via BAR1 Address, for all devices except DMA
+ ///
+ if(i != INDEX_DMA) {
+ Data32And = (UINT32) ~B_PCH_LP_SERIAL_IO_PME_CTRL_STS_PWR_ST;
+ Data32Or = B_PCH_LP_SERIAL_IO_PME_CTRL_STS_PWR_ST;
+
+ PCH_INIT_COMMON_SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ Bar1 + R_PCH_LP_SERIAL_IO_PME_CTRL_STS,
+ &Data32Or,
+ &Data32And
+ );
+ }
+
+ }
+
+ return Status;
+}
+
+/**
+ Assigns MMIO addresses for SerialIO controllers from a predefined pool
+
+ @retval None
+**/
+EFI_STATUS
+AssignBARs (
+ IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy
+)
+{
+ EFI_PHYSICAL_ADDRESS Bar;
+ EFI_PHYSICAL_ADDRESS RegBase;
+ EFI_STATUS Status;
+ UINTN i;
+ UINT64 TotalSize;
+ UINT32 IrqNumber;
+
+ Bar = SERIAL_IO_ADDRESS_AREA;
+ TotalSize = 2 * ((SERIAL_IO_DEVICE_QUANTITY - 1) * V_PCH_LP_SERIAL_IO_BAR_SIZE + V_PCH_LP_SERIAL_SDIO_BAR_SIZE);
+
+ Status = gDS->AddMemorySpace (
+ EfiGcdMemoryTypeReserved,
+ Bar,
+ TotalSize,
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ Status = gDS->AllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ EfiGcdMemoryTypeReserved,
+ N_PCH_LP_SERIAL_IO_BAR_ALIGNMENT,
+ TotalSize,
+ &Bar,
+ mImageHandle,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ for (i = 0; i < SERIAL_IO_DEVICE_QUANTITY; i++) {
+ if (!IsSerialIoDeviceEnabled(i)) {
+ continue;
+ }
+ RegBase = MmPciAddress (0, 0, SerialIoDevice[i].DevNum, SerialIoDevice[i].FuncNum, 0);
+
+ MmioAndThenOr32WithScript(RegBase + R_PCH_LP_SERIAL_IO_BAR0, 0x0, SerialIoDevice[i].Bar0);
+ MmioAndThenOr32WithScript(RegBase + R_PCH_LP_SERIAL_IO_BAR1, 0x0, SerialIoDevice[i].Bar1);
+
+ MmioAndThenOr32WithScript(RegBase + R_PCH_LP_SERIAL_IO_COMMAND,
+ 0xFFFFFFFF,
+ B_PCH_LP_SERIAL_IO_COMMAND_BME | B_PCH_LP_SERIAL_IO_COMMAND_MSE
+ );
+ IrqNumber = GetSerialIoIrqNumber(SerialIoDevice[i].DevNum, SerialIoDevice[i].IrqPin, PchPlatformPolicy->SerialIoConfig->SerialIoInterruptMode);
+ MmioAndThenOr32WithScript(RegBase + R_PCH_PCIE_INTR, (UINT32)~B_PCH_PCIE_INTR_ILINE, IrqNumber);
+ }
+ return Status;
+
+}
+
+
+/**
+ Hides SerialIo controllers from Pci config space
+ This prevents BIOS Pci enumerator from assigning mmio resources
+ SerialIo controllers will receive addresses from a separate pool
+
+ @param[in] RootComplexBar RootComplexBar address of this PCH device
+
+ @retval None
+**/
+VOID
+HideSerialIoDevices (
+ IN UINT32 RootComplexBar
+ )
+{
+ UINTN i;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+
+ for (i = 0; i < SERIAL_IO_DEVICE_QUANTITY; i++) {
+ Data32And = (UINT32) 0xFFFFFFFF;
+ Data32Or = (UINT32) SerialIoDevice[i].DeviceModeSwitchBit;
+
+ ProgramIobpWithScript (RootComplexBar, SerialIoDevice[i].AcpiSwitchAddr, Data32And, Data32Or);
+ }
+}
+
+/**
+ Reveals SerialIo controllers' Pci config space
+ This allows BIOS to complete initialization for those devices
+
+ @param[in] RootComplexBar RootComplexBar address of this PCH device
+
+ @retval None
+**/
+VOID
+RevealConfigSpace (
+ IN UINT32 RootComplexBar
+ )
+{
+ UINTN i;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+
+ for (i = 0; i < SERIAL_IO_DEVICE_QUANTITY; i++) {
+ Data32And = (UINT32)~(SerialIoDevice[i].DeviceModeSwitchBit);
+ Data32Or = (UINT32) 0x0;
+ ProgramIobpWithScript (RootComplexBar, SerialIoDevice[i].AcpiSwitchAddr, Data32And, Data32Or);
+ }
+}
+
+
+/**
+ Configures Serial IO Controllers
+
+ @param[in] PchPlatformPolicy The PCH Platform Policy protocol instance
+ @param[in] RootComplexBar RootComplexBar address of this PCH device
+
+ @retval None
+**/
+EFI_STATUS
+ConfigureSerialIoDevices (
+ IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy,
+ IN UINT32 RootComplexBar
+ )
+{
+ UINT8 Index;
+ UINTN RegBase;
+ UINTN Bar0;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ UINT8 i;
+
+ for (i = 0; i < INDEX_SDIO; i++) {
+ ///
+ /// Check if device is present
+ ///
+ if (!IsSerialIoDeviceEnabled(i)) {
+ continue;
+ }
+ RegBase = MmPciAddress (0, 0, SerialIoDevice[i].DevNum, SerialIoDevice[i].FuncNum, 0);
+
+ Bar0 = MmioRead32 (RegBase + R_PCH_LP_SERIAL_IO_BAR0);
+
+ if(i != PCI_FUNCTION_NUMBER_PCH_LP_SERIAL_IO_DMA) {
+ ///
+ /// PCH BIOS Spec Rev 0.7.0 Section 23.3 Serial IO LTR Programming
+ /// Step 1: Program BAR0 + 808h[2] = 0b
+ /// Step 2: Program BAR0 + 804h[1:0] = 00b
+ /// Step 3: Program BAR0 + 804h[1:0] = 11b
+ ///
+ MmioAndThenOr32WithScript (Bar0 + R_PCH_LP_SERIAL_IO_PPR_GEN, (UINT32)(~B_PCH_LP_SERIAL_IO_PPR_GEN_LTR_MODE), 0x0);
+ MmioAndThenOr32WithScript (Bar0 + R_PCH_LP_SERIAL_IO_PPR_RST, (UINT32)(~(B_PCH_LP_SERIAL_IO_PPR_RST_FUNC | B_PCH_LP_SERIAL_IO_PPR_RST_APB)), 0);
+ MmioAndThenOr32WithScript (Bar0 + R_PCH_LP_SERIAL_IO_PPR_RST, 0xFFFFFFFF, (UINT32)(B_PCH_LP_SERIAL_IO_PPR_RST_FUNC | B_PCH_LP_SERIAL_IO_PPR_RST_APB));
+
+ ///
+ /// Step 4
+ /// Program BAR0 + 814h with LTR value for each SerialIo controller
+ ///
+ MmioAndThenOr32WithScript(Bar0 + R_PCH_LP_SERIAL_IO_PPR_AUTO_LTR, 0, 0);
+ }
+
+ ///
+ /// PCH BIOS Spec Rev 0.7.0 Section 23.7 Serial IO Power Management Programming
+ /// Step 4
+ /// Program IO Voltage Select for I2C0 & I2C1 as per platform policy
+ ///
+ if(i == PCI_FUNCTION_NUMBER_PCH_LP_SERIAL_IO_I2C0) {
+ if (PchPlatformPolicy->SerialIoConfig->I2c0VoltageSelect == PchSerialIoIs33V) {
+ MmioAndThenOr32WithScript(Bar0 + R_PCH_LP_SERIAL_IO_PPR_GEN, (UINT32)~(B_PCH_LP_SERIAL_IO_PPR_GEN_IO_VOLTAGE_SEL), 0);
+ } else {
+ MmioAndThenOr32WithScript(Bar0 + R_PCH_LP_SERIAL_IO_PPR_GEN, 0xFFFFFFFF, B_PCH_LP_SERIAL_IO_PPR_GEN_IO_VOLTAGE_SEL);
+ }
+ }
+
+ if(i== PCI_FUNCTION_NUMBER_PCH_LP_SERIAL_IO_I2C1) {
+ if (PchPlatformPolicy->SerialIoConfig->I2c1VoltageSelect == PchSerialIoIs33V) {
+ MmioAndThenOr32WithScript(Bar0 + R_PCH_LP_SERIAL_IO_PPR_GEN, (UINT32)~(B_PCH_LP_SERIAL_IO_PPR_GEN_IO_VOLTAGE_SEL), 0);
+ } else {
+ MmioAndThenOr32WithScript(Bar0 + R_PCH_LP_SERIAL_IO_PPR_GEN, 0xFFFFFFFF, B_PCH_LP_SERIAL_IO_PPR_GEN_IO_VOLTAGE_SEL);
+ }
+ }
+
+ ///
+ /// PCH BIOS Spec Rev 0.7.0 Section 23.4 Serial IO Interrupt Programming
+ /// Step 4
+ /// Program D21:Fx to PCI Interrupt Mode
+ ///
+ Data32And = (UINT32)~(SerialIoDevice[i].IrqModeSwitchBit);
+ if(PchPlatformPolicy->SerialIoConfig->SerialIoInterruptMode == PchSerialIoIsAcpi) {
+ Data32Or = SerialIoDevice[i].IrqModeSwitchBit;
+ } else {
+ Data32Or = 0x00;
+ }
+
+ ///
+ /// PCH BIOS Spec Rev 0.7.0 Section 23.7 Serial IO Power Management Programming
+ /// Step 5
+ /// Program D21:Fx FAB_PM_CAP_PRSNT_PORT0
+ ///
+ Data32Or |= BIT1;
+ ProgramIobpWithScript (RootComplexBar, SerialIoDevice[i].AcpiSwitchAddr, Data32And, Data32Or);
+ }
+
+ ///
+ /// Check if SDIO device is present
+ ///
+ if (IsSerialIoDeviceEnabled(INDEX_SDIO)) {
+
+ RegBase = MmPciAddress (0, 0, SerialIoDevice[INDEX_SDIO].DevNum, SerialIoDevice[INDEX_SDIO].FuncNum, 0);
+
+ Bar0 = MmioRead32 (RegBase + R_PCH_LP_SERIAL_IO_BAR0);
+
+ MmioAndThenOr32WithScript (Bar0 + R_PCH_LP_SERIAL_IO_SDIO_SLAVE_DELAY_DDR50_MODE, 0, 0x00000306);
+
+
+ ///
+ /// PCH BIOS Spec Rev 0.3.0 Section 23.3 Serial IO LTR Programming
+ /// Step 5
+ /// Program BAR0 + 1008h[2] = 1b
+ ///
+ MmioAndThenOr32WithScript (Bar0 + R_PCH_LP_SERIAL_IO_SDIO_PPR_GEN, 0xFFFFFFFF, B_PCH_LP_SERIAL_IO_SDIO_PPR_GEN_LTR_MODE);
+
+ ///
+ /// Step 6
+ /// Program BAR0 + 1010h = 0x00000000 for SDIO controller
+ ///
+ Data32And = 0x00000000;
+ MmioAndThenOr32WithScript (Bar0 + R_PCH_LP_SERIAL_IO_SDIO_PPR_SW_LTR, 0, 0);
+
+ ///
+ /// Program D23:F0 to PCI Interrupt Mode
+ ///
+ Data32And = (UINT32)~(SerialIoDevice[INDEX_SDIO].IrqModeSwitchBit);
+ if(PchPlatformPolicy->SerialIoConfig->SerialIoInterruptMode == PchSerialIoIsAcpi) {
+ Data32Or = SerialIoDevice[INDEX_SDIO].IrqModeSwitchBit;
+ } else {
+ Data32Or = 0x00;
+ }
+ ProgramIobpWithScript (RootComplexBar, SerialIoDevice[INDEX_SDIO].AcpiSwitchAddr, Data32And, Data32Or);
+ }
+
+ ///
+ /// PCH BIOS Spec Rev 0.7.0 Section 23.4 Serial IO Interrupt Programing
+ ///
+ if(PchPlatformPolicy->SerialIoConfig->SerialIoInterruptMode == PchSerialIoIsAcpi) {
+ ///
+ /// Enable ACPI IRQ for IRQ13, IRQ7, IRQ6, IRQ5 in RCRB
+ ///
+ Data32Or = (B_PCH_RCRB_INT_ACPIIRQEN_A13E | B_PCH_RCRB_INT_ACPIIRQEN_A7E | B_PCH_RCRB_INT_ACPIIRQEN_A6E | B_PCH_RCRB_INT_ACPIIRQEN_A5E);
+ MmioAndThenOr32WithScript((UINTN)(RootComplexBar + R_PCH_RCRB_INT_ACPIIRQEN), 0xFFFFFFFF, Data32Or);
+ }
+
+#ifdef ULT_FLAG
+ if (GetPchSeries() == PchLp) {
+ for (Index = 0; Index < (sizeof (PchSerialIoIntsLptLp) / sizeof (IOBP_MMIO_TABLE_STRUCT)); Index++) {
+ ///
+ /// Program IOBP register
+ ///
+ Data32And = PchSerialIoIntsLptLp[Index].AndMask;
+ Data32Or = PchSerialIoIntsLptLp[Index].OrMask;
+ ProgramIobpWithScript (RootComplexBar, PchSerialIoIntsLptLp[Index].Address, Data32And, Data32Or);
+ }
+ }
+#endif //ULT_FLAG
+
+ ///
+ /// PCH BIOS Spec Rev 0.3.0 Section 31.22.6 Serial IO Power Management Programming
+ /// Step 1
+ /// Program CB000154h[12,9:8,4:0] = 1001100011111b
+ ///
+ Data32And = (UINT32)~(BIT12 | BIT9 | BIT8 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0);
+ Data32Or = (UINT32) (BIT12 | BIT9 | BIT8 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0);
+
+ if (PchPlatformPolicy->Revision >= DXE_PCH_PLATFORM_POLICY_PROTOCOL_REVISION_6) {
+ if (PchPlatformPolicy->SerialIoConfig->Ddr50Support) {
+ Data32Or |= BIT6;
+ }
+ }
+
+ ProgramIobpWithScript (RootComplexBar, 0xCB000154, Data32And, Data32Or);
+
+ ///
+ /// Step 2
+ /// Programming done above
+ ///
+ /// Step 3
+ /// Program CB000180h[5:0] = 111111b
+ ///
+ Data32And = (UINT32)~(BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0);
+ Data32Or = (UINT32) (BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0);
+ ProgramIobpWithScript (RootComplexBar, 0xCB000180, Data32And, Data32Or);
+
+#ifdef ULT_FLAG
+ if (GetPchSeries() == PchLp) {
+ ///
+ /// PCH BIOS Spec Rev 0.3.0 Section 23.8 Serial IO Snoop Programing
+ ///
+ for (Index = 0; Index < (sizeof (PchSerialIoSnoopLptLp) / sizeof (IOBP_MMIO_TABLE_STRUCT)); Index++) {
+ ///
+ /// Program IOBP register
+ ///
+ ProgramIobpWithScript (
+ RootComplexBar,
+ PchSerialIoSnoopLptLp[Index].Address,
+ PchSerialIoSnoopLptLp[Index].AndMask,
+ PchSerialIoSnoopLptLp[Index].OrMask
+ );
+ }
+ }
+#endif // ULT_FLAG
+
+ return EFI_SUCCESS;
+}
+
+VOID
+ConfigureSerialIoAtBoot (
+ IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy
+ )
+{
+ UINTN i;
+ UINT8 FunctionEnable[SERIAL_IO_DEVICE_QUANTITY];
+
+ if (PchPlatformPolicy->SerialIoConfig->SerialIoMode != PchSerialIoIsAcpi) {
+ return;
+ }
+
+ FunctionEnable[INDEX_I2C0] = PchPlatformPolicy->DeviceEnabling->SerialIoI2c0;
+ FunctionEnable[INDEX_I2C1] = PchPlatformPolicy->DeviceEnabling->SerialIoI2c1;
+ FunctionEnable[INDEX_SPI0] = PchPlatformPolicy->DeviceEnabling->SerialIoSpi0;
+ FunctionEnable[INDEX_SPI1] = PchPlatformPolicy->DeviceEnabling->SerialIoSpi1;
+ FunctionEnable[INDEX_UART0] = PchPlatformPolicy->DeviceEnabling->SerialIoUart0;
+ FunctionEnable[INDEX_UART1] = PchPlatformPolicy->DeviceEnabling->SerialIoUart1;
+ FunctionEnable[INDEX_SDIO] = PchPlatformPolicy->DeviceEnabling->SerialIoSdio;
+
+ for (i=INDEX_I2C0; i<MAX_SIO_INDEX; i++) {
+ if (!FunctionEnable[i]) {
+ continue;
+ }
+
+ ///
+ /// Set D3Hot Power State via BAR1 Address, for all devices except DMA
+ ///
+ if(i != INDEX_DMA) {
+ MmioAndThenOr32 (SerialIoDevice[i].Bar1 + R_PCH_LP_SERIAL_IO_PME_CTRL_STS,
+ (UINT32) ~B_PCH_LP_SERIAL_IO_PME_CTRL_STS_PWR_ST,
+ B_PCH_LP_SERIAL_IO_PME_CTRL_STS_PWR_ST
+ );
+ MmioRead32(SerialIoDevice[i].Bar1 + R_PCH_LP_SERIAL_IO_PME_CTRL_STS);
+ }
+ }
+}
+
+
+/**
+ Configures Serial IO Controllers after Pci Enum
+
+ @param[in] PchPlatformPolicy The PCH Platform Policy protocol instance
+ @param[in] RootComplexBar RootComplexBar address of this PCH device
+
+ @retval None
+**/
+EFI_STATUS
+ConfigureSerialIoBeforeBoot (
+ IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy,
+ IN UINT32 RootComplexBar
+ )
+{
+
+ RevealConfigSpace(RootComplexBar);
+ DisableSerialIoControllers(PchPlatformPolicy, RootComplexBar);
+ AssignBARs(PchPlatformPolicy);
+ ConfigureSerialIoDevices(PchPlatformPolicy, RootComplexBar);
+ UpdateSerialIoAcpiData(PchPlatformPolicy, RootComplexBar);
+
+ if (PchPlatformPolicy->SerialIoConfig->SerialIoMode == PchSerialIoIsAcpi) {
+ PutSerialIoInAcpiMode(PchPlatformPolicy, RootComplexBar);
+ }
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+ConfigureSerialIo (
+ IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy,
+ IN UINT32 RootComplexBar
+ )
+{
+ HideSerialIoDevices(RootComplexBar);
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+InstallDmaAcpiTable (
+ IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy
+)
+{
+ UINTN AcpiTableKey;
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
+ EFI_ACPI_5_0_CORE_SYSTEM_RESOURCES_TABLE *CoreSystemResourcesTable;
+ UINT64 Data64;
+ UINT32 Data32;
+ UINTN RegBase;
+ UINT8 Index;
+ EFI_STATUS Status;
+ UINT32 IrqNumber;
+
+ AcpiTable = NULL;
+ CoreSystemResourcesTable = NULL;
+ AcpiTableKey = 0;
+
+ //
+ // Locate ACPI support protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, &AcpiTable);
+ if( EFI_ERROR(Status) || AcpiTable == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Allocate Memory for Core System Resources Table
+ //
+ CoreSystemResourcesTable = AllocateZeroPool(sizeof(EFI_ACPI_5_0_CORE_SYSTEM_RESOURCES_TABLE));
+
+ if(CoreSystemResourcesTable == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CoreSystemResourcesTable->Header.Signature = EFI_SIGNATURE_32('C','S','R','T');
+ CoreSystemResourcesTable->Header.Length = sizeof(EFI_ACPI_5_0_CORE_SYSTEM_RESOURCES_TABLE);
+ CoreSystemResourcesTable->Header.Revision = 0x01;
+ CoreSystemResourcesTable->Header.Checksum = 0x00;
+ Data64 = EFI_SIGNATURE_64 ('I', 'N', 'T', 'L', 0, 0, 0, 0);
+ CopyMem (&CoreSystemResourcesTable->Header.OemId, &Data64, sizeof(CoreSystemResourcesTable->Header.OemId));
+ Data64 = EFI_SIGNATURE_64 ('H', 'S', 'W', 'U', 'L', 'T', '-', 'R');
+ CopyMem (&CoreSystemResourcesTable->Header.OemTableId, &Data64, sizeof(CoreSystemResourcesTable->Header.OemTableId));
+ CoreSystemResourcesTable->Header.OemRevision = 0x00000001;
+ CoreSystemResourcesTable->Header.CreatorId = EFI_SIGNATURE_32('I','N','T','L');
+ CoreSystemResourcesTable->Header.CreatorRevision = 0x20100528;
+
+ CoreSystemResourcesTable->ResourceGroup1.ResourceGroupLength = sizeof(EFI_ACPI_5_0_CORE_SYSTEM_RESOURCES_TABLE) - sizeof(EFI_ACPI_DESCRIPTION_HEADER);
+ CoreSystemResourcesTable->ResourceGroup1.VendorId = EFI_SIGNATURE_32('I','N','T','L');
+ CoreSystemResourcesTable->ResourceGroup1.SubVendorId = 0x00000000;
+ CoreSystemResourcesTable->ResourceGroup1.DeviceId = 0x9C60;
+ CoreSystemResourcesTable->ResourceGroup1.SubDeviceId = 0x0000;
+ CoreSystemResourcesTable->ResourceGroup1.Revision = 0x0001;
+ CoreSystemResourcesTable->ResourceGroup1.Reserved = 0x0000;
+ CoreSystemResourcesTable->ResourceGroup1.SharedInfoLength = 0x00000001C;
+ CoreSystemResourcesTable->ResourceGroup1SharedInfo.MajorVersion1 = 0x001;
+ CoreSystemResourcesTable->ResourceGroup1SharedInfo.MinorVersion0 = 0x000;
+
+ RegBase = MmPciAddress (0, 0, SerialIoDevice[INDEX_DMA].DevNum, SerialIoDevice[INDEX_DMA].FuncNum, 0);
+ Data32 = (MmioRead32(RegBase + R_PCH_LP_SERIAL_IO_BAR0) & B_PCH_LP_SERIAL_IO_BAR0_BAR);
+ CoreSystemResourcesTable->ResourceGroup1SharedInfo.MmioBaseL = Data32;
+ CoreSystemResourcesTable->ResourceGroup1SharedInfo.MmioBaseH = 0x00000000;
+ //
+ // Match DMA interrupt value
+ //
+ IrqNumber = GetSerialIoIrqNumber(SerialIoDevice[INDEX_DMA].DevNum, SerialIoDevice[INDEX_DMA].IrqPin, PchPlatformPolicy->SerialIoConfig->SerialIoInterruptMode);
+ CoreSystemResourcesTable->ResourceGroup1SharedInfo.InterruptGSI = IrqNumber;
+
+ CoreSystemResourcesTable->ResourceGroup1SharedInfo.InterruptPolarity = 0x02;
+ CoreSystemResourcesTable->ResourceGroup1SharedInfo.InterruptMode = 0x00;
+ CoreSystemResourcesTable->ResourceGroup1SharedInfo.NumberofChannels = 0x08;
+ CoreSystemResourcesTable->ResourceGroup1SharedInfo.DMAAddressWidth = 0x20;
+
+ CoreSystemResourcesTable->ResourceGroup1SharedInfo.BaseRequestLine = 0x0010;
+ CoreSystemResourcesTable->ResourceGroup1SharedInfo.NumberofHandshakeSignals = 0x0010;
+ CoreSystemResourcesTable->ResourceGroup1SharedInfo.MaximumBlockTransferSize = 0x00000FFF;
+
+ CoreSystemResourcesTable->ControllerResourceDescriptor1.ResourceDescriptorLength = 0x0000000C;
+ CoreSystemResourcesTable->ControllerResourceDescriptor1.ResourceType = 0x0003;
+ CoreSystemResourcesTable->ControllerResourceDescriptor1.ResourceSubType = 0x0001;
+ CoreSystemResourcesTable->ControllerResourceDescriptor1.UID = 0x20495053;
+
+ Data32 = 0x30414843;
+ for(Index = 0; Index < 8; Index++) {
+ CoreSystemResourcesTable->ChannelResourceDescriptor1[Index].ResourceDescriptorLength = 0x0000000C;
+ CoreSystemResourcesTable->ChannelResourceDescriptor1[Index].ResourceType = 0x0003;
+ CoreSystemResourcesTable->ChannelResourceDescriptor1[Index].ResourceSubType = 0x0000;
+ CoreSystemResourcesTable->ChannelResourceDescriptor1[Index].UID = Data32;
+ Data32 += 0x1000000;
+ }
+ Status = AcpiTable->InstallAcpiTable (AcpiTable, CoreSystemResourcesTable, CoreSystemResourcesTable->Header.Length, &AcpiTableKey);
+ return Status;
+}
+
+
+
+#endif // SERIAL_IO_FLAG
+
+
+