diff options
Diffstat (limited to 'ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/AudioInit.c')
-rw-r--r-- | ReferenceCode/Chipset/SystemAgent/SaInit/Dxe/AudioInit.c | 849 |
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; +} |