/** @file Initializes the PCH HD Audio ACPI Tables. Copyright (c) 2019 - 2020 Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #include "PchInit.h" #include #include #include #include #include #include #include #include PCH_HDA_NHLT_ENDPOINTS mPchHdaNhltEndpoints[HdaEndpointMax] = { {HdaDmicX1, B_HDA_DMIC_1CH_48KHZ_16BIT_FORMAT, 0, FALSE}, {HdaDmicX2, (B_HDA_DMIC_2CH_48KHZ_16BIT_FORMAT | B_HDA_DMIC_2CH_48KHZ_32BIT_FORMAT), 0, FALSE}, {HdaDmicX4, (B_HDA_DMIC_4CH_48KHZ_16BIT_FORMAT | B_HDA_DMIC_4CH_48KHZ_32BIT_FORMAT), 0, FALSE}, {HdaBtRender, (B_HDA_BT_NARROWBAND_FORMAT | B_HDA_BT_WIDEBAND_FORMAT | B_HDA_BT_A2DP_FORMAT), 0, FALSE}, {HdaBtCapture, (B_HDA_BT_NARROWBAND_FORMAT | B_HDA_BT_WIDEBAND_FORMAT), 0, FALSE}, {HdaI2sRender1, B_HDA_I2S_RTK274_RENDER_4CH_48KHZ_24BIT_FORMAT, B_HDA_I2S_RENDER_DEVICE_INFO, FALSE}, {HdaI2sRender2, B_HDA_I2S_RTK274_RENDER_4CH_48KHZ_24BIT_FORMAT, B_HDA_I2S_RENDER_DEVICE_INFO, FALSE}, {HdaI2sCapture, B_HDA_I2S_RTK274_CAPTURE_4CH_48KHZ_24BIT_FORMAT, B_HDA_I2S_CAPTURE_DEVICE_INFO, FALSE} }; #define DSP_FW_STOLEN_MEMORY_SIZE 0x400000 //4MB /** Allocates 4MB of memory for DSP FW usage. @retval EFI_PHYSICAL_ADDRESS Allocated memory address **/ EFI_PHYSICAL_ADDRESS AllocateAudioDspStolenMemory ( ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS DspStolenMemBaseAddress; DspStolenMemBaseAddress = 0; DEBUG ((DEBUG_INFO, "AllocateAudioDspStolenMemory()\n")); // // Reserve memory to store Acpi Debug data. // DspStolenMemBaseAddress = 0xFFFFFFFF; Status = gBS->AllocatePages ( AllocateMaxAddress, EfiReservedMemoryType, EFI_SIZE_TO_PAGES (DSP_FW_STOLEN_MEMORY_SIZE), &DspStolenMemBaseAddress ); ASSERT_EFI_ERROR(Status); ZeroMem ((VOID *) (UINTN) DspStolenMemBaseAddress, DSP_FW_STOLEN_MEMORY_SIZE); mPchNvsAreaProtocol.Area->DSPM = (UINT32) DspStolenMemBaseAddress; DEBUG ((DEBUG_INFO, "mPchNvsAreaProtocol.Area->DSPM = 0x%016x\n", mPchNvsAreaProtocol.Area->DSPM)); return DspStolenMemBaseAddress; } /** Retrieves address of NHLT table from XSDT/RSDT. @retval NHLT_ACPI_TABLE* Pointer to NHLT table if found @retval NULL NHLT could not be found **/ NHLT_ACPI_TABLE * LocateNhltAcpiTable ( VOID ) { EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp; EFI_ACPI_DESCRIPTION_HEADER *Xsdt; NHLT_ACPI_TABLE *Nhlt; UINTN Index; UINT64 Data64; EFI_STATUS Status; Rsdp = NULL; Xsdt = NULL; Nhlt = NULL; /// /// Find the AcpiSupport protocol returns RSDP (or RSD PTR) address. /// DEBUG ((DEBUG_INFO, "LocateNhltAcpiTable() Start\n")); Status = EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid, (VOID *) &Rsdp); if (EFI_ERROR (Status) || (Rsdp == NULL)) { DEBUG ((DEBUG_ERROR, "EFI_ERROR or Rsdp == NULL\n")); return NULL; } Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->XsdtAddress; if (Xsdt == NULL || Xsdt->Signature != EFI_ACPI_5_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) { // If XSDT has not been found, check RSDT Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->RsdtAddress; if (Xsdt == NULL || Xsdt->Signature != EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) { DEBUG ((DEBUG_ERROR, "XSDT/RSDT == NULL or wrong signature\n")); return NULL; } } for (Index = sizeof (EFI_ACPI_DESCRIPTION_HEADER); Index < Xsdt->Length; Index = Index + sizeof (UINT64)) { Data64 = *(UINT64 *) ((UINT8 *) Xsdt + Index); Nhlt = (NHLT_ACPI_TABLE *) (UINTN) Data64; if (Nhlt->Header.Signature == NHLT_ACPI_TABLE_SIGNATURE) { break; } } if (Nhlt == NULL || Nhlt->Header.Signature != NHLT_ACPI_TABLE_SIGNATURE) { DEBUG ((DEBUG_ERROR, "Nhlt == NULL or wrong signature\n")); return NULL; } DEBUG ((DEBUG_INFO, "Found NhltTable, Address = 0x%016x\n", Nhlt)); return Nhlt; } /** Constructs and installs NHLT table. @retval EFI_SUCCESS ACPI Table installed successfully @retval EFI_UNSUPPORTED ACPI Table protocol not found **/ EFI_STATUS PublishNhltAcpiTable ( VOID ) { UINTN AcpiTableKey; EFI_ACPI_TABLE_PROTOCOL *AcpiTable; NHLT_ACPI_TABLE *NhltTable; UINT32 TableLength; EFI_STATUS Status; AcpiTable = NULL; NhltTable = NULL; AcpiTableKey = 0; DEBUG ((DEBUG_INFO, "PublishNhltAcpiTable() Start\n")); // // Locate ACPI support protocol // Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable); if ( EFI_ERROR (Status) || AcpiTable == NULL) { return EFI_UNSUPPORTED; } NhltConstructor (mPchHdaNhltEndpoints, &NhltTable, &TableLength); NhltAcpiHeaderConstructor (NhltTable, TableLength); Status = AcpiTable->InstallAcpiTable (AcpiTable, NhltTable, NhltTable->Header.Length, &AcpiTableKey); DEBUG ((DEBUG_INFO, "PublishNhltAcpiTable() End\n")); return Status; } /** Sets NVS ACPI variables for HDAS._DSM and SNDW._DSD accordingly to policy. @param[in] NhltAcpiTableAddress @param[in] NhltAcpiTableLength @param[in] *HdAudioConfigHob @param[in] *HdAudioDxeConfig **/ VOID UpdateHdaAcpiData ( IN UINT64 NhltAcpiTableAddress, IN UINT32 NhltAcpiTableLength, IN CONST HDAUDIO_HOB *HdAudioConfigHob, IN CONST PCH_HDAUDIO_DXE_CONFIG *HdAudioDxeConfig ) { DEBUG ((DEBUG_INFO, "UpdateHdaAcpiData():\n NHLT Address = 0x%016x, Length = 0x%08x\n", NhltAcpiTableAddress, NhltAcpiTableLength)); DEBUG ((DEBUG_INFO, " FeatureMask = 0x%08x\n", HdAudioDxeConfig->DspFeatureMask)); mPchNvsAreaProtocol.Area->NHLA = NhltAcpiTableAddress; mPchNvsAreaProtocol.Area->NHLL = NhltAcpiTableLength; mPchNvsAreaProtocol.Area->ADFM = HdAudioDxeConfig->DspFeatureMask; mPchNvsAreaProtocol.Area->SWQ0 = HdAudioConfigHob->AudioLinkSndw1 ? 0 : BIT1; mPchNvsAreaProtocol.Area->SWQ1 = HdAudioConfigHob->AudioLinkSndw2 ? 0 : BIT1; mPchNvsAreaProtocol.Area->SWQ2 = HdAudioConfigHob->AudioLinkSndw3 ? 0 : BIT1; mPchNvsAreaProtocol.Area->SWQ3 = HdAudioConfigHob->AudioLinkSndw4 ? 0 : BIT1; } /** Initialize and publish NHLT (Non-HDA Link Table), update NVS variables. @param[in] *HdAudioConfigHob @param[in] *HdAudioDxeConfig @retval EFI_SUCCESS The function completed successfully **/ EFI_STATUS SetHdaAcpiTable ( IN CONST HDAUDIO_HOB *HdAudioConfigHob, IN CONST PCH_HDAUDIO_DXE_CONFIG *HdAudioDxeConfig ) { NHLT_ACPI_TABLE *NhltTable; EFI_STATUS Status; NhltTable = NULL; Status = EFI_SUCCESS; if (HdAudioDxeConfig->NhltDefaultFlow == TRUE) { switch (HdAudioDxeConfig->DspEndpointDmic) { case PchHdaDmic1chArray: mPchHdaNhltEndpoints[HdaDmicX1].Enable = TRUE; break; case PchHdaDmic2chArray: mPchHdaNhltEndpoints[HdaDmicX2].Enable = TRUE; break; case PchHdaDmic4chArray: mPchHdaNhltEndpoints[HdaDmicX4].Enable = TRUE; break; case PchHdaDmicDisabled: default: mPchHdaNhltEndpoints[HdaDmicX2].Enable = FALSE; mPchHdaNhltEndpoints[HdaDmicX4].Enable = FALSE; } if (HdAudioDxeConfig->DspEndpointBluetooth) { mPchHdaNhltEndpoints[HdaBtRender].Enable = TRUE; mPchHdaNhltEndpoints[HdaBtCapture].Enable = TRUE; } if (HdAudioDxeConfig->DspEndpointI2s) { mPchHdaNhltEndpoints[HdaI2sRender1].Enable = TRUE; mPchHdaNhltEndpoints[HdaI2sRender2].Enable = TRUE; mPchHdaNhltEndpoints[HdaI2sCapture].Enable = TRUE; } Status = PublishNhltAcpiTable (); } NhltTable = LocateNhltAcpiTable (); if (NhltTable == NULL) { return EFI_LOAD_ERROR; } UpdateHdaAcpiData ((UINT64) (UINTN) NhltTable, (UINT32) (NhltTable->Header.Length), HdAudioConfigHob, HdAudioDxeConfig); if (IsPchLp () && (PchStepping () < PCH_B0)) { AllocateAudioDspStolenMemory (); } DEBUG_CODE ( NhltAcpiTableDump (NhltTable); ); return Status; } /** Initialize Intel High Definition Audio ACPI Tables @retval EFI_SUCCESS The function completed successfully @retval EFI_LOAD_ERROR ACPI table cannot be installed @retval EFI_UNSUPPORTED ACPI table not set because DSP is disabled **/ EFI_STATUS PchHdAudioAcpiInit ( VOID ) { EFI_STATUS Status; UINT64 HdaPciBase; CONST HDAUDIO_HOB *HdAudioConfigHob; PCH_POLICY_PROTOCOL *PchPolicy; PCH_HDAUDIO_DXE_CONFIG *HdAudioDxeConfig; DEBUG ((DEBUG_INFO, "PchHdAudioAcpiInit() Start\n")); HdAudioConfigHob = &mPchConfigHob->HdAudio; /// /// Get PCH Policy Protocol /// Status = gBS->LocateProtocol (&gPchPolicyProtocolGuid, NULL, (VOID **)&PchPolicy); ASSERT_EFI_ERROR (Status); /// /// Get HD Audio DXE Config Block /// Status = GetConfigBlock ((VOID *)PchPolicy, &gHdAudioDxeConfigGuid, (VOID *)&HdAudioDxeConfig); ASSERT_EFI_ERROR (Status); HdaPciBase = PCI_SEGMENT_LIB_ADDRESS ( DEFAULT_PCI_SEGMENT_NUMBER_PCH, DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_HDA, PCI_FUNCTION_NUMBER_PCH_HDA, 0 ); if ((PciSegmentRead16 (HdaPciBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) || (HdAudioConfigHob->DspEnable == FALSE)) { // Do not set ACPI tables if HDAudio is Function disabled or DSP is disabled DEBUG ((DEBUG_INFO, "AudioDSP: Non-HDAudio ACPI Table (NHLT) not set!\n")); return EFI_UNSUPPORTED; } Status = SetHdaAcpiTable (HdAudioConfigHob, HdAudioDxeConfig); DEBUG ((DEBUG_INFO, "PchHdAudioAcpiInit() End - Status = %r\n", Status)); return Status; }