/** @file
|
Initializes the PCH HD Audio ACPI Tables.
|
|
Copyright (c) 2019 - 2020 Intel Corporation. All rights reserved. <BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
**/
|
|
#include <Library/DebugLib.h>
|
#include <Library/IoLib.h>
|
#include <Library/BaseMemoryLib.h>
|
#include <Library/PciSegmentLib.h>
|
#include <Library/UefiBootServicesTableLib.h>
|
#include <Library/UefiLib.h>
|
#include <Protocol/AcpiTable.h>
|
#include <Library/ConfigBlockLib.h>
|
|
#include "PchInit.h"
|
#include <Protocol/PchPolicy.h>
|
#include <ConfigBlock/HdAudioConfig.h>
|
#include <Private/PchConfigHob.h>
|
#include <Library/PchInfoLib.h>
|
#include <Private/Library/PchHdaLib.h>
|
#include <IndustryStandard/Pci30.h>
|
#include <Register/PchRegs.h>
|
#include <Register/PchRegsHda.h>
|
|
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;
|
}
|
|