summaryrefslogtreecommitdiff
path: root/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/AudioInit.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/AudioInit.c')
-rw-r--r--ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/AudioInit.c849
1 files changed, 849 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/AudioInit.c b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/AudioInit.c
new file mode 100644
index 0000000..a55603a
--- /dev/null
+++ b/ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/AudioInit.c
@@ -0,0 +1,849 @@
+/** @file
+ This is the driver that initializes the CPU Audio device.
+
+@copyright
+ Copyright (c) 1999 - 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 "AudioInit.h"
+
+extern SYSTEM_AGENT_GLOBAL_NVS_AREA_PROTOCOL mSaGlobalNvsAreaProtocol;
+
+///
+/// Global variables
+///
+UINT32 *mVerbCodecSaveAddress = NULL;
+UINT8 mVerbCount = 0;
+
+UINT32 mSaHdaVerbTableDataDefault[] = {
+ ///
+ /// Audio Verb Table - 0x80862807
+ ///
+ ///
+ /// Pin Widget 5 - PORT B
+ ///
+ 0x00571C10,
+ 0x00571D00,
+ 0x00571E56,
+ 0x00571F18,
+ ///
+ /// Pin Widget 6 - PORT C
+ ///
+ 0x00671C20,
+ 0x00671D00,
+ 0x00671E56,
+ 0x00671F18,
+ ///
+ /// Pin Widget 7 - PORT D
+ ///
+ 0x00771C30,
+ 0x00771D00,
+ 0x00771E56,
+ 0x00771F18
+};
+
+SA_HDA_VERB_TABLE mSaHdaVerbTableDefault[] = {
+ {
+ ///
+ /// VerbTable:
+ /// Revision ID = 0xFF
+ /// Codec Vendor: 0x80862807
+ ///
+ {
+ 0x80862807, ///< Vendor ID/Device ID
+ 0x0000, ///< SubSystem ID
+ 0xFF, ///< Revision ID
+ 0x02, ///< Front panel support (1=yes, 2=no)
+ 0x0003, ///< Number of Rear Jacks
+ 0x0000 ///< Number of Front Jacks
+ },
+ 0 ///< Pointer to verb table data, need to be inited in the code.
+ }
+};
+
+/**
+ Polling the Status bit
+
+ @param[in] StatusReg The regsiter address to read the status
+ @param[in] PollingBitMap The bit mapping for polling
+ @param[in] PollingData The Data for polling
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_TIMEOUT Polling the bit map time out
+**/
+EFI_STATUS
+StatusPolling (
+ IN UINT32 StatusReg,
+ IN UINT16 PollingBitMap,
+ IN UINT16 PollingData
+ )
+{
+ UINT32 LoopTime;
+
+ for (LoopTime = 0; LoopTime < SA_HDA_MAX_LOOP_TIME; LoopTime++) {
+ if ((MmioRead16 (StatusReg) & PollingBitMap) == PollingData) {
+ break;
+ } else {
+ PchPmTimerStall (SA_HDA_WAIT_PERIOD);
+ }
+ }
+
+ if (LoopTime >= SA_HDA_MAX_LOOP_TIME) {
+ DEBUG ((EFI_D_ERROR, "Polling StatusReg 0x%X BitMap 0x%x TimeOut\n", StatusReg, PollingBitMap));
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Send the command to the codec via the Immediate Command mechanism is written
+ to the IC register
+
+ @param[in] HdaBar Base address of Intel HD Audio memory mapped configuration registers
+ @param[in, out] CodecCommandData The Codec Command to be sent to the codec
+ @param[in] ReadBack Whether to get the response received from the codec
+
+ @exception EFI_DEVICE_ERROR Device status error, operation failed
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+SendCodecCommand (
+ IN UINT32 HdaBar,
+ IN OUT UINT32 *CodecCommandData,
+ IN BOOLEAN ReadBack
+ )
+{
+ EFI_STATUS Status;
+
+ ///
+ /// Wait for Command Busy (ICB) bit to be cleared
+ ///
+ Status = StatusPolling (HdaBar + R_HDA_IRS, (UINT16) B_HDA_IRS_ICB, (UINT16) 0);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "ICB bit is not zero before SendCodecCommand! \n"));
+ return EFI_DEVICE_ERROR;
+ }
+ ///
+ /// Clear Result Valid (IRV) bit (by writing a one to it) before issuing a new command
+ ///
+ MmioOr16 ((UINTN) (HdaBar + R_HDA_IRS), (UINT16) (B_HDA_IRS_IRV));
+ ///
+ /// Send command to codec
+ ///
+ MmioWrite32 (HdaBar + R_HDA_IC, *CodecCommandData);
+ ///
+ /// Set ICB bit to issue the command currently stored in IC to the codec.
+ ///
+ MmioOr16 ((UINTN) (HdaBar + R_HDA_IRS), (UINT16) (B_HDA_IRS_ICB));
+ ///
+ /// Wait for Command Busy (ICB) bit to be cleared
+ ///
+ Status = StatusPolling (HdaBar + R_HDA_IRS, (UINT16) B_HDA_IRS_ICB, (UINT16) 0);
+ if (EFI_ERROR (Status)) {
+ MmioAnd16 ((UINTN) (HdaBar + R_HDA_IRS), (UINT16)~(B_HDA_IRS_ICB));
+ return Status;
+ }
+
+ ///
+ /// Save Codec command for runtime code
+ ///
+ if (mVerbCodecSaveAddress != NULL) {
+ if ((mVerbCount * 4) < AUDIO_CODEC_MAX_SIZE) {
+ *(mVerbCodecSaveAddress + mVerbCount) = *CodecCommandData;
+ mVerbCount++;
+ DEBUG ((EFI_D_ERROR, "SendCodecCommand(0x%x): 0x%x \n",(mVerbCodecSaveAddress + (mVerbCount)), *CodecCommandData));
+ } else {
+ DEBUG ((EFI_D_ERROR, "Codec Command Save Area Overflow max value of %d\n", AUDIO_CODEC_MAX_SIZE));
+ }
+ }
+
+ if (ReadBack == TRUE) {
+ if ((MmioRead16 (HdaBar + R_HDA_IRS) & B_HDA_IRS_IRV) != 0) {
+ *CodecCommandData = MmioRead32 (HdaBar + R_HDA_IR);
+ } else {
+ DEBUG ((EFI_D_ERROR, "SendCodecCommand: ReadBack fail! \n"));
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set a "Send Codec Command" S3 dispatch item
+
+ @param[in] HdaBar Base address of Intel HD Audio memory mapped configuration registers
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+SendCodecCommandS3Item (
+ IN UINT32 HdaBar
+ )
+{
+ UINT16 BitMask;
+ UINT16 BitValue;
+ UINT16 Data16And;
+ UINT16 Data16Or;
+
+ ///
+ /// Wait for Command Busy (ICB) bit to be cleared
+ ///
+ BitMask = (UINT16) B_HDA_IRS_ICB;
+ BitValue = (UINT16) 0;
+ SCRIPT_MEM_POLL (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ HdaBar + R_HDA_IRS,
+ &BitMask,
+ &BitValue,
+ SA_HDA_WAIT_PERIOD,
+ SA_HDA_MAX_LOOP_TIME
+ );
+ ///
+ /// Clear Result Valid (IRV) bit (by writing a one to it) before issuing a new command
+ ///
+ Data16And = 0xFFFF;
+ Data16Or = (UINT16) (B_HDA_IRS_IRV);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (HdaBar + R_HDA_IRS),
+ &Data16Or, /// Data to be ORed
+ &Data16And /// Data to be ANDed
+ );
+
+ ///
+ /// Send command to codec
+ ///
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (HdaBar + R_HDA_IC),
+ 1,
+ (VOID *) (UINTN) (HdaBar + R_HDA_IC)
+ );
+
+ ///
+ /// Set ICB bit to issue the command currently stored in IC to the codec.
+ ///
+ Data16And = 0xFFFF;
+ Data16Or = (UINT16) (B_HDA_IRS_ICB );
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (HdaBar + R_HDA_IRS),
+ &Data16Or, /// Data to be ORed
+ &Data16And /// Data to be ANDed
+ );
+
+ ///
+ /// Wait for Command Busy (ICB) bit to be cleared
+ ///
+ SCRIPT_MEM_POLL (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ HdaBar + R_HDA_IRS,
+ &BitMask,
+ &BitValue,
+ SA_HDA_WAIT_PERIOD,
+ SA_HDA_MAX_LOOP_TIME
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Detect And Initialize SA Audio Codec
+
+ @param[in] ImageHandle Handle for the image of this driver
+ @param[in] DxePlatformSaPolicy SA DxePlatformPolicy protocol
+
+ @retval EFI_SUCCESS - Legacy Region protocol installed
+ @retval Other - No protocol installed, unload driver.
+**/
+EFI_STATUS
+DetectAndInitializeCodec (
+ IN EFI_HANDLE mImageHandle,
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ UINT32 VendorDeviceId;
+ UINT32 RevisionId;
+ UINT8 ByteReg;
+ UINTN AudioBase;
+ UINT8 AudioSDINo;
+ UINT32 HdaBar;
+ UINT32 *VerbTable;
+ UINT32 LoopTime;
+ SA_HDA_VERB_TABLE_HEADER *VerbHeaderTable;
+ EFI_PHYSICAL_ADDRESS BaseAddressBarMem;
+ UINT8 VerbTableNum;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ UINT32 Data32;
+ UINT32 CodecCmdData;
+ UINT16 AudioDeviceId;
+ UINT16 Data16;
+ UINT16 BitMask;
+ UINT16 BitValue;
+ CPU_STEPPING CpuSteppingId;
+ CPU_FAMILY CpuFamilyId;
+ UINT16 IsUlx;
+
+ CpuFamilyId = GetCpuFamily();
+ CpuSteppingId = GetCpuStepping();
+
+ AudioBase = MmPciAddress (0, SA_HDA_BUS_NUM, SA_HDA_DEV_NUM, SA_HDA_FUN_NUM, 0);
+ AudioDeviceId = MmioRead16 (AudioBase + PCI_DEVICE_ID_OFFSET);
+
+ ///
+ /// Allocate resource for HDBAR
+ ///
+ BaseAddressBarMem = 0x0FFFFFFFF;
+ Status = gDS->AllocateMemorySpace (
+ EfiGcdAllocateMaxAddressSearchBottomUp,
+ EfiGcdMemoryTypeMemoryMappedIo,
+ 14,
+ SA_HDA_HDBAR_SIZE,
+ &BaseAddressBarMem,
+ mImageHandle,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ///
+ /// System BIOS should ensure that the High Definition Audio HDBAR D27:F0:Reg 10-17h contains a valid address value
+ /// and is enabled by setting D3:F0:Reg 04h[1].
+ ///
+ HdaBar = (UINT32) BaseAddressBarMem;
+ MmioWrite32 (AudioBase + SA_HDA_HDBARL, HdaBar);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (AudioBase + SA_HDA_HDBARL),
+ 1,
+ (VOID *) (UINTN) (AudioBase + SA_HDA_HDBARL)
+ );
+
+ MmioWrite32 (AudioBase + SA_HDA_HDBARU, 0);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (AudioBase + SA_HDA_HDBARU),
+ 1,
+ (VOID *) (UINTN) (AudioBase + SA_HDA_HDBARU)
+ );
+
+ MmioOr16 ((UINTN) (AudioBase + PCI_COMMAND_OFFSET), (UINT16) BIT1);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (AudioBase + PCI_COMMAND_OFFSET),
+ 1,
+ (VOID *) (UINTN) (AudioBase + PCI_COMMAND_OFFSET)
+ );
+
+ ///
+ /// AudioWA: Apply until C0, program Chicken bit: set Dev3 mmio 101C bit 29
+ ///
+ if (((CpuFamilyId == EnumCpuHsw) && (CpuSteppingId < EnumHswC0)) ||
+ ((CpuFamilyId == EnumCpuCrw) && (CpuSteppingId < EnumCrwC0))) {
+ Data32And = 0xFFFFFFFF;
+ Data32Or = (UINT32) (BIT29);
+ MmioOr32 ((UINTN) (HdaBar + 0x101C), Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (HdaBar + 0x101C),
+ &Data32Or, /// Data to be ORed
+ &Data32And /// Data to be ANDed
+ );
+ }
+ if (DxePlatformSaPolicy->Revision >=4) {
+ IsUlx = 0;
+ Data16 = McD2PciCfg16 (0x2);
+ if ((Data16 == 0xA0E) || (Data16 == 0xA1E)) {
+ IsUlx = 1;
+ }
+ Data32Or = 4;
+ Data32 = 75;
+ if (DxePlatformSaPolicy->IgdConfig->CdClkVar != 0) {
+ if (DxePlatformSaPolicy->IgdConfig->CdClk == 0) {
+ Data32Or = 16;
+ Data32 = 225;
+ }
+ if (DxePlatformSaPolicy->IgdConfig->CdClk == 2) {
+ Data32Or = 4;
+ Data32 = 90;
+ }
+ }
+ if(IsUlx == 1) {
+ Data32Or = 16;
+ Data32 = 225;
+ }
+ ///
+ /// Program Dev3 EM4 and EM5 MMIO registers [17:00] based on Cd Clk frequency
+ ///
+ Data32And = 0xFFFC0000;
+ Mmio32AndThenOr ((UINTN) HdaBar, 0x100c, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (HdaBar + 0x100c),
+ &Data32Or, /// Data to be ORed
+ &Data32And /// Data to be ANDed
+ );
+
+ Data32And = 0xFFFC0000;
+ Data32Or = Data32;
+ Mmio32AndThenOr ((UINTN) HdaBar, 0x1010, Data32And, Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (HdaBar + 0x1010),
+ &Data32Or, /// Data to be ORed
+ &Data32And /// Data to be ANDed
+ );
+ }
+
+ mSaGlobalNvsAreaProtocol.Area->AudioWaA = MmioRead32(HdaBar + 0x1010);
+ mSaGlobalNvsAreaProtocol.Area->AudioWaB = MmioRead32(HdaBar + 0x101C);
+ mSaGlobalNvsAreaProtocol.Area->AudioWaC = MmioRead32(HdaBar + 0x100C);
+
+ ///
+ /// Allocate an ACPI NVS memory buffer for Saving Codec value for Adapter Power on restore
+ /// , zero initialize, and set the pointer in the SA NVS area structure.
+ ///
+ Status = (gBS->AllocatePool) (EfiACPIMemoryNVS, AUDIO_CODEC_MAX_SIZE, (VOID **) &mVerbCodecSaveAddress);
+ if (EFI_ERROR(Status)) {
+ mSaGlobalNvsAreaProtocol.Area->AudioCodecSaveAddress = 0;
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ ZeroMem ((VOID *) mVerbCodecSaveAddress, AUDIO_CODEC_MAX_SIZE);
+ mSaGlobalNvsAreaProtocol.Area->AudioCodecSaveAddress = (UINT32) (UINTN) (mVerbCodecSaveAddress);
+ }
+
+ ///
+ /// Codec Initialization Programming Sequence
+ /// System BIOS should also ensure that the Controller Reset# bit of Global Control register
+ /// in memory-mapped space (HDBAR+08h[0]) is set to 1 and read back as 1.
+ /// Deassert the HDA controller RESET# to start up the link
+ ///
+ DEBUG ((EFI_D_INFO, "Codec Initialization...\n"));
+ Data32And = 0xFFFFFFFF;
+ Data32Or = (UINT32) (B_HDA_GCTL_CRST);
+ MmioOr32 ((UINTN) (HdaBar + R_HDA_GCTL), Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (HdaBar + R_HDA_GCTL),
+ &Data32Or, /// Data to be ORed
+ &Data32And /// Data to be ANDed
+ );
+
+ BitMask = (UINT16) B_HDA_GCTL_CRST;
+ BitValue = (UINT16) B_HDA_GCTL_CRST;
+ Status = StatusPolling (HdaBar + R_HDA_GCTL, BitMask, BitValue);
+ SCRIPT_MEM_POLL (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ HdaBar + R_HDA_GCTL,
+ &BitMask,
+ &BitValue,
+ SA_HDA_WAIT_PERIOD,
+ SA_HDA_MAX_LOOP_TIME
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Reset SA dHDA Codec - Set Controller Reset# bit and Poll: Time Out - 0! \n"));
+ goto ExitInitAudio;
+ }
+ ///
+ /// Read GCAP and write the same value back to the register once after Controller Reset# bit is set
+ ///
+ Data16 = MmioRead16 (HdaBar + R_HDA_GCAP);
+ MmioWrite16 (HdaBar + R_HDA_GCAP, Data16);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (HdaBar + R_HDA_GCAP),
+ 1,
+ (VOID *) (UINTN) (HdaBar + R_HDA_GCAP)
+ );
+ ///
+ /// Clear the "State Change Status Register" STATESTS bits for
+ /// each of the "SDIN Stat Change Status Flag"
+ ///
+ MmioOr8 ((UINTN) (HdaBar + R_HDA_STATESTS), (UINT8) (SA_HDA_MAX_SID_MASK));
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint8,
+ (UINTN) (HdaBar + R_HDA_STATESTS),
+ 1,
+ (VOID *) (UINTN) (HdaBar + R_HDA_STATESTS)
+ );
+ ///
+ /// Turn off the link and poll RESET# bit until it reads back as 0 to get hardware reset report
+ ///
+ Data32And = (UINT32) (~B_HDA_GCTL_CRST);
+ Data32Or = (UINT32) 0;
+ MmioAnd32 ((UINTN) (HdaBar + R_HDA_GCTL), Data32And);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (HdaBar + R_HDA_GCTL),
+ &Data32Or, /// Data to be ORed
+ &Data32And /// Data to be ANDed
+ );
+
+ BitMask = (UINT16) B_HDA_GCTL_CRST;
+ BitValue = 0;
+ Status = StatusPolling (HdaBar + R_HDA_GCTL, BitMask, BitValue);
+ SCRIPT_MEM_POLL (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ HdaBar + R_HDA_GCTL,
+ &BitMask,
+ &BitValue,
+ SA_HDA_WAIT_PERIOD,
+ SA_HDA_MAX_LOOP_TIME
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Reset SA dHDA Codec - Turn off the link and Poll: Time Out - 1! \n"));
+ goto ExitInitAudio;
+ }
+ ///
+ /// Turn on the link and poll RESET# bit until it reads back as 1
+ ///
+ Data32And = 0xFFFFFFFF;
+ Data32Or = (UINT32) (B_HDA_GCTL_CRST);
+ MmioOr32 ((UINTN) (HdaBar + R_HDA_GCTL), Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (HdaBar + R_HDA_GCTL),
+ &Data32Or, /// Data to be ORed
+ &Data32And /// Data to be ANDed
+ );
+ ///
+ /// For some combo card that will need this delay because each codec has different latency to come out from RESET.
+ /// This delay can make sure all codecs be recognized by BIOS after RESET sequence.
+ /// Additional delay might be required to allow codec coming out of reset prior to subsequent operations,
+ /// please contact your codec vendor for detail. When clearing this bit and setting it afterward,
+ /// BIOS must ensure that minimum link timing requirements (minimum RESET# assertion time, etc.) are met..
+ ///
+ PchPmTimerStall (SA_HDA_WAIT_PERIOD);
+ SCRIPT_STALL (EFI_ACPI_S3_RESUME_SCRIPT_TABLE, 300 * STALL_ONE_MICRO_SECOND);
+
+ BitMask = (UINT16) B_HDA_GCTL_CRST;
+ BitValue = (UINT16) B_HDA_GCTL_CRST;
+ Status = StatusPolling (HdaBar + R_HDA_GCTL, BitMask, BitValue);
+ SCRIPT_MEM_POLL (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ HdaBar + R_HDA_GCTL,
+ &BitMask,
+ &BitValue,
+ SA_HDA_WAIT_PERIOD,
+ SA_HDA_MAX_LOOP_TIME
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Reset SA dHDA Codec - Turn on the link and Poll: Time Out - 2! \n"));
+ goto ExitInitAudio;
+ }
+ ///
+ /// Read the "State Change Status Register" STATESTS bits twice to find out if any SDIN is connected
+ /// to a codec.
+ ///
+ for (LoopTime = 0, ByteReg = 0, AudioSDINo = 0; LoopTime < SA_HDA_MAX_LOOP_TIME; LoopTime++) {
+ ByteReg = MmioRead8 (HdaBar + R_HDA_STATESTS) & SA_HDA_MAX_SID_MASK;
+ if (ByteReg != 0 && (ByteReg == AudioSDINo)) {
+ break;
+ } else {
+ AudioSDINo = ByteReg;
+ }
+
+ PchPmTimerStall (SA_HDA_WAIT_PERIOD);
+ }
+ ///
+ /// BIT3(1000) -- SDI3
+ /// BIT2(0100) -- SDI2
+ /// BIT1(0010) -- SDI1
+ /// BIT0(0001) -- SDI0
+ ///
+ if (ByteReg == 0) {
+ ///
+ /// No Codec Detected, Turn off the link
+ ///
+ DEBUG ((EFI_D_INFO, "No Codec device is detected.\n"));
+ Data32And = (UINT32) (~B_HDA_GCTL_CRST);
+ Data32Or = (UINT32) 0;
+ MmioAnd32 ((UINTN) (HdaBar + R_HDA_GCTL), Data32And);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (HdaBar + R_HDA_GCTL),
+ &Data32Or, /// Data to be ORed
+ &Data32And /// Data to be ANDed
+ );
+ Status = EFI_DEVICE_ERROR;
+ goto ExitInitAudio;
+ }
+
+ for (AudioSDINo = 0; AudioSDINo < SA_HDA_MAX_SID_NUMBER; AudioSDINo++, ByteReg >>= 1) {
+ if ((ByteReg & 0x1) == 0) {
+ ///
+ /// SDIx has no Codec Device
+ ///
+ DEBUG ((EFI_D_INFO, "SDI%d has no Codec device.\n", AudioSDINo));
+ continue;
+ }
+ ///
+ /// Verb: 31~28 27 26~20 19~0
+ /// CAd 1 NID Verb Command and data
+ /// 0/1/2
+ ///
+ /// Read the Vendor ID/Device ID pair from the attached codec
+ ///
+ VendorDeviceId = 0x000F0000 | (AudioSDINo << 28);
+ Status = SendCodecCommand (HdaBar, &VendorDeviceId, TRUE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Read the Codec Vendor ID/Device ID fail! \n"));
+ goto ExitInitAudio;
+ }
+ ///
+ /// Read the Revision ID from the attached codec
+ ///
+ RevisionId = 0x000F0002 | (AudioSDINo << 28);
+ Status = SendCodecCommand (HdaBar, &RevisionId, TRUE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Read the Codec Revision ID fail! \n"));
+ goto ExitInitAudio;
+ }
+
+ RevisionId = (RevisionId >> 8) & 0xFF;
+
+ ///
+ /// Get the match codec verb table, RevID of 0xFF applies to all steppings.
+ ///
+ if (DxePlatformSaPolicy->MiscConfig->SaHdaVerbTableNum == 0) {
+ ///
+ /// Init Verb Table Data
+ ///
+ DxePlatformSaPolicy->MiscConfig->SaHdaVerbTable[0].VerbTableData = mSaHdaVerbTableDataDefault;
+ DxePlatformSaPolicy->MiscConfig->SaHdaVerbTableNum = sizeof (mSaHdaVerbTableDefault) / sizeof (SA_HDA_VERB_TABLE);
+ }
+ for (VerbTableNum = 0, VerbHeaderTable = NULL, VerbTable = NULL;
+ VerbTableNum < DxePlatformSaPolicy->MiscConfig->SaHdaVerbTableNum;
+ VerbTableNum++
+ ) {
+ if ((VendorDeviceId == DxePlatformSaPolicy->MiscConfig->SaHdaVerbTable[VerbTableNum].VerbTableHeader.VendorDeviceId) &&
+ (
+ (DxePlatformSaPolicy->MiscConfig->SaHdaVerbTable[VerbTableNum].VerbTableHeader.RevisionId == 0xFF) ||
+ (RevisionId == DxePlatformSaPolicy->MiscConfig->SaHdaVerbTable[VerbTableNum].VerbTableHeader.RevisionId)
+ )
+ ) {
+ VerbHeaderTable = &(DxePlatformSaPolicy->MiscConfig->SaHdaVerbTable[VerbTableNum].VerbTableHeader);
+ VerbTable = DxePlatformSaPolicy->MiscConfig->SaHdaVerbTable[VerbTableNum].VerbTableData;
+ if (VerbTable == 0) {
+ DEBUG ((EFI_D_ERROR, "VerbTableData of VendorID:0x%X is null.\n", VendorDeviceId));
+ Status = EFI_INVALID_PARAMETER;
+ goto ExitInitAudio;
+ }
+
+ DEBUG ((EFI_D_INFO, "Detected SA HDA Codec with verb table, VendorID = 0x%X", VendorDeviceId));
+ DEBUG ((EFI_D_INFO, " on SDI%d, revision = 0x%0x.\n", AudioSDINo, RevisionId));
+ ///
+ /// Enable 3rd Pin and Converter Widget
+ /// Clear CAd Field
+ ///
+ CodecCmdData = SA_HDA_ENABLE_3RD_PIN_WIDGET;
+ ///
+ /// Program CAd Field per the SDI number got during codec detection
+ ///
+ CodecCmdData |= (UINT32) (AudioSDINo << 28);
+ Status = SendCodecCommand (HdaBar, &CodecCmdData, FALSE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Error occurs at loading Verb 0x00878101"));
+ ///
+ /// Skip the verb table loading when find the verb table content is not
+ /// properly matched with the HDA hardware, though IDs match.
+ ///
+ DEBUG (
+ (EFI_D_ERROR,
+ "Detected Codec of VendorID:0x%X, error occurs during loading verb table.\n",
+ VendorDeviceId)
+ );
+ goto ExitInitAudio;
+ }
+
+ SendCodecCommandS3Item (HdaBar);
+ ///
+ /// Send the entire list of verbs in the matching verb table one by one to the codec
+ ///
+ for (Index = 0; Index < (UINT32) ((VerbHeaderTable->NumberOfFrontJacks + VerbHeaderTable->NumberOfRearJacks) * 4); Index++) {
+ ///
+ /// Clear CAd Field
+ ///
+ CodecCmdData = VerbTable[Index] & (UINT32)~(BIT31 | BIT30 | BIT29 | BIT28);
+ ///
+ /// Program CAd Field per the SDI number got during codec detection
+ ///
+ CodecCmdData |= (UINT32) (AudioSDINo << 28);
+ Status = SendCodecCommand (HdaBar, &CodecCmdData, FALSE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Error occurs at loading Command Index:%x\n", Index));
+ ///
+ /// Skip the verb table loading when find the verb table content is not
+ /// properly matched with the HDA hardware, though IDs match.
+ ///
+ DEBUG (
+ (EFI_D_ERROR,
+ "Detected Codec of VendorID:0x%X, error occurs during loading verb table.\n",
+ VendorDeviceId)
+ );
+ goto ExitInitAudio;
+ }
+
+ SendCodecCommandS3Item (HdaBar);
+ }
+ ///
+ /// Disable 3rd Pin and Converter Widget
+ /// Clear CAd Field
+ ///
+ CodecCmdData = SA_HDA_DISABLE_3RD_PIN_WIDGET;
+ ///
+ /// Program CAd Field per the SDI number got during codec detection
+ ///
+ CodecCmdData |= (UINT32) (AudioSDINo << 28);
+ Status = SendCodecCommand (HdaBar, &CodecCmdData, FALSE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Error occurs at loading verb 0x00878100"));
+ ///
+ /// Skip the verb table loading when find the verb table content is not
+ /// properly matched with the HDA hardware, though IDs match.
+ ///
+ DEBUG (
+ (EFI_D_ERROR,
+ "Detected Codec of VendorID:0x%X, error occurs during loading verb table.\n",
+ VendorDeviceId)
+ );
+ goto ExitInitAudio;
+ }
+
+ SendCodecCommandS3Item (HdaBar);
+
+ DEBUG ((EFI_D_INFO, "Verb Table loading complete to Codec on SDI%d\n", AudioSDINo));
+ break;
+ }
+ }
+
+ if (VerbTableNum >= DxePlatformSaPolicy->MiscConfig->SaHdaVerbTableNum) {
+ DEBUG (
+ (EFI_D_INFO,
+ "Detected SA High Definition Audio Codec, VendorID = 0x%08x on SDI%d,",
+ VendorDeviceId,
+ AudioSDINo)
+ );
+ DEBUG ((EFI_D_INFO, " but no matching verb table found.\n"));
+ }
+ } // end of for
+ Status = EFI_SUCCESS;
+
+ExitInitAudio:
+ ///
+ /// Clear HdaBar and disable memory map access
+ ///
+ MmioAnd16 ((UINTN) (AudioBase + PCI_COMMAND_OFFSET), (UINT16) (~BIT1));
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (AudioBase + PCI_COMMAND_OFFSET),
+ 1,
+ (VOID *) (UINTN) (AudioBase + PCI_COMMAND_OFFSET)
+ );
+
+ MmioWrite32 (AudioBase + SA_HDA_HDBARL, 0);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (AudioBase + SA_HDA_HDBARL),
+ 1,
+ (VOID *) (UINTN) (AudioBase + SA_HDA_HDBARL)
+ );
+
+ MmioWrite32 (AudioBase + SA_HDA_HDBARU, 0);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (AudioBase + SA_HDA_HDBARU),
+ 1,
+ (VOID *) (UINTN) (AudioBase + SA_HDA_HDBARU)
+ );
+
+ gDS->FreeMemorySpace (
+ BaseAddressBarMem,
+ SA_HDA_HDBAR_SIZE
+ );
+ ///
+ /// Save the final count of Audio Codec Save data in SA NVS
+ ///
+ mSaGlobalNvsAreaProtocol.Area->AudioCodecSaveCount = mVerbCount;
+
+ return Status;
+}
+
+/**
+ Initialize SystemAgent Audio Device/Codec.
+
+ @param[in] ImageHandle Handle for the image of this driver
+ @param[in] DxePlatformSaPolicy SA DxePlatformPolicy protocol
+
+ @retval EFI_SUCCESS - Audio/Codec initialization done
+**/
+EFI_STATUS
+AudioInit (
+ IN EFI_HANDLE ImageHandle,
+ IN DXE_PLATFORM_SA_POLICY_PROTOCOL *DxePlatformSaPolicy
+ )
+{
+ EFI_STATUS Status;
+
+ if ((DxePlatformSaPolicy->MiscConfig->AudioEnable == 0) || (McD2PciCfg16 (R_SA_IGD_VID) == 0xFFFF)) {
+ DEBUG ((
+ EFI_D_INFO, "Skip Audio Initialization when BIOS option set to disable Or iGfx is not enabled.\n"
+ )
+ );
+ return EFI_SUCCESS;
+ }
+
+ Status = DetectAndInitializeCodec (ImageHandle, DxePlatformSaPolicy);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "SA Audio Codec initialization failure!\n"));
+ }
+
+ DEBUG ((EFI_D_INFO, "AudioInit() End\n"));
+ return EFI_SUCCESS;
+}