summaryrefslogtreecommitdiff
path: root/ReferenceCode/Chipset/LynxPoint/PchInit/Dxe/PchAzalia.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Chipset/LynxPoint/PchInit/Dxe/PchAzalia.c')
-rw-r--r--ReferenceCode/Chipset/LynxPoint/PchInit/Dxe/PchAzalia.c915
1 files changed, 915 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/LynxPoint/PchInit/Dxe/PchAzalia.c b/ReferenceCode/Chipset/LynxPoint/PchInit/Dxe/PchAzalia.c
new file mode 100644
index 0000000..a0c7535
--- /dev/null
+++ b/ReferenceCode/Chipset/LynxPoint/PchInit/Dxe/PchAzalia.c
@@ -0,0 +1,915 @@
+/** @file
+ Initializes the PCH Azalia codec.
+
+@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 "PchInit.h"
+
+/**
+ 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 < AZALIA_MAX_LOOP_TIME; LoopTime++) {
+ if ((MmioRead16 (StatusReg) & PollingBitMap) == PollingData) {
+ break;
+ } else {
+ PchPmTimerStall (AZALIA_WAIT_PERIOD);
+ }
+ }
+
+ if (LoopTime >= AZALIA_MAX_LOOP_TIME) {
+ 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
+
+ @retval 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;
+
+ 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;
+ }
+
+ MmioWrite32 (HdaBar + R_HDA_IC, *CodecCommandData);
+ MmioOr16 ((UINTN) (HdaBar + R_HDA_IRS), (UINT16) ((B_HDA_IRS_IRV | B_HDA_IRS_ICB)));
+
+ 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;
+ }
+
+ 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
+ @param[in, out] CodecCommandData The Codec Command to be sent to the codec
+
+ @retval EFI_SUCCESS The function completed successfully
+**/
+EFI_STATUS
+SendCodecCommandS3Item (
+ IN UINT32 HdaBar,
+ IN OUT UINT32 CodecCommandData
+ )
+{
+ EFI_STATUS Status;
+#ifdef EFI_S3_RESUME
+ STATIC EFI_PCH_S3_SUPPORT_PROTOCOL *PchS3Support;
+ STATIC EFI_PCH_S3_PARAMETER_SEND_CODEC_COMMAND S3ParameterSendCodecCommand;
+ STATIC EFI_PCH_S3_DISPATCH_ITEM S3DispatchItem = {
+ PchS3ItemTypeSendCodecCommand,
+ &S3ParameterSendCodecCommand
+ };
+ EFI_PHYSICAL_ADDRESS S3DispatchEntryPoint;
+
+ if (!PchS3Support) {
+ ///
+ /// Get the PCH S3 Support Protocol
+ ///
+ Status = gBS->LocateProtocol (
+ &gEfiPchS3SupportProtocolGuid,
+ NULL,
+ (VOID **) &PchS3Support
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ S3ParameterSendCodecCommand.HdaBar = HdaBar;
+ S3ParameterSendCodecCommand.CodecCmdData = CodecCommandData;
+ Status = PchS3Support->SetDispatchItem (
+ PchS3Support,
+ &S3DispatchItem,
+ &S3DispatchEntryPoint
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Save the script dispatch item in the Boot Script
+ ///
+ SCRIPT_DISPATCH (EFI_ACPI_S3_RESUME_SCRIPT_TABLE, S3DispatchEntryPoint);
+#else
+ Status = EFI_SUCCESS;
+#endif
+ return Status;
+}
+
+/**
+ Initialize the Intel High Definition Audio Codec(s) present in the system.
+ For each codec, a predefined codec verb table should be programmed.
+ The list contains 32-bit verbs to be sent to the corresponding codec.
+ If it is not programmed, the codec uses the default verb table, which may or may not
+ correspond to the platform jack information.
+
+ @param[in] PchPlatformPolicy The PCH Platform Policy protocol instance
+ @param[in] RootComplexBar RootComplexBar address of this PCH device
+ @param[in, out] AzaliaStarted Whether Azalia is successfully started
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_INVALID_PARAMETER Provided VerbTableData is null
+**/
+EFI_STATUS
+DetectAndInitializeAzalia (
+ IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy,
+ IN UINT32 RootComplexBar,
+ IN OUT BOOLEAN *AzaliaStarted
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ UINT32 VendorDeviceId;
+ UINT32 RevisionId;
+ UINT8 ByteReg;
+ UINTN AzaliaBase;
+ UINT8 AzaliaSDINo;
+ UINT32 HdaBar;
+ UINT32 *VerbTable;
+ UINT32 LoopTime;
+ PCH_AZALIA_VERB_TABLE_HEADER *VerbHeaderTable;
+ EFI_PHYSICAL_ADDRESS BaseAddressBarMem;
+ UINT8 VerbTableNum;
+ PCH_AZALIA_CONFIG *AzaliaConfig;
+ UINT32 Data32And;
+ UINT32 Data32Or;
+ UINT16 Data16And;
+ UINT16 Data16Or;
+ UINT8 Data8And;
+ UINT8 Data8Or;
+ UINT32 CodecCmdData;
+ UINTN PciD31F0RegBase;
+ UINT16 LpcDeviceId;
+ UINT16 Data16;
+ UINT16 BitMask;
+ UINT16 BitValue;
+ PCH_SERIES PchSeries;
+
+ PchSeries = GetPchSeries();
+ AzaliaConfig = PchPlatformPolicy->AzaliaConfig;
+ AzaliaBase = MmPciAddress (
+ 0,
+ PchPlatformPolicy->BusNumber,
+ PCI_DEVICE_NUMBER_PCH_AZALIA,
+ PCI_FUNCTION_NUMBER_PCH_AZALIA,
+ 0
+ );
+ PciD31F0RegBase = MmPciAddress (
+ 0,
+ PchPlatformPolicy->BusNumber,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ 0
+ );
+ LpcDeviceId = MmioRead16 (PciD31F0RegBase + R_PCH_LPC_DEVICE_ID);
+
+ Data32And = 0xF8FFFF01;
+ if ((MmioRead32 ((UINTN) (RootComplexBar + R_PCH_RCRB_CIR2030)) & (UINT32) BIT31) != 0) {
+ ///
+ /// PCH BIOS Spec Rev 0.5.0 Section 9.4.2 High Definition Audio VCi Configuration
+ /// For Sever
+ /// Step 1
+ /// Configure and enable Vcp on DMI, done on PchDmiPeim.c
+ /// Step 2
+ /// Assign a Vcp ID value of 2 to High Definition Audio VCi ID field of VCi Resource Control register
+ /// D27:F0:Reg 120h[26:24] = 2
+ /// Step 3
+ /// Map Tcp to VCP. Set bit 2 of TC/VCi Map field of High Definition Audio VCi Resource Control register
+ /// D27:F0:Reg 120h[7:1]
+ ///
+ Data32Or = BIT25;
+ Data32Or |= MmioRead32 ((UINTN) (RootComplexBar + R_PCH_RCRB_CIR2030)) & V_PCH_RCRB_V1CTL_TVM_MASK;
+ MmioAndThenOr32 (
+ (UINTN) (AzaliaBase + R_PCH_HDA_VCICTL),
+ Data32And, // Data to be ANDed
+ Data32Or // Data to be ORed
+ );
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (AzaliaBase + R_PCH_HDA_VCICTL),
+ &Data32Or, // Data to be ORed
+ &Data32And // Data to be ANDed
+ );
+ ///
+ /// Step 4
+ /// Avoid isochronous transfers to use VC1, Clear No Snoop Enable of Device Control Register
+ /// D27:F0:Reg 78h[11] = 0b
+ ///
+ if (PchSeries == PchH) {
+ MmioAnd16 (
+ (UINTN) (AzaliaBase + R_PCH_HDA_DEVC),
+ (UINT16) (~B_PCH_HDA_DEVC_NSNPEN)
+ );
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (AzaliaBase + R_PCH_HDA_DEVC),
+ 1,
+ (VOID *) (UINTN) (AzaliaBase + R_PCH_HDA_DEVC)
+ );
+ }
+ }
+ if ((MmioRead32 ((UINTN) (AzaliaBase + R_PCH_HDA_VCICTL)) & B_PCH_HDA_VCICTL_ID) != 0) {
+ ///
+ /// Step 5
+ /// Clear the TC/VC0 Map field of VC0 Resource Control register
+ /// D27:F0:Reg 114h[7:1] = 0
+ ///
+ MmioAnd32 (
+ (UINTN) (AzaliaBase + R_PCH_HDA_VC0CTL),
+ (UINT32) (~B_PCH_HDA_VC0CTL_TCVC0_MAP)
+ );
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (AzaliaBase + R_PCH_HDA_VC0CTL),
+ 1,
+ (VOID *) (UINTN) (AzaliaBase + R_PCH_HDA_VC0CTL)
+ );
+ ///
+ /// Step 6
+ /// For LPT-H, Set VCi Enable bit of VCi Resource Control register
+ /// D27:F0:Reg 120h[31] = 1
+ /// For LPT-LP, Clear VCi Enable bit of VCi Resource Control register
+ /// D27:F0:Reg 120h[31] = 0
+ ///
+ if (PchSeries == PchH) {
+ MmioOr32 ((UINTN) (AzaliaBase + R_PCH_HDA_VCICTL), (UINT32) (B_PCH_HDA_VCICTL_EN));
+ }
+ if (PchSeries == PchLp) {
+ MmioAnd32 ((UINTN) (AzaliaBase + R_PCH_HDA_VCICTL), (UINT32)~(B_PCH_HDA_VCICTL_EN));
+ }
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (AzaliaBase + R_PCH_HDA_VCICTL),
+ 1,
+ (VOID *) (UINTN) (AzaliaBase + R_PCH_HDA_VCICTL)
+ );
+ }
+ ///
+ /// Firstly Initialize Azalia to be not started.
+ ///
+ *AzaliaStarted = FALSE;
+
+ ///
+ /// Allocate resource for HDBAR
+ ///
+ BaseAddressBarMem = 0x0FFFFFFFF;
+ Status = gDS->AllocateMemorySpace (
+ EfiGcdAllocateMaxAddressSearchBottomUp,
+ EfiGcdMemoryTypeMemoryMappedIo,
+ 14,
+ V_PCH_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 D27:F0:Reg 04h[1].
+ ///
+ HdaBar = (UINT32) BaseAddressBarMem;
+ MmioWrite32 (AzaliaBase + R_PCH_HDA_HDBARL, HdaBar);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (AzaliaBase + R_PCH_HDA_HDBARL),
+ 1,
+ (VOID *) (UINTN) (AzaliaBase + R_PCH_HDA_HDBARL)
+ );
+
+ MmioWrite32 (AzaliaBase + R_PCH_HDA_HDBARU, 0);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (AzaliaBase + R_PCH_HDA_HDBARU),
+ 1,
+ (VOID *) (UINTN) (AzaliaBase + R_PCH_HDA_HDBARU)
+ );
+
+ MmioOr16 ((UINTN) (AzaliaBase + R_PCH_HDA_COMMAND), (UINT16) B_PCH_HDA_COMMAND_MSE);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (AzaliaBase + R_PCH_HDA_COMMAND),
+ 1,
+ (VOID *) (UINTN) (AzaliaBase + R_PCH_HDA_COMMAND)
+ );
+
+ ///
+ /// PCH BIOS Spec Rev 0.5.0 Section 9.5
+ /// Additional High Definition Audio Programming Steps
+ ///
+ if(PchSeries == PchH) {
+ ///
+ /// Step 1
+ /// Set D27:F0:43h[4] = 1b
+ ///
+ Data8And = (UINT8) ~0;
+ Data8Or = BIT4;
+ MmioOr8 ((UINTN) (AzaliaBase + 0x43), Data8Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint8,
+ (UINTN) (AzaliaBase + 0x43),
+ &Data8Or, // Data to be ORed
+ &Data8And // Data to be ANDed
+ );
+ ///
+ /// Step 2
+ /// Set D27:F0:C0h[17] = 1b
+ ///
+ Data32And = (UINT32) ~0;
+ Data32Or = BIT17;
+ MmioOr32 ((UINTN) (AzaliaBase + 0xC0), Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (AzaliaBase + 0xC0),
+ &Data32Or, // Data to be ORed
+ &Data32And // Data to be ANDed
+ );
+ }
+ ///
+ /// For LPT-LP, clear D27:F0:43h[6] = 0b
+ ///
+ if(PchSeries == PchLp) {
+ ///
+ /// Step 1
+ /// Set D27:F0:43h[6] = 0b
+ ///
+ MmioAnd8 ((UINTN) (AzaliaBase + 0x43), (UINT8) (~BIT6));
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint8,
+ (UINTN) (AzaliaBase + 0x43),
+ 1,
+ (VOID *) (UINTN) (AzaliaBase + 0x43)
+ );
+ }
+
+ ///
+ /// Step 3
+ /// For LPT-H, Set D27:F0:C4h[14] = 1b
+ /// For LPT-LP, Set D27:F0:C4h[24] = 1b
+ ///
+ Data32And = (UINT32) ~0;
+ Data32Or = 0;
+ if (PchSeries == PchH) {
+ Data32Or |= BIT14;
+ }
+ if (PchSeries == PchLp) {
+ Data32Or |= BIT24;
+ }
+ MmioOr32 ((UINTN) (AzaliaBase + 0xC4), Data32Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (AzaliaBase + 0xC4),
+ &Data32Or, // Data to be ORed
+ &Data32And // Data to be ANDed
+ );
+
+ if (PchSeries == PchH) {
+ ///
+ /// Step 4
+ /// Set D27:F0:D0h[31] = 0b
+ ///
+ Data32And = ~BIT31;
+ Data32Or = (UINT32) 0;
+ MmioAnd32 ((UINTN) (AzaliaBase + 0xD0), Data32And);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (AzaliaBase + 0xD0),
+ &Data32Or, // Data to be ORed
+ &Data32And // Data to be ANDed
+ );
+ }
+
+ if (AzaliaConfig->DS == PCH_DEVICE_DISABLE) {
+ MmioAnd8 ((UINTN) (AzaliaBase + R_PCH_HDA_DCKSTS), (UINT8) (~B_PCH_HDA_DCKSTS_DS));
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint8,
+ (UINTN) (AzaliaBase + R_PCH_HDA_DCKSTS),
+ 1,
+ (VOID *) (UINTN) (AzaliaBase + R_PCH_HDA_DCKSTS)
+ );
+ } else if (AzaliaConfig->DA != PCH_DEVICE_DISABLE) {
+ if ((MmioRead8 (AzaliaBase + R_PCH_HDA_DCKSTS) & B_PCH_HDA_DCKSTS_DM) == 0) {
+ MmioOr8 ((UINTN) (AzaliaBase + R_PCH_HDA_DCKCTL), (UINT8) (B_PCH_HDA_DCKCTL_DA));
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint8,
+ (UINTN) (AzaliaBase + R_PCH_HDA_DCKCTL),
+ 1,
+ (VOID *) (UINTN) (AzaliaBase + R_PCH_HDA_DCKCTL)
+ );
+ }
+ }
+
+ if (PchSeries == PchLp) {
+ ///
+ /// @todo: Policy check to bypass for PO
+ /// Set Hdabar + 0x0012h[0] to 1b
+ ///
+ Data16And = (UINT16)~BIT0;
+ Data16Or = (UINT16) (BIT0);
+ MmioOr16 ((UINTN) (HdaBar + 0x0012), Data16Or);
+ SCRIPT_MEM_READ_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (HdaBar + 0x0012),
+ &Data16Or, // Data to be ORed
+ &Data16And // Data to be ANDed
+ );
+
+ ///
+ /// W/A: Azalia BCLK is not at full swing when operating in high voltage mode
+ /// Set D27:F0:42h[2] = 1b - disabling Auto Voltage Detector.
+ ///
+ MmioOr8 ((UINTN)(AzaliaBase + R_PCH_HDA_AZIOBC), (UINT8)B_PCH_HDA_AZIOBC_AVDDIS);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint8,
+ (UINTN) (AzaliaBase + R_PCH_HDA_AZIOBC),
+ 1,
+ (VOID *) (UINTN) (AzaliaBase + R_PCH_HDA_AZIOBC)
+ );
+ }
+ ///
+ /// PCH BIOS Spec Rev 0.5.0 Section 9.1.3 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
+ ///
+ 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,
+ AZALIA_WAIT_PERIOD,
+ AZALIA_MAX_LOOP_TIME
+ );
+ ///
+ /// PCH BIOS Spec Rev 0.5.0 Section 9.1.3 Codec Initialization Programming Sequence
+ /// 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"
+ ///
+ Data16 = AZALIA_MAX_SID_MASK_PCH_H;
+ if (PchSeries == PchLp) {
+ Data16 = AZALIA_MAX_SID_MASK_PCH_LP;
+ }
+ MmioOr8 ((UINTN) (HdaBar + R_HDA_STATESTS), (UINT8) (Data16));
+ 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,
+ AZALIA_WAIT_PERIOD,
+ AZALIA_MAX_LOOP_TIME
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Reset High Definition Audio (Azalia) Codec Time Out - 1! \n"));
+ goto ExitInitAzalia;
+ }
+ ///
+ /// 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 (AzaliaConfig->ResetWaitTimer);
+ SCRIPT_STALL (EFI_ACPI_S3_RESUME_SCRIPT_TABLE, AzaliaConfig->ResetWaitTimer);
+
+ 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,
+ AZALIA_WAIT_PERIOD,
+ AZALIA_MAX_LOOP_TIME
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Reset High Definition Audio (Azalia) Codec Time Out - 2! \n"));
+ goto ExitInitAzalia;
+ }
+ ///
+ /// Read the "State Change Status Register" STATESTS bits twice to find out if any SDIN is connected
+ /// to a codec.
+ ///
+ Data16 = AZALIA_MAX_SID_MASK_PCH_H;
+ if (PchSeries == PchLp) {
+ Data16 = AZALIA_MAX_SID_MASK_PCH_LP;
+ }
+ for (LoopTime = 0, ByteReg = 0, AzaliaSDINo = 0; LoopTime < AZALIA_MAX_LOOP_TIME; LoopTime++) {
+ ByteReg = (UINT8)(MmioRead8 (HdaBar + R_HDA_STATESTS) & Data16);
+ if (ByteReg != 0 && (ByteReg == AzaliaSDINo)) {
+ break;
+ } else {
+ AzaliaSDINo = ByteReg;
+ }
+
+ PchPmTimerStall (AZALIA_WAIT_PERIOD);
+ }
+ ///
+ /// BIT3(1000) -- SDI3
+ /// BIT2(0100) -- SDI2
+ /// BIT1(0010) -- SDI1
+ /// BIT0(0001) -- SDI0
+ ///
+ if (ByteReg == 0) {
+ ///
+ /// No Azalia Detected
+ ///
+ ///
+ /// Turn off the link
+ ///
+ DEBUG ((EFI_D_ERROR, "No Azalia 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 ExitInitAzalia;
+ }
+ ///
+ /// PME Enable for Audio controller, this bit is in the resume well
+ ///
+ if (AzaliaConfig->Pme == PCH_DEVICE_ENABLE) {
+ MmioOr32 ((UINTN) (AzaliaBase + R_PCH_HDA_PCS), (UINT32) (B_PCH_HDA_PCS_PMEE));
+#ifdef SUS_WELL_RESTORE
+ ///
+ /// To support RapidStart resume from G3 state, all resume well registers need to be saved
+ /// into S3 Script table.
+ ///
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (AzaliaBase + R_PCH_HDA_PCS),
+ 1,
+ (VOID *) (UINTN) (AzaliaBase + R_PCH_HDA_PCS)
+ );
+#endif
+ }
+
+ Data16 = AZALIA_MAX_SID_NUMBER_PCH_H;
+ if (PchSeries == PchLp) {
+ Data16 = AZALIA_MAX_SID_NUMBER_PCH_LP;
+ }
+ for (AzaliaSDINo = 0; AzaliaSDINo < Data16; AzaliaSDINo++, ByteReg >>= 1) {
+ if ((ByteReg & 0x1) == 0) {
+ ///
+ /// SDIx has no Azalia Device
+ ///
+ DEBUG ((EFI_D_ERROR, "SDI%d has no Azalia device.\n", AzaliaSDINo));
+ continue;
+ }
+ ///
+ /// PME Enable for each existing codec, these bits are in the resume well
+ ///
+ if (AzaliaConfig->Pme != PCH_DEVICE_DISABLE) {
+ MmioOr16 (
+ (UINTN) (HdaBar + R_HDA_WAKEEN),
+ (UINT16) ((B_HDA_WAKEEN_SDI_0 << AzaliaSDINo))
+ );
+#ifdef SUS_WELL_RESTORE
+ ///
+ /// To support RapidStart resume from G3 state, all resume well registers need to be saved
+ /// into S3 Script table.
+ ///
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (HdaBar + R_HDA_WAKEEN),
+ 1,
+ (VOID *) (UINTN) (HdaBar + R_HDA_WAKEEN)
+ );
+#endif
+ }
+ ///
+ /// 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 | (AzaliaSDINo << 28);
+ Status = SendCodecCommand (HdaBar, &VendorDeviceId, TRUE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Read the Codec Vendor ID/Device ID fail! \n"));
+ goto ExitInitAzalia;
+ }
+ ///
+ /// Read the Revision ID from the attached codec
+ ///
+ RevisionId = 0x000F0002 | (AzaliaSDINo << 28);
+ Status = SendCodecCommand (HdaBar, &RevisionId, TRUE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Read the Codec Revision ID fail! \n"));
+ goto ExitInitAzalia;
+ }
+
+ RevisionId = (RevisionId >> 8) & 0xFF;
+
+ ///
+ /// Get the match codec verb table, RevID of 0xFF applies to all steppings.
+ ///
+ for (VerbTableNum = 0, VerbHeaderTable = NULL, VerbTable = NULL;
+ VerbTableNum < AzaliaConfig->AzaliaVerbTableNum;
+ VerbTableNum++) {
+ if ((VendorDeviceId == AzaliaConfig->AzaliaVerbTable[VerbTableNum].VerbTableHeader.VendorDeviceId) &&
+ ((AzaliaConfig->AzaliaVerbTable[VerbTableNum].VerbTableHeader.RevisionId == 0xFF) ||
+ ( RevisionId == AzaliaConfig->AzaliaVerbTable[VerbTableNum].VerbTableHeader.RevisionId))) {
+ VerbHeaderTable = &(AzaliaConfig->AzaliaVerbTable[VerbTableNum].VerbTableHeader);
+ VerbTable = AzaliaConfig->AzaliaVerbTable[VerbTableNum].VerbTableData;
+ if (VerbTable == 0) {
+ DEBUG ((EFI_D_ERROR | EFI_D_INFO, "VerbTableData of VendorID:0x%X is null.\n", VendorDeviceId));
+ Status = EFI_INVALID_PARAMETER;
+ goto ExitInitAzalia;
+ }
+ DEBUG ((EFI_D_INFO, "Detected Azalia Codec with verb table, VendorID = 0x%X", VendorDeviceId));
+ DEBUG ((EFI_D_INFO, " on SDI%d, revision = 0x%0x.\n", AzaliaSDINo, RevisionId));
+ ///
+ /// 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) (AzaliaSDINo << 28);
+ Status = SendCodecCommand (HdaBar, &CodecCmdData, FALSE);
+ if (EFI_ERROR (Status)) {
+ ///
+ /// Skip the Azalia verb table loading when find the verb table content is not
+ /// properly matched with the HDA hardware, though IDs match.
+ ///
+ DEBUG (
+ (EFI_D_ERROR | EFI_D_INFO,
+ "Detected Azalia Codec of VendorID:0x%X, error occurs during loading verb table.\n",
+ VendorDeviceId)
+ );
+ goto ExitInitAzalia;
+ }
+ SendCodecCommandS3Item (HdaBar, CodecCmdData);
+ }
+ break;
+ }
+ }
+
+ if (VerbTableNum >= AzaliaConfig->AzaliaVerbTableNum) {
+ DEBUG (
+ (EFI_D_ERROR,
+ "Detected High Definition Audio (Azalia) Codec, VendorID = 0x%08x on SDI%d,",
+ VendorDeviceId,
+ AzaliaSDINo)
+ );
+ DEBUG ((EFI_D_ERROR, " but no matching verb table found.\n"));
+ }
+ }
+ ///
+ /// end of for
+ ///
+ *AzaliaStarted = TRUE;
+ Status = EFI_SUCCESS;
+
+ExitInitAzalia:
+ ///
+ /// Clear AZBAR and disable memory map access
+ ///
+ MmioAnd16 ((UINTN) (AzaliaBase + R_PCH_HDA_COMMAND), (UINT16) (~B_PCH_HDA_COMMAND_MSE));
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint16,
+ (UINTN) (AzaliaBase + R_PCH_HDA_COMMAND),
+ 1,
+ (VOID *) (UINTN) (AzaliaBase + R_PCH_HDA_COMMAND)
+ );
+
+ MmioWrite32 (AzaliaBase + R_PCH_HDA_HDBARL, 0);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (AzaliaBase + R_PCH_HDA_HDBARL),
+ 1,
+ (VOID *) (UINTN) (AzaliaBase + R_PCH_HDA_HDBARL)
+ );
+
+ MmioWrite32 (AzaliaBase + R_PCH_HDA_HDBARU, 0);
+ SCRIPT_MEM_WRITE (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ EfiBootScriptWidthUint32,
+ (UINTN) (AzaliaBase + R_PCH_HDA_HDBARU),
+ 1,
+ (VOID *) (UINTN) (AzaliaBase + R_PCH_HDA_HDBARU)
+ );
+
+ gDS->FreeMemorySpace (
+ BaseAddressBarMem,
+ V_PCH_HDA_HDBAR_SIZE
+ );
+
+ return Status;
+}
+
+/**
+ Detect and initialize the type of codec (AC'97 and HDA) present in the system.
+
+ @param[in] PchPlatformPolicy The PCH Platform Policy protocol instance
+ @param[in] RootComplexBar RootComplexBar value of this PCH device
+ @param[in, out] AzaliaEnable Returned with TRUE if Azalia High Definition Audio codec
+ is detected and initialized.
+
+ @retval EFI_SUCCESS Codec is detected and initialized.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to initialize the codec.
+**/
+EFI_STATUS
+ConfigureAzalia (
+ IN DXE_PCH_PLATFORM_POLICY_PROTOCOL *PchPlatformPolicy,
+ IN UINT32 RootComplexBar,
+ IN OUT BOOLEAN *AzaliaEnable
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG ((EFI_D_INFO, "ConfigureAzalia() Start\n"));
+
+ *AzaliaEnable = FALSE;
+
+ ///
+ /// If all codec devices are to be disabled, skip the detection code
+ ///
+ if (PchPlatformPolicy->DeviceEnabling->Azalia == PCH_DEVICE_DISABLE) {
+ DEBUG ((EFI_D_ERROR | EFI_D_INFO, "Skip Azalia Codec detection.\n"));
+ return EFI_SUCCESS;
+ }
+
+ Status = DetectAndInitializeAzalia (PchPlatformPolicy, RootComplexBar, AzaliaEnable);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR | EFI_D_INFO, "Azalia detection / initialization failure!\n"));
+
+ if (PchPlatformPolicy->DeviceEnabling->Azalia == PCH_DEVICE_ENABLE) {
+ *AzaliaEnable = TRUE;
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "ConfigureAzalia() End\n"));
+ return EFI_SUCCESS;
+}