alder_lake_bios/Intel/AlderLake/Features/Audio/NhltFeaturePkg/NhltInstallTable/NhltInstallTable.c

552 lines
18 KiB
C

/** @file
Nhlt driver for Intel platforms.
@copyright
INTEL CONFIDENTIAL
Copyright 2020 - 2021 Intel Corporation.
The source code contained or described herein and all documents related to the
source code ("Material") are owned by Intel Corporation or its suppliers or
licensors. Title to the Material remains with Intel Corporation or its suppliers
and licensors. The Material may contain trade secrets and proprietary and
confidential information of Intel Corporation and its suppliers and licensors,
and is protected by worldwide copyright and trade secret laws and treaty
provisions. No part of the Material may be used, copied, reproduced, modified,
published, uploaded, posted, transmitted, distributed, or disclosed in any way
without Intel's prior express written permission.
No license under any patent, copyright, trade secret or other intellectual
property right is granted to or conferred upon you by disclosure or delivery
of the Materials, either expressly, by implication, inducement, estoppel or
otherwise. Any license under such intellectual property rights must be
express and approved by Intel in writing.
Unless otherwise agreed by Intel in writing, you may not remove or alter
this notice or any other notice embedded in Materials by Intel or
Intel's suppliers or licensors in any way.
This file contains an 'Intel Peripheral Driver' and is 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.
@par Specification Reference:
**/
#include <Uefi.h>
#include <Uefi/UefiMultiPhase.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/BaseMemoryLib.h>
#include <Nhlt.h>
#include <NhltConfiguration.h>
#include <Library/NhltLib.h>
#include <Library/GetNhltConfigurationLib.h>
#include <Uefi/UefiBaseType.h>
#include <Protocol/AcpiTable.h>
#include <Pi/PiFirmwareFile.h>
#include <Library/PcdLib.h>
#include <Library/DxeServicesLib.h>
//
// This guids should be used by Platform/Board Code for Nhlt binary assignment
//
GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID mNhltConfigurationGuids [NHLT_ENDPOINTS_TABLE_MAX_CONFIGURATION_NUMBER] =
{
{0x06adc9b7, 0x837f, 0x47df, {0xac, 0x0c, 0xa0, 0xee, 0x18, 0xbf, 0xad, 0x67}},
{0x54067565, 0xb069, 0x4260, {0x87, 0xac, 0x41, 0x6a, 0xc8, 0x15, 0x9B, 0xd5}},
{0x729d003a, 0x0125, 0x4489, {0xb2, 0xec, 0x00, 0x41, 0x5c, 0x88, 0xef, 0xeb}},
{0x40801b42, 0x4b8e, 0x4cfc, {0x90, 0xf6, 0x8a, 0xaa, 0xea, 0x82, 0x60, 0x7c}},
{0x5f845818, 0x7d38, 0x4ebf, {0xb4, 0x10, 0x92, 0x2b, 0x8c, 0xe8, 0x25, 0xbb}},
{0x27bdbe6f, 0x4c7a, 0x48aa, {0x92, 0x89, 0x4c, 0x5a, 0x2e, 0xca, 0x28, 0xd7}},
{0xf1722f56, 0xf045, 0x4ca6, {0xa8, 0x4f, 0x6a, 0x7c, 0xa1, 0xa1, 0x4c, 0x8c}},
{0x0046a325, 0xb87b, 0x4dd3, {0x8a, 0x6f, 0x6a, 0xba, 0xcc, 0x9e, 0xfd, 0x5a}},
{0x4d77b5d2, 0xa3b5, 0x4abe, {0xbf, 0x70, 0xf9, 0x82, 0xb2, 0xbb, 0x2e, 0xed}},
{0x9e83ae47, 0x0db1, 0x4be0, {0x94, 0x78, 0x6e, 0x86, 0x36, 0x6d, 0x5e, 0xa4}},
{0xce49bfc7, 0xeebf, 0x49b9, {0xb5, 0xd0, 0x94, 0xa7, 0x71, 0x65, 0x9b, 0x00}},
{0x7da9fe6f, 0x0aa9, 0x443c, {0x9c, 0xa8, 0x23, 0x1e, 0xbb, 0xc9, 0x2b, 0x4b}},
{0xdce94204, 0x618e, 0x4289, {0xb9, 0x7a, 0x00, 0xcf, 0x43, 0xfd, 0xb2, 0x9a}},
{0x01a63902, 0x0efa, 0x4aff, {0x83, 0xa0, 0xfc, 0x1b, 0x90, 0x9e, 0xcd, 0xdf}},
{0xc7227c60, 0xf6fc, 0x48ee, {0xa1, 0x48, 0x19, 0xa4, 0xd0, 0x65, 0xf4, 0x7d}},
{0x4ec0c41e, 0x40d5, 0x4760, {0xab, 0x08, 0x11, 0xef, 0xc7, 0x17, 0xba, 0xae}}
};
GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mNhltOedConfiguration[] = { 0xEFBEADDE };
GLOBAL_REMOVE_IF_UNREFERENCED UINT32 gNhltOedConfigurationSize = sizeof (mNhltOedConfiguration);
/**
Get Nhlt binary table from FV
@param[in][out] NhltTableGuid Nhlt table guid.
@retval Pointer to NHLT configuration which is part of final Nhlt table.
**/
NHLT_ACPI_TABLE*
NhltGetTable (
IN EFI_GUID NhltTableGuid,
OUT UINTN *TableSize
)
{
EFI_STATUS Status;
NHLT_ACPI_TABLE *NhltTable;
NhltTable = NULL;
*TableSize = 0;
Status = GetSectionFromFv (
&NhltTableGuid,
EFI_SECTION_RAW,
0,
(VOID **) &NhltTable,
TableSize
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "NHLT table binary does not exist in FVs.\n"));
return NULL;
}
DEBUG ((DEBUG_INFO, "NHLT binary exist in FV. Guid: %g, Size = %d.\n", NhltTableGuid, *TableSize));
if (NhltTable->Header.Signature != NHLT_ACPI_TABLE_SIGNATURE) {
DEBUG ((DEBUG_ERROR, "NHLT has bad signature.\n"));
gBS->FreePool (NhltTable);
return NULL;
}
return NhltTable;
}
/**
Constructs SPECIFIC_CONFIG structure for OED configuration.
@param[in][out] **NhltTable Pointer to Nhlt table.
@param[in] NhltTableSize Nhlt table size.
@retval EFI_SUCCESS The function completed successfully
@retval EFI_BAD_BUFFER_SIZE Not enough resources to allocate NHLT
@retval EFI_NOT_FOUND NHLT structure is corrupted
@retval EFI_OUT_OF_RESOURCES Nhlt Oed configuration has bad size
**/
EFI_STATUS
NhltOedConfigConstructor (
IN OUT NHLT_ACPI_TABLE *NhltTable,
IN UINTN TableSize
)
{
SPECIFIC_CONFIG *OedConfig;
if (NhltTable == NULL) {
DEBUG ((DEBUG_ERROR, "NhltOedConfigConstructor: Nhlt table not exists.\n"));
return EFI_INVALID_PARAMETER;
}
OedConfig = GetNhltOedConfig (NhltTable, TableSize);
if (OedConfig == NULL) {
DEBUG ((DEBUG_ERROR, "NhltOedConfigConstructor: OED configuration not exists.\n"));
return EFI_NOT_FOUND;
}
OedConfig->CapabilitiesSize = gNhltOedConfigurationSize;
CopyMem (OedConfig->Capabilities, (UINT8*) mNhltOedConfiguration, gNhltOedConfigurationSize);
return EFI_SUCCESS;
}
/**
Add Nhlt Endpoints configuration to final NHLT table.
@param[in] *NhltConfiguration Pointer to Nhlt configuration.
@param[in][out] **NhltTable Pointer to Nhlt table.
@param[in] NhltTableSize Nhlt table size.
@retval EFI_SUCCESS The function completed successfully
@retval EFI_BAD_BUFFER_SIZE Not enough resources to allocate NHLT
@retval EFI_NOT_FOUND Configuration was not found
@retval EFI_OUT_OF_RESOURCES Nhlt endpoint has bad size
**/
EFI_STATUS
NhltEndpointsConstructor (
IN NHLT_CONFIGURATION *NhltConfiguration,
IN OUT NHLT_ACPI_TABLE *NhltTable,
IN UINTN NhltTableSize
)
{
UINTN Index;
UINT8 EndpointIndex;
NHLT_ACPI_TABLE *NhltTableSource;
UINTN NhltTableSourceSize;
ENDPOINT_DESCRIPTOR *NhltEndpoint;
NhltTableSourceSize = 0;
if (NhltConfiguration == NULL) {
return EFI_INVALID_PARAMETER;
}
if (NhltConfiguration == NULL) {
DEBUG ((DEBUG_ERROR, "NhltEndpointsConstructor: NhltConfiguration has NULL pointer.\n"));
return EFI_INVALID_PARAMETER;
}
for (Index = 0; Index < sizeof (NhltConfiguration->NhltConfigurationEnabled); Index++) {
if (NhltConfiguration->NhltConfigurationEnabled[Index] == TRUE) {
DEBUG ((DEBUG_INFO, "Conf#%d enabled. ", Index));
NhltTableSource = NhltGetTable (mNhltConfigurationGuids[Index], &NhltTableSourceSize);
if (NhltTableSource == NULL) {
DEBUG ((DEBUG_ERROR, "NhltEndpointsConstructor: NhltTableSource has NULL pointer.\n"));
continue;
}
for (EndpointIndex = 0; EndpointIndex < NhltTableSource->EndpointCount; EndpointIndex++) {
NhltEndpoint = GetNhltEndpoint (NhltTableSource, EndpointIndex, NhltTableSourceSize);
if (NhltEndpoint == NULL) {
DEBUG ((DEBUG_ERROR, "NhltEndpointsConstructor: Endpoint number %d not found in Nhlt.\n", EndpointIndex));
return EFI_NOT_FOUND;
}
CopyMem (GetNhltEndpoint (NhltTable, NhltTable->EndpointCount++, NhltTableSize), NhltEndpoint, NhltEndpoint->EndpointDescriptorLength);
}
}
}
return EFI_SUCCESS;
}
/**
Create Nhlt header which are compliant with ACPI standards and Intel ACPI tables naming.
@param[in][out] **NhltTable Pointer to Nhlt table.
@param[in] NhltTableSize Nhlt table size.
@retval EFI_SUCCESS The function completed successfully
@retval EFI_BAD_BUFFER_SIZE Not enough resources to allocate NHLT
**/
EFI_STATUS
NhltHeaderConstructor (
IN OUT NHLT_ACPI_TABLE *NhltTable,
IN UINT32 NhltTableSize
)
{
EFI_ACPI_DESCRIPTION_HEADER *NhltHeader;
NhltHeader = &(NhltTable->Header);
// Header
NhltHeader->Signature = NHLT_ACPI_TABLE_SIGNATURE;
NhltHeader->Length = NhltTableSize;
NhltHeader->Revision = 0x0;
NhltHeader->Checksum = 0x0;
NhltHeader->OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
NhltHeader->OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
NhltHeader->CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
NhltHeader->CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
CopyMem (NhltHeader->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (NhltHeader->OemId));
return EFI_SUCCESS;
}
/**
Based on Nhlt configuration function calculate Nhlt table size
@param[in] *NhltConfiguration Pointer to Nhlt configuration.
@retval Nhlt table size including Header, Endpoints configurations and OED configurations.
**/
UINT32
NhltCalculateTableSize (
IN NHLT_CONFIGURATION *NhltConfiguration
)
{
UINTN Index;
UINT8 EndpointIndex;
NHLT_ACPI_TABLE *NhltTableSource;
ENDPOINT_DESCRIPTOR *NhltEndpoint;
UINTN NhltTableSourceSize;
UINT32 NhltTableSize;
NhltTableSourceSize = 0;
if (NhltConfiguration == NULL) {
DEBUG ((DEBUG_ERROR, "NhltCalculateTableSize: NhltConfiguration has NULL pointer.\n"));
return 0;
}
// ACPI Header size
NhltTableSize = (UINT32) sizeof (EFI_ACPI_DESCRIPTION_HEADER);
// EndpointCount size
NhltTableSize += (UINT32) sizeof (UINT8);
for (Index = 0; Index < sizeof (NhltConfiguration->NhltConfigurationEnabled); Index++) {
if (NhltConfiguration->NhltConfigurationEnabled[Index] == TRUE) {
NhltTableSource = NhltGetTable (mNhltConfigurationGuids[Index], &NhltTableSourceSize);
if (NhltTableSource == NULL) {
DEBUG ((DEBUG_ERROR, "NhltCalculateTableSize: NhltTableSource has NULL pointer.\n"));
continue;
}
for (EndpointIndex = 0; EndpointIndex < NhltTableSource->EndpointCount; EndpointIndex++) {
NhltEndpoint = GetNhltEndpoint (NhltTableSource, EndpointIndex, NhltTableSourceSize);
if (NhltEndpoint == NULL) {
DEBUG ((DEBUG_ERROR, "NhltCalculateTableSize: NhltEndpoint has NULL pointer.\n"));
}
else{
// Endpoint size
NhltTableSize += (UINT32) NhltEndpoint->EndpointDescriptorLength;
}
}
}
}
// OED Configuration header size and OED Configuration size
NhltTableSize += (UINT32) (sizeof (UINT32) + gNhltOedConfigurationSize);
DEBUG ((DEBUG_INFO, "NhltCalculateTableSize: Required size: %d bytes.\n", NhltTableSize));
return NhltTableSize;
}
/**
Create valid Nhlt structure including Nhlt header, Endpoints configuration and Oed configuration.
@param[in] *NhltConfiguration Pointer to Nhlt configuration.
@param[in][out] **NhltTable Pointer to Nhlt table.
@retval EFI_SUCCESS The function completed successfully
@retval EFI_BAD_BUFFER_SIZE Not enough resources to allocate NHLT
@retval EFI_OUT_OF_RESOURCES Not enough memory to allocate NHLT
@retval EFI_NOT_FOUND NHLT structure is corrupted
**/
EFI_STATUS
NhltConstructor (
IN NHLT_CONFIGURATION *NhltConfiguration,
IN OUT EFI_ACPI_DESCRIPTION_HEADER **NhltTable
)
{
EFI_STATUS Status;
NHLT_ACPI_TABLE *TempNhltTable;
UINT32 NhltTableSize;
NhltTableSize = NhltCalculateTableSize (NhltConfiguration);
TempNhltTable = AllocateZeroPool (NhltTableSize);
if (TempNhltTable == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Nhlt header should be added first because other parts of NHLT use Nhlt size value from header
//
NhltHeaderConstructor (TempNhltTable, NhltTableSize);
Status = NhltEndpointsConstructor (NhltConfiguration, TempNhltTable, NhltTableSize);
if (EFI_ERROR (Status)) {
gBS->FreePool (TempNhltTable);
return Status;
}
Status = NhltOedConfigConstructor (TempNhltTable, NhltTableSize);
if (EFI_ERROR (Status)) {
gBS->FreePool (TempNhltTable);
return Status;
}
*NhltTable = (EFI_ACPI_DESCRIPTION_HEADER *) TempNhltTable;
return EFI_SUCCESS;
}
/**
Initialize and publish NHLT (Non-HDA Link Table), update NVS variables.
@param[in] *NhltConfiguration Pointer to Nhlt configuration.
@retval EFI_SUCCESS The function completed successfully
@retval EFI_BAD_BUFFER_SIZE Not enough resources to allocate NHLT
@retval EFI_OUT_OF_RESOURCES Not enough memory to allocate NHLT
@retval EFI_INVALID_PARAMETER NHLT structure is corrupted
**/
EFI_STATUS
NhltInstallTable (
IN NHLT_CONFIGURATION *NhltConfiguration
)
{
EFI_ACPI_DESCRIPTION_HEADER *NhltTable;
UINTN AcpiTableKey;
EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
EFI_STATUS Status;
AcpiTableProtocol = NULL;
NhltTable = NULL;
AcpiTableKey = 0;
DEBUG ((DEBUG_INFO, "%a () Start.\n", __FUNCTION__));
Status = NhltConstructor (NhltConfiguration, &NhltTable);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Nhlt not created correctly - Status = %r\n", Status));
return Status;
}
//
// Locate ACPI support protocol
//
Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);
if ( EFI_ERROR (Status) || AcpiTableProtocol == NULL) {
gBS->FreePool (NhltTable);
return EFI_UNSUPPORTED;
}
//
// Publish NHLT ACPI table
//
Status = AcpiTableProtocol->InstallAcpiTable (
AcpiTableProtocol,
NhltTable,
NhltTable->Length,
&AcpiTableKey
);
gBS->FreePool (NhltTable);
if (EFI_ERROR (Status)) {
return Status;
}
DEBUG ((DEBUG_INFO, "%a () End. Status = %r.\n", __FUNCTION__, Status));
return EFI_SUCCESS;
}
/**
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
**/
EFI_STATUS
NhltLocateAndDumpAcpiTable (
VOID
)
{
EFI_ACPI_6_2_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.
///
Status = EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid, (VOID *) &Rsdp);
if (EFI_ERROR (Status) || (Rsdp == NULL)) {
DEBUG ((DEBUG_ERROR, "EFI_ERROR or Rsdp == NULL\n"));
return Status;
}
Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->XsdtAddress;
if (Xsdt == NULL || Xsdt->Signature != EFI_ACPI_6_2_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_6_2_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
DEBUG ((DEBUG_ERROR, "XSDT/RSDT == NULL or wrong signature\n"));
return EFI_NOT_FOUND;
}
}
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 EFI_NOT_FOUND;
}
DEBUG ((DEBUG_INFO, "Found NhltTable, Address = 0x%016lx\n", Nhlt));
DEBUG_CODE ( NhltAcpiTableDump (Nhlt); );
return EFI_SUCCESS;
}
/**
Nhlt install table notification event handler.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
**/
VOID
EFIAPI
NhltInstallTableEventOnAcpiProtocol (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
NHLT_CONFIGURATION NhltConfiguration;
DEBUG ((DEBUG_INFO, "%a () Start.\n", __FUNCTION__));
gBS->CloseEvent (Event);
Status = GetNhltConfiguration (&NhltConfiguration);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Failed to load NHLT configuration. Status = %r.\n", Status));
DEBUG ((DEBUG_INFO, "%a () End. Status = %r.\n", __FUNCTION__, Status));
return;
}
Status = NhltInstallTable (&NhltConfiguration);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Failed to install NHLT table.\n"));
DEBUG ((DEBUG_INFO, "%a () End. Status = %r.\n", __FUNCTION__, Status));
return;
}
Status = NhltLocateAndDumpAcpiTable ();
DEBUG ((DEBUG_INFO, "%a () End. Status = %r.\n", __FUNCTION__, Status));
}
/**
Entry point for Nhlt Install driver for Intel platforms
@param[in] ImageHandle This image handle
@param[in] SystemTable System table pointer
@retval EFI_SUCCESS The function completed successfully
@retval EFI_ABORTED Event not installed
**/
EFI_STATUS
EFIAPI
NhltInstallTableDriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
VOID *Registration;
EFI_EVENT Event;
Event = NULL;
Event = EfiCreateProtocolNotifyEvent (
&gEfiAcpiTableProtocolGuid,
TPL_CALLBACK,
NhltInstallTableEventOnAcpiProtocol,
NULL,
&Registration
);
if (Event == NULL) {
return EFI_ABORTED;
}
return EFI_SUCCESS;
}