alder_lake_bios/Insyde/InsydeSamplePkg/ASM1061Dxe/ASM1061Dxe.c

390 lines
11 KiB
C

/** @file
ASM1061Dxe driver will set ASM1061 related PCI setting for compatibility concerns
;******************************************************************************
;* Copyright (c) 2016, Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
#include <Uefi.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/S3BootScriptLib.h>
#include <Library/PciExpressLib.h>
#include <Library/PcdLib.h>
#include <Library/VariableLib.h>
#include <Library/TimerLib.h>
#include <Protocol/PlatformPhaseNotify.h>
#define PrimayBusNumber 0x1c
#define PrimaryDeviceNumber 0x02
#define LINK_CAPABILTIES_REG 0x0c
#define Device_Control_REG 0x08
#define PCI_CAPBILITY_POINTER_OFFSET 0x34
#define EFI_PCI_CAPABILITY_ID_PCIEXP 0x10
#pragma optimize("", off)
/**
A function to search the ASPM register location (offset) by using the capability register
to trace and identify if the capability ID match 0x10.
@param Bus The PCIE bus number of the searching device
@param Dev The PCIE device number of the searching device
@param Fun The PCIE function number of the searching device
@retval 0 No PCIExpress capability register
@retval Register The PCIExpress capability register offset of given PCIE device
**/
UINT16
FindPCIECapOffset (
IN UINT8 Bus,
IN UINT8 Dev,
IN UINT8 Fun
)
{
UINT16 Reg;
UINT16 Cap;
UINT16 Data16;
Data16 = PciExpressRead16 (PCI_EXPRESS_LIB_ADDRESS (Bus, Dev, Fun, PCI_CAPBILITY_POINTER_OFFSET));
if (((Data16 & 0x00FF) == 0x00) || ((Data16 & 0x00FF) == 0xFF)) {
return 0x00;
} else {
Data16 &= 0x00FF;
Data16 <<= 8;
}
do {
Reg = (Data16 >> 8);
Data16 = PciExpressRead16 (PCI_EXPRESS_LIB_ADDRESS (Bus, Dev, Fun, Reg));
Cap = (Data16 & 0x00FF);
} while ((Cap != EFI_PCI_CAPABILITY_ID_PCIEXP) && ( (Data16 >> 8) != 0x00));
if (Cap != EFI_PCI_CAPABILITY_ID_PCIEXP) {
return 0x00;
} else {
return Reg;
}
}
STATIC
VOID
EFIAPI
ASM1061NotifyFunction (
IN EFI_EVENT Event,
IN VOID *Context
)
{
UINT32 SubClassCode;
UINT64 BootScriptPciAddress;
UINT8 Register;
UINT32 *Bus;
UINT8 RevID;
UINT16 LINKCapOffset;
UINT16 LINKCap;
UINT8 Data;
UINT8 DataMask;
EFI_STATUS Status;
Bus = (UINT32*) PcdGetPtr (PcdAhciPcieBridgeAddress);
//
// PrimayBusNumber and PrimaryDeviceNumber are varied with different projects
//
LINKCapOffset = FindPCIECapOffset(PrimayBusNumber, PrimaryDeviceNumber, 0);
//
// below code follow ASM1061 A3 system BIOS Programming Supplement v1.0
//
RevID = PciExpressRead8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0x08));
if (RevID >= 0x02) {
//
// recommended set to 1 to improve S4 wake-up time on Microsoft Window 8 operating system.
//
//
PciExpressOr8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0xfd), BIT0);
//
//Bit 7 is recommended to set to satisfy AHCI specification.
//Bit 6 is a reserved bit. Don't set this bit.
//Bit 5 is recommended to set to support ATAPI device that capacity is greater than 800 GB
//Bit 4 is recommended to set to support ATA and ATAPI device are connected on ASM1061
//Bit 3, 2 can be set to disable SATA 6G support. It is not recommended to disable SATA 6G
//
PciExpressOr8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0xfe), BIT7 | BIT5 | BIT4);
if (LINKCapOffset > 0) {
LINKCap = PciExpressRead16(LINKCapOffset + LINK_CAPABILTIES_REG);
if (LINKCap && 0x0800)
//
//Bit 1, 0 are recommended to set if PCIE ASPM L1 is supported on platform,
//
PciExpressOr8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0xfe), 0x03);
}
//
// Bit 7 is recommended to set to satisfy AHCI specification.
// Bit 6 can be set on ASM1061 A3 only. Don't set this bit on A2 or previous version.
// Bit 5, 4, 3, 2 are reserved. Don't program these bit
// Bit 1, 0 can be set to modify AHCI PxCMD.ESP and HPCP bit. Please refer to below
//
PciExpressOr8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0xff), BIT7 | BIT6);
//
//AHCI specification defines that CAP.SXS and PxCMD.HPCP are read
//only bits. They can't be modified by software. ASM106x provides other PCI
//registers to modify these AHCI read only bits - RxE5C[5] for modifying
//CAP.SXS, RxFF[0] for modifying Port 0 PxCMD.HCPC and RxFF[1] for
//modifying Port 1 PxCMD.HCPC.
//
//
// To disable eSATA and hot-plug for AHCI Mode, please set
//
PciExpressAnd8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0xE5C), (UINT8)(~BIT5));
PciExpressAnd8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0xff), (UINT8)(~BIT0));
PciExpressAnd8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0xff), (UINT8)(~BIT1));
}
//
// 2. Set PCI Subclass Code for SATA Controller
//
SubClassCode = PciExpressRead8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0x0A));
if (SubClassCode == 0x01) {
//
// enable subclass to be programmed
//
PciExpressOr8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0xec), BIT2);
BootScriptPciAddress = S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (Bus[0], 0, 0, 0xec);
Data = BIT2;
DataMask = (UINT8)(~BIT2);
Status = S3BootScriptSavePciCfgReadWrite(
S3BootScriptWidthUint8,
BootScriptPciAddress,
&Data,
&DataMask);
//
// Set Subclass Code
//
PciExpressWrite8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0xa), 0x06);
BootScriptPciAddress = S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (Bus[0], 0, 0, 0xa);
Register = 0x6;
Status = S3BootScriptSavePciCfgWrite (
S3BootScriptWidthUint8,
BootScriptPciAddress,
1,
&Register
);
//
// disable subclass to be programmed
//
PciExpressAnd8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0xec), (UINT8)(~BIT2));
BootScriptPciAddress = S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (Bus[0], 0, 0, 0xec);
Data = 0;
DataMask = (UINT8)(~BIT2);
Status = S3BootScriptSavePciCfgReadWrite(
S3BootScriptWidthUint8,
BootScriptPciAddress,
&Data,
&DataMask);
}
//
// SATA Optimal Setting for Devices Compatibility
// all should be set before Spin-up and PCI resources assigned
//
PciExpressWrite8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0xcae), 0x92);
BootScriptPciAddress = S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (Bus[0], 0, 0, 0xcae);
Register = 0x92;
Status = S3BootScriptSavePciCfgWrite (
S3BootScriptWidthUint8,
BootScriptPciAddress,
1,
&Register
);
PciExpressWrite8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0xda5), 0x26);
BootScriptPciAddress = S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (Bus[0], 0, 0, 0xda5);
Register = 0x26;
Status = S3BootScriptSavePciCfgWrite (
S3BootScriptWidthUint8,
BootScriptPciAddress,
1,
&Register
);
PciExpressWrite8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0xdae), 0x92);
BootScriptPciAddress = S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (Bus[0], 0, 0, 0xdae);
Register = 0x92;
Status = S3BootScriptSavePciCfgWrite (
S3BootScriptWidthUint8,
BootScriptPciAddress,
1,
&Register
);
PciExpressWrite8(PCI_EXPRESS_LIB_ADDRESS(0x01, 0, 0, 0xca4), 0xab);
BootScriptPciAddress = S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (Bus[0], 0, 0, 0xca4);
Register = 0xab;
Status = S3BootScriptSavePciCfgWrite (
S3BootScriptWidthUint8,
BootScriptPciAddress,
1,
&Register
);
PciExpressWrite8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0xda4), 0xab);
BootScriptPciAddress = S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (Bus[0], 0, 0, 0xda4);
Register = 0xab;
Status = S3BootScriptSavePciCfgWrite (
S3BootScriptWidthUint8,
BootScriptPciAddress,
1,
&Register
);
//
// L0s state must be disabled in ASM106x for PCIE compatibility. Set
//PCI RxA01[0] = 0 to disable ASM106x PCIE L0s active state power
//management.
//
// PciExpressOr8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0xa01), BIT0);
//
//Microsoft WHCK will check the L0s supported bit in PCIE Link
//Capabilities Register (offset 0x0C bit 10), PCI RxA01[0] must be set 1 to
//pass WHCK test.
//
PciExpressAnd8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0xa01), (UINT8)(~BIT1));
Data = 0;
DataMask = (UINT8)(~BIT1);
Status = S3BootScriptSavePciCfgReadWrite(
S3BootScriptWidthUint8,
BootScriptPciAddress,
&Data,
&DataMask);
//
// Internal Regulator Setting
//
PciExpressOr8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0xa12), BIT4|BIT3);
Data = BIT4|BIT3;
DataMask = 0Xff;
Status = S3BootScriptSavePciCfgReadWrite(
S3BootScriptWidthUint8,
BootScriptPciAddress,
&Data,
&DataMask);
//
//S4 wake up improved
//
PciExpressOr8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0xfd), BIT0);
Data = BIT0;
DataMask = 0Xff;
Status = S3BootScriptSavePciCfgReadWrite(
S3BootScriptWidthUint8,
BootScriptPciAddress,
&Data,
&DataMask);
//
//SSC mode set to 0~-1250ppm can reduce ElectroMagnetic Interference
//(EMI). The SSC enable bit must be delayed at least 100 ns to set after other
//bits are set
//
//
// 1. Set RxA10[4:2] = 2'011b, SSC mode 0~-1250ppm, 1:1 modulation
//
PciExpressAndThenOr8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0xa10), (UINT8)(~BIT4), BIT2 | BIT3);
//
// 2. Delay 100 ns at least
//
NanoSecondDelay(100);
//
//3. Set RxA10[0] = 1, SSC enable
//
PciExpressOr8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0xa10), BIT0);
//
//15. PCIE Max Payload Size Compatibility
//strong recommend that don't set the Max Payload Size and remain
//the default value 3'000b for ASM1061.
//
if (PciExpressRead8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0x88) && 0xE0) > 0) {
PciExpressAnd8(PciExpressRead8(PCI_EXPRESS_LIB_ADDRESS(Bus[0], 0, 0, 0x88), 0x1f);
}
gBS->CloseEvent (Event);
}
EFI_STATUS
EFIAPI
ASM1061DxeEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_EVENT Event;
VOID *Registration;
//
// Registers the gEfiPciEnumerationCompleteProtocolGuid protocol notification for PCIe port switching
//
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
ASM1061NotifyFunction,
NULL,
&Event
);
if (Status == EFI_SUCCESS) {
Status = gBS->RegisterProtocolNotify (
&gEfiPciHostBridgeEndResourceAllocationNotifyGuid,
Event,
&Registration
);
}
return Status;
}
#pragma optimize("", on)