849 lines
28 KiB
C
849 lines
28 KiB
C
/** @file
|
|
This DXE driver configures Sndw controllers, performs codecs enumeration process, allows to send/receive messages to/from them.
|
|
|
|
@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 a 'Sample Driver' and is licensed as such under the terms
|
|
of your license agreement with Intel or your vendor. This file may be modified
|
|
by the user, subject to the additional terms of the license agreement.
|
|
|
|
@par Specification Reference:
|
|
**/
|
|
#include <Base.h>
|
|
#include <Uefi.h>
|
|
#include <Pi/PiFirmwareFile.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/IoLib.h>
|
|
#include <Library/TimerLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/DxeServicesLib.h>
|
|
#include <Library/PciSegmentLib.h>
|
|
#include <Library/UefiDriverEntryPoint.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/UefiRuntimeServicesTableLib.h>
|
|
#include <Library/PeiDxeSndwCommonLib.h>
|
|
#include <Library/PeiDxeSndwInitLib.h>
|
|
#include <Protocol/SndwAccessProtocol.h>
|
|
#include <IndustryStandard/Pci22.h>
|
|
#include <Register/SndwCavsRegs.h>
|
|
#include <Register/SndwCadenceRegs.h>
|
|
#include <SndwMipiCmd.h>
|
|
|
|
#define SNDW_ACCESS_SIGNATURE SIGNATURE_32 ('s', 'd', 'w', 'a')
|
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED SNDW_COMMAND MipiSndwPeripheralInitCmds = {
|
|
.TxWrite = {
|
|
.OpCode = SndwCmdWrite,
|
|
.RegAddr = 0x0049,
|
|
.RegData = 0x01,
|
|
}
|
|
};
|
|
|
|
typedef struct {
|
|
LIST_ENTRY ListEntry;
|
|
SNDW_CODEC_INFO CodecInfo;
|
|
UINTN SndwControllerMmioOffset;
|
|
UINT32 PeripheralIndex;
|
|
} CODEC_LIST_ENTRY;
|
|
|
|
#define CODEC_LIST_ENTRY_FROM_LIST_ENTRY(a) BASE_CR (a, CODEC_LIST_ENTRY, ListEntry)
|
|
|
|
typedef struct {
|
|
UINTN Signature;
|
|
SNDW_ACCESS_PROTOCOL SndwAccessProtocol;
|
|
CODEC_LIST_ENTRY *CodecListHead;
|
|
UINTN EnableCounter;
|
|
} SNDW_ACCESS_CONTEXT;
|
|
|
|
#define SNDW_ACCESS_CONTEXT_FROM_SNDW_ACCESS_PROTOCOL(a) CR (a, SNDW_ACCESS_CONTEXT, SndwAccessProtocol, SNDW_ACCESS_SIGNATURE)
|
|
|
|
|
|
EFI_STATUS
|
|
EnableHdaDspMmioAccess (
|
|
IN OUT UINT64 *HdaBar,
|
|
IN OUT UINT64 *DspBar,
|
|
OUT BOOLEAN *IsTemporaryBar
|
|
)
|
|
{
|
|
UINT64 HdaPciBase;
|
|
|
|
*IsTemporaryBar = FALSE;
|
|
|
|
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_DEVICE_ID_OFFSET) == 0xFFFF) {
|
|
DEBUG ((DEBUG_WARN, "HDA is not enabled in this phase.\n"));
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
*HdaBar = (UINT64) PciSegmentRead32 (HdaPciBase + R_HDA_CFG_HDALBA);
|
|
if ((*HdaBar & B_PCI_BAR_MEMORY_TYPE_MASK) == B_PCI_BAR_MEMORY_TYPE_64) {
|
|
*HdaBar |= LShiftU64 ((UINT64) PciSegmentRead32 (HdaPciBase + R_HDA_CFG_HDAUBA), 32);
|
|
}
|
|
*HdaBar &= ~((UINT64) (0xFFFFF));
|
|
|
|
*DspBar = (UINT64) PciSegmentRead32 (HdaPciBase + R_HDA_CFG_ADSPLBA);
|
|
if ((*DspBar & B_PCI_BAR_MEMORY_TYPE_MASK) == B_PCI_BAR_MEMORY_TYPE_64) {
|
|
*DspBar |= LShiftU64 ((UINT64) PciSegmentRead32 (HdaPciBase + R_HDA_CFG_ADSPUBA), 32);
|
|
}
|
|
*DspBar &= ~((UINT64) (0xFFFFF));
|
|
|
|
if (*HdaBar == 0 || *DspBar == 0) {
|
|
DEBUG ((DEBUG_WARN, "DSP Bar isn't programmed in this phase, set HDA and DSP bars to temporary value.\n"));
|
|
*HdaBar = (UINT64) PcdGet32 (PcdSiliconInitTempMemBaseAddr);
|
|
*DspBar = (UINT64) PcdGet32 (PcdSiliconInitTempMemBaseAddr) + (UINT64) V_HDA_CFG_HDABAR_SIZE;
|
|
PciSegmentWrite32 (HdaPciBase + R_HDA_CFG_HDALBA, (UINT32) *HdaBar);
|
|
PciSegmentWrite32 (HdaPciBase + R_HDA_CFG_HDAUBA, 0);
|
|
PciSegmentWrite32 (HdaPciBase + R_HDA_CFG_ADSPLBA, (UINT32) *DspBar);
|
|
PciSegmentWrite32 (HdaPciBase + R_HDA_CFG_ADSPUBA, 0);
|
|
*IsTemporaryBar = TRUE;
|
|
}
|
|
|
|
//
|
|
// Enable memory map access
|
|
//
|
|
PciSegmentOr16 (HdaPciBase + PCI_COMMAND_OFFSET, (UINT16) EFI_PCI_COMMAND_MEMORY_SPACE);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
DisableHdaDspMmioAccess (
|
|
IN BOOLEAN IsTemporaryBar
|
|
)
|
|
{
|
|
UINTN HdaPciBase;
|
|
|
|
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
|
|
);
|
|
|
|
//
|
|
// Disable memory map access
|
|
//
|
|
PciSegmentAnd16 (HdaPciBase + PCI_COMMAND_OFFSET, (UINT16) (~EFI_PCI_COMMAND_MEMORY_SPACE));
|
|
//
|
|
// Clear DSP and HDA BARs
|
|
//
|
|
if (IsTemporaryBar == TRUE) {
|
|
PciSegmentWrite32 (HdaPciBase + R_HDA_CFG_HDALBA, 0);
|
|
PciSegmentWrite32 (HdaPciBase + R_HDA_CFG_HDAUBA, 0);
|
|
PciSegmentWrite32 (HdaPciBase + R_HDA_CFG_ADSPLBA, 0);
|
|
PciSegmentWrite32 (HdaPciBase + R_HDA_CFG_ADSPUBA, 0);
|
|
}
|
|
}
|
|
|
|
|
|
EFI_STATUS
|
|
GetCodecAddressFromCodecInfo (
|
|
IN SNDW_ACCESS_CONTEXT *SndwAccessContext,
|
|
IN SNDW_CODEC_INFO *SndwCodecInfo,
|
|
IN OUT UINT32 *PeripheralIndex,
|
|
IN OUT UINTN *SndwControllerMmioOffset
|
|
)
|
|
{
|
|
CODEC_LIST_ENTRY *CurrentSndwListEntry;
|
|
LIST_ENTRY *ListEntryHead;
|
|
LIST_ENTRY *CurrentListEntry;
|
|
|
|
*SndwControllerMmioOffset = 0;
|
|
*PeripheralIndex = 0;
|
|
|
|
CurrentSndwListEntry = SndwAccessContext->CodecListHead;
|
|
CurrentListEntry = &(CurrentSndwListEntry->ListEntry);
|
|
ListEntryHead = CurrentListEntry;
|
|
|
|
while (CurrentListEntry != NULL) {
|
|
CurrentSndwListEntry = CODEC_LIST_ENTRY_FROM_LIST_ENTRY (CurrentListEntry);
|
|
|
|
if ((CurrentSndwListEntry->CodecInfo.SndwLinkIndex == SndwCodecInfo->SndwLinkIndex) &&
|
|
(CompareMem (CurrentSndwListEntry->CodecInfo.CodecId.Data, SndwCodecInfo->CodecId.Data, sizeof (SNDW_CODEC_ID)) == 0)) {
|
|
*PeripheralIndex = CurrentSndwListEntry->PeripheralIndex;
|
|
*SndwControllerMmioOffset = CurrentSndwListEntry->SndwControllerMmioOffset;
|
|
DEBUG ((DEBUG_INFO, "Codec Found - PeripheralIndex: 0x%x, SndwControllerMmioOffset: 0x%x\n", *PeripheralIndex, *SndwControllerMmioOffset));
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
CurrentListEntry = GetNextNode (ListEntryHead, CurrentListEntry);
|
|
if (CurrentListEntry == ListEntryHead) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
|
|
/**
|
|
Function operating on Sndw Fifo buffer for sending messages to codecs.
|
|
|
|
@param[in] This Pointer to Sndw Access Protocol
|
|
@param[in] SndwCodecInfo Sndw codec information
|
|
@param[in] TxCommands Pointer to send messages
|
|
@param[in] TxSize Size of messages to send
|
|
|
|
@retval EFI_SUCCESS Message sent successfully
|
|
@retval EFI_NOT_FOUND Given codec not found
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DxeSndwSend (
|
|
IN CONST SNDW_ACCESS_PROTOCOL *This,
|
|
IN SNDW_CODEC_INFO SndwCodecInfo,
|
|
IN SNDW_COMMAND *TxCommand,
|
|
IN UINTN TxSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
SNDW_ACCESS_CONTEXT *SndwAccessContext;
|
|
UINTN SndwControllerMmioOffset;
|
|
UINTN Index;
|
|
UINT64 HdaBar;
|
|
UINT64 DspBar;
|
|
UINT32 PeripheralIndex;
|
|
BOOLEAN IsTemporaryBar;
|
|
|
|
DEBUG ((DEBUG_INFO, "%a () - Start.\n", __FUNCTION__));
|
|
|
|
if (This == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Sndw Access protocol has not been passed, aborting.\n"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
EnableHdaDspMmioAccess (&HdaBar, &DspBar, &IsTemporaryBar);
|
|
|
|
SndwAccessContext = SNDW_ACCESS_CONTEXT_FROM_SNDW_ACCESS_PROTOCOL (This);
|
|
Status = GetCodecAddressFromCodecInfo (SndwAccessContext, &SndwCodecInfo, &PeripheralIndex, &SndwControllerMmioOffset);
|
|
if (EFI_ERROR (Status)) {
|
|
DisableHdaDspMmioAccess (IsTemporaryBar);
|
|
DEBUG ((DEBUG_INFO, "%a () - End. Status = %r\n", __FUNCTION__, Status));
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
for (Index = 0; Index < TxSize; Index++) {
|
|
TxCommand[Index].TxWrite.DeviceAddress = PeripheralIndex;
|
|
}
|
|
Send (DspBar + SndwControllerMmioOffset, TxCommand, TxSize);
|
|
|
|
DisableHdaDspMmioAccess (IsTemporaryBar);
|
|
|
|
DEBUG ((DEBUG_INFO, "%a () - End.\n", __FUNCTION__));
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Function sends one message through the Sndw interface and waits
|
|
for the corresponding ACK message.
|
|
|
|
@param[in] This Pointer to Sndw Access Protocol
|
|
@param[in] SndwCodecInfo Sndw codec information
|
|
@param[in] TxCommands Pointer to sending message
|
|
@param[out] RxCommands Pointer to receiving message
|
|
|
|
@retval EFI_SUCCESS The function completed successfully
|
|
@retval EFI_NOT_FOUND Given codec not found
|
|
@retval EFI_TIMEOUT Sending command has failed
|
|
@retval EFI_DEVICE_ERROR Response command has failed
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DxeSndwSendWithAck (
|
|
IN CONST SNDW_ACCESS_PROTOCOL *This,
|
|
IN SNDW_CODEC_INFO SndwCodecInfo,
|
|
IN SNDW_COMMAND TxCommand,
|
|
OUT SNDW_COMMAND* RxCommand OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
SNDW_ACCESS_CONTEXT *SndwAccessContext;
|
|
UINTN SndwControllerMmioOffset;
|
|
UINT64 HdaBar;
|
|
UINT64 DspBar;
|
|
UINT32 PeripheralIndex;
|
|
BOOLEAN IsTemporaryBar;
|
|
|
|
DEBUG ((DEBUG_INFO, "%a () - Start.\n", __FUNCTION__));
|
|
|
|
if (This == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Sndw Access protocol has not been passed, aborting.\n"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
EnableHdaDspMmioAccess (&HdaBar, &DspBar, &IsTemporaryBar);
|
|
|
|
SndwAccessContext = SNDW_ACCESS_CONTEXT_FROM_SNDW_ACCESS_PROTOCOL (This);
|
|
Status = GetCodecAddressFromCodecInfo (SndwAccessContext, &SndwCodecInfo, &PeripheralIndex, &SndwControllerMmioOffset);
|
|
if (EFI_ERROR (Status)) {
|
|
DisableHdaDspMmioAccess (IsTemporaryBar);
|
|
DEBUG ((DEBUG_INFO, "%a () - End. Status = %r\n", __FUNCTION__, Status));
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "PeripheralIndex: %d\n", PeripheralIndex));
|
|
DEBUG ((DEBUG_INFO, "Sndw%d: Controller mmio address: 0x%X.\n", SndwCodecInfo.SndwLinkIndex, DspBar + SndwControllerMmioOffset));
|
|
|
|
TxCommand.TxWrite.DeviceAddress = PeripheralIndex;
|
|
SendwAck (DspBar + SndwControllerMmioOffset, TxCommand, RxCommand);
|
|
|
|
DisableHdaDspMmioAccess (IsTemporaryBar);
|
|
|
|
DEBUG ((DEBUG_INFO, "%a () - End.\n", __FUNCTION__));
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Function operating on Sndw Fifo for receiving messages from codecs.
|
|
|
|
@param[in] This Pointer to Sndw Access Protocol
|
|
@param[in] SndwCodecInfo Sndw codec information
|
|
@param[out] RxCommands Pointer to pointer to received messages.
|
|
Memory pool is allocated in this function,
|
|
but the caller is responsible for
|
|
freeing the memory with FreePool.
|
|
@param[out] RxSize Size of received messages
|
|
|
|
@retval EFI_SUCCESS Message received successfully
|
|
@retval EFI_NOT_FOUND Given codec not found
|
|
@retval EFI_OUT_OF_RESOURCES Memory allocation for response failed
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DxeSndwReceive (
|
|
IN CONST SNDW_ACCESS_PROTOCOL *This,
|
|
IN SNDW_CODEC_INFO SndwCodecInfo,
|
|
OUT SNDW_COMMAND **RxCommands,
|
|
OUT UINTN* RxSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
SNDW_ACCESS_CONTEXT *SndwAccessContext;
|
|
UINTN SndwControllerMmioOffset;
|
|
UINT64 HdaBar;
|
|
UINT64 DspBar;
|
|
BOOLEAN IsTemporaryBar;
|
|
|
|
DEBUG ((DEBUG_INFO, "%a () - Start.\n", __FUNCTION__));
|
|
|
|
if (This == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Sndw Access protocol has not been passed, aborting.\n"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
EnableHdaDspMmioAccess (&HdaBar, &DspBar, &IsTemporaryBar);
|
|
|
|
SndwAccessContext = SNDW_ACCESS_CONTEXT_FROM_SNDW_ACCESS_PROTOCOL (This);
|
|
Status = GetCodecAddressFromCodecInfo (SndwAccessContext, &SndwCodecInfo, NULL, &SndwControllerMmioOffset);
|
|
if (EFI_ERROR (Status)) {
|
|
DisableHdaDspMmioAccess (IsTemporaryBar);
|
|
DEBUG ((DEBUG_INFO, "%a () - End. Status = %r\n", __FUNCTION__, Status));
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
Receive (DspBar + SndwControllerMmioOffset, RxCommands, RxSize);
|
|
|
|
DisableHdaDspMmioAccess (IsTemporaryBar);
|
|
|
|
if (*RxCommands == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "%a () - End.\n", __FUNCTION__));
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Function disables Soundwire interface
|
|
|
|
@param[in] This Pointer to Sndw Access Protocol
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_DEVICE_ERROR
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DxeSndwAccessDisable (
|
|
IN CONST SNDW_ACCESS_PROTOCOL *This
|
|
)
|
|
{
|
|
SNDW_ACCESS_CONTEXT *SndwAccessContext;
|
|
UINT64 HdaBar;
|
|
UINT64 DspBar;
|
|
BOOLEAN IsTemporaryBar;
|
|
|
|
if (This == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Sndw Access protocol has not been passed, aborting.\n"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
SndwAccessContext = SNDW_ACCESS_CONTEXT_FROM_SNDW_ACCESS_PROTOCOL (This);
|
|
if (SndwAccessContext->EnableCounter <= 0) {
|
|
DEBUG ((DEBUG_ERROR, "SndwAccess already disabled.\n"));
|
|
return EFI_SUCCESS;
|
|
}
|
|
SndwAccessContext->EnableCounter -= 1;
|
|
if (SndwAccessContext->EnableCounter > 0) {
|
|
DEBUG ((DEBUG_ERROR, "SndwAccess still being used.\n"));
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EnableHdaDspMmioAccess (&HdaBar, &DspBar, &IsTemporaryBar);
|
|
ResetDsp (DspBar);
|
|
DisableHdaDspMmioAccess (IsTemporaryBar);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Function initializes Soundwire controllers
|
|
|
|
@param[in, out] NumberOfSupportedSndwLinks Pointer to number of supported Sndw links
|
|
@param[in] HdaBar HDA base address
|
|
@param[in] DspBar DSP base address
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_DEVICE_ERROR
|
|
**/
|
|
EFI_STATUS
|
|
InitializeSndwControllers (
|
|
IN OUT UINTN *NumberOfSupportedSndwLinks,
|
|
IN UINT64 HdaBar,
|
|
IN UINT64 DspBar
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT64 SndwControllerMmioOffset;
|
|
UINT32 SndwLinkIndex;
|
|
|
|
Status = GetDspOutOfReset (HdaBar, DspBar);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "%a () - End. Status = %r\n", __FUNCTION__, Status));
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
///
|
|
/// Read number of supported links
|
|
///
|
|
Status = GetNumberOfSupportedSndwLinks (DspBar, NumberOfSupportedSndwLinks);
|
|
DEBUG ((DEBUG_INFO, "Number of Supported Sndw Links %d\n", *NumberOfSupportedSndwLinks));
|
|
|
|
for (SndwLinkIndex = 0; SndwLinkIndex < *NumberOfSupportedSndwLinks; SndwLinkIndex++) {
|
|
Status = GetSndwLinkOutOfReset (DspBar, SndwLinkIndex);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "%a () - End. Status = %r\n", __FUNCTION__, Status));
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
SetSndwShimRegisters (DspBar, SndwLinkIndex);
|
|
|
|
///
|
|
/// Read address of SndwX controller
|
|
///
|
|
GetLinkControllerMmioAddress (DspBar, SndwLinkIndex, &SndwControllerMmioOffset);
|
|
DEBUG ((DEBUG_INFO, "Sndw%d: Controller mmio address: 0x%X.\n", SndwLinkIndex+1, DspBar + SndwControllerMmioOffset));
|
|
|
|
///
|
|
/// Check access to SndwX controller
|
|
///
|
|
if (SndwIoAccessReady (DspBar + SndwControllerMmioOffset) == FALSE) {
|
|
DEBUG ((DEBUG_INFO, "No access to Sndw%d Controller registers! Aborting", SndwLinkIndex+1));
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
///
|
|
/// Initialize SndwX controller
|
|
///
|
|
Status = SndwControllerInit (DspBar + SndwControllerMmioOffset);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "%a () - End. Status = %r\n", __FUNCTION__, Status));
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Function enumerates connected Soundwire codecs
|
|
|
|
@param[in] SndwAccessContext Pointer to Sndw access context
|
|
@param[in] NumberOfSupportedSndwLinks Number of supported Sndw links
|
|
@param[in] DspBar DSP base address
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_DEVICE_ERROR
|
|
**/
|
|
EFI_STATUS
|
|
EnumerateSndwCodecs (
|
|
IN SNDW_ACCESS_CONTEXT *SndwAccessContext,
|
|
IN UINTN NumberOfSupportedSndwLinks,
|
|
IN UINT64 DspBar
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CODEC_LIST_ENTRY *CodecListEntry;
|
|
SNDW_CODEC_ID CodecId;
|
|
SNDW_COMMAND RxCommand;
|
|
LIST_ENTRY *CodecListHead;
|
|
UINT64 SndwControllerMmioOffset;
|
|
UINT32 SndwLinkIndex;
|
|
UINT32 PeripheralIndex;
|
|
UINT32 PeripheralsStatus;
|
|
|
|
CodecListHead = NULL;
|
|
|
|
///
|
|
/// Controller after initialization sending ping message automatically
|
|
///
|
|
MicroSecondDelay (SNDW_WAIT_PERIOD * 100);
|
|
|
|
for (SndwLinkIndex = 0; SndwLinkIndex < NumberOfSupportedSndwLinks; SndwLinkIndex++) {
|
|
//
|
|
// Read address of SndwX controller
|
|
//
|
|
Status = GetLinkControllerMmioAddress (DspBar, SndwLinkIndex, &SndwControllerMmioOffset);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
DEBUG ((DEBUG_INFO, "Sndw%d controller mmio address: 0x%X.\n", SndwLinkIndex+1, DspBar + SndwControllerMmioOffset));
|
|
|
|
///
|
|
/// Now we are ready to send data to codecs
|
|
///
|
|
for (PeripheralIndex = 0; PeripheralIndex < SNDW_MAX_PERIPHERAL_NUMBER; PeripheralIndex++) {
|
|
///
|
|
/// Codecs enumeration process, check peripherals status
|
|
///
|
|
Status = SndwReadCodecsStatus (DspBar + SndwControllerMmioOffset, &PeripheralsStatus);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "Sndw%d peripheral status: 0x%X.\n", SndwLinkIndex+1, PeripheralsStatus));
|
|
|
|
if ((PeripheralsStatus & B_SNDW_MEM_PERIPHERALSTAT_STATUS (PeripheralIndex)) == SndwPeripheralAttachedOk) {
|
|
DEBUG ((DEBUG_INFO, "Peripheral number: %d attached correctly.\n", PeripheralIndex));
|
|
|
|
///
|
|
/// Waiting a few ms after sending init msg
|
|
///
|
|
MicroSecondDelay (SNDW_WAIT_PERIOD * 100);
|
|
|
|
///
|
|
/// Read if Codec is connected to PeripheralIndex
|
|
///
|
|
Status = ReadPeripheralId (DspBar + SndwControllerMmioOffset, PeripheralIndex, &CodecId);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
///
|
|
/// Waiting a few ms after sending init msg
|
|
///
|
|
MicroSecondDelay (SNDW_WAIT_PERIOD * 100);
|
|
|
|
///
|
|
/// Send Init commands to codecs
|
|
///
|
|
MipiSndwPeripheralInitCmds.TxWrite.DeviceAddress = PeripheralIndex;
|
|
Status = SendwAck (DspBar + SndwControllerMmioOffset, MipiSndwPeripheralInitCmds, &RxCommand);
|
|
if (EFI_ERROR (Status) || (RxCommand.Rx.Ack == 0)) {
|
|
DEBUG ((DEBUG_INFO, "Sndw%d controller - Peripheral number: %d initialization failed.\n", SndwLinkIndex+1, PeripheralIndex));
|
|
continue;
|
|
}
|
|
|
|
CodecListEntry = AllocatePool (sizeof (CODEC_LIST_ENTRY));
|
|
|
|
if (CodecListEntry == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
CodecListEntry->CodecInfo.SndwLinkIndex = SndwLinkIndex;
|
|
CodecListEntry->PeripheralIndex = PeripheralIndex;
|
|
CodecListEntry->SndwControllerMmioOffset = SndwControllerMmioOffset;
|
|
|
|
CopyMem (CodecListEntry->CodecInfo.CodecId.Data, CodecId.Data, sizeof (SNDW_CODEC_ID));
|
|
|
|
PrintCodecInfo (&(CodecListEntry->CodecInfo));
|
|
|
|
if (CodecListHead == NULL) {
|
|
SndwAccessContext->CodecListHead = CodecListEntry;
|
|
CodecListHead = &(CodecListEntry->ListEntry);
|
|
InitializeListHead (CodecListHead);
|
|
}
|
|
else {
|
|
InsertTailList (CodecListHead, &(CodecListEntry->ListEntry));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Function enables Soundwire interface and enumerates attached codecs
|
|
|
|
@param[in] This Pointer to Sndw Access Protocol
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_DEVICE_ERROR
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DxeSndwAccessEnable (
|
|
IN CONST SNDW_ACCESS_PROTOCOL *This
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
SNDW_ACCESS_CONTEXT *SndwAccessContext;
|
|
UINTN NumberOfSupportedSndwLinks;
|
|
UINT64 HdaBar;
|
|
UINT64 DspBar;
|
|
BOOLEAN IsTemporaryBar;
|
|
|
|
DEBUG ((DEBUG_INFO, "%a () - Start.\n", __FUNCTION__));
|
|
|
|
if (This == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Sndw Access protocol has not been passed, aborting.\n"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
SndwAccessContext = SNDW_ACCESS_CONTEXT_FROM_SNDW_ACCESS_PROTOCOL (This);
|
|
SndwAccessContext->EnableCounter += 1;
|
|
if (SndwAccessContext->EnableCounter != 1) {
|
|
DEBUG ((DEBUG_ERROR, "SndwAccess already enabled.\n"));
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EnableHdaDspMmioAccess (&HdaBar, &DspBar, &IsTemporaryBar);
|
|
|
|
Status = InitializeSndwControllers (&NumberOfSupportedSndwLinks, HdaBar, DspBar);
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
Status = EnumerateSndwCodecs (SndwAccessContext, NumberOfSupportedSndwLinks, DspBar);
|
|
}
|
|
|
|
DisableHdaDspMmioAccess (IsTemporaryBar);
|
|
|
|
DEBUG ((DEBUG_INFO, "%a () - End. Status = %r.\n", __FUNCTION__, Status));
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Function return first codec saved in codecs list.
|
|
If it does not exist, function sets *CodecInfo to NULL.
|
|
|
|
@param[in] This Pointer to Sndw Access Protocol
|
|
@param[out] SndwCodecInfo Pointer to pointer to Sndw codec information structure.
|
|
The caller is responsible for freeing the memory.
|
|
|
|
@retval EFI_SUCCESS Codec found
|
|
@retval EFI_NOT_FOUND Codec not found
|
|
@retval EFI_OUT_OF_RESOURCES Memory allocation for codec info failed
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DxeSndwGetFirstCodec (
|
|
IN CONST SNDW_ACCESS_PROTOCOL *This,
|
|
OUT SNDW_CODEC_INFO **SndwCodecInfo
|
|
)
|
|
{
|
|
SNDW_ACCESS_CONTEXT *SndwAccessContext;
|
|
CODEC_LIST_ENTRY *CurrentCodecListEntry;
|
|
|
|
if (This == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Sndw Access protocol has not been passed, aborting.\n"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
SndwAccessContext = SNDW_ACCESS_CONTEXT_FROM_SNDW_ACCESS_PROTOCOL (This);
|
|
CurrentCodecListEntry = SndwAccessContext->CodecListHead;
|
|
|
|
if (CurrentCodecListEntry != NULL) {
|
|
*SndwCodecInfo = AllocatePool (sizeof (SNDW_CODEC_INFO));
|
|
if (*SndwCodecInfo == NULL) {
|
|
DEBUG ((DEBUG_INFO, "Couldn't allocate the memory for Sndw Codec Info!\n"));
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
(*SndwCodecInfo)->SndwLinkIndex = CurrentCodecListEntry->CodecInfo.SndwLinkIndex;
|
|
CopyMem (&((*SndwCodecInfo)->CodecId.Data), &(CurrentCodecListEntry->CodecInfo.CodecId.Data), sizeof (SNDW_CODEC_ID));
|
|
}
|
|
else {
|
|
*SndwCodecInfo = NULL;
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Function retrieves the next codec saved in codecs list that follows the given one.
|
|
If it does not exist, function sets *NextCodecInfo to NULL.
|
|
|
|
@param[in] This Pointer to Sndw Access Protocol
|
|
@param[in] SndwCodecInfo Pointer to Sndw codec information structure.
|
|
@param[out] NextCodecInfo Pointer to pointer to Sndw codec information structure.
|
|
The caller is responsible for freeing the memory.
|
|
|
|
@retval EFI_SUCCESS Codec found
|
|
@retval EFI_NOT_FOUND Codec not found
|
|
@retval EFI_OUT_OF_RESOURCES Memory allocation for codec info failed
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DxeSndwGetNextCodec (
|
|
IN CONST SNDW_ACCESS_PROTOCOL *This,
|
|
IN SNDW_CODEC_INFO *SndwCodecInfo,
|
|
OUT SNDW_CODEC_INFO **NextSndwCodecInfo
|
|
)
|
|
{
|
|
SNDW_ACCESS_CONTEXT *SndwAccessContext;
|
|
CODEC_LIST_ENTRY *CurrentCodecListEntry;
|
|
LIST_ENTRY *ListHead;
|
|
LIST_ENTRY *CurrentListEntry;
|
|
|
|
if (This == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Sndw Access protocol has not been passed, aborting.\n"));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
SndwAccessContext = SNDW_ACCESS_CONTEXT_FROM_SNDW_ACCESS_PROTOCOL (This);
|
|
ListHead = &(SndwAccessContext->CodecListHead->ListEntry);
|
|
CurrentListEntry = ListHead;
|
|
|
|
while (TRUE) {
|
|
CurrentCodecListEntry = CODEC_LIST_ENTRY_FROM_LIST_ENTRY (CurrentListEntry);
|
|
|
|
if ((CurrentCodecListEntry->CodecInfo.SndwLinkIndex == SndwCodecInfo->SndwLinkIndex) &&
|
|
(CompareMem (CurrentCodecListEntry->CodecInfo.CodecId.Data, SndwCodecInfo->CodecId.Data, sizeof (SNDW_CODEC_ID)) == 0)) {
|
|
CurrentListEntry = GetNextNode (ListHead, CurrentListEntry);
|
|
if (CurrentListEntry == ListHead) {
|
|
*NextSndwCodecInfo = NULL;
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
CurrentCodecListEntry = CODEC_LIST_ENTRY_FROM_LIST_ENTRY (CurrentListEntry);
|
|
|
|
*NextSndwCodecInfo = AllocatePool (sizeof (SNDW_CODEC_INFO));
|
|
if (*NextSndwCodecInfo == NULL) {
|
|
DEBUG ((DEBUG_INFO, "Couldn't allocate the memory for Sndw Codec Info!\n"));
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
(*NextSndwCodecInfo)->SndwLinkIndex = CurrentCodecListEntry->CodecInfo.SndwLinkIndex;
|
|
CopyMem (&((*NextSndwCodecInfo)->CodecId.Data), &(CurrentCodecListEntry->CodecInfo.CodecId.Data), sizeof (SNDW_CODEC_ID));
|
|
break;
|
|
}
|
|
|
|
CurrentListEntry = GetNextNode (ListHead, CurrentListEntry);
|
|
if (CurrentListEntry == ListHead) {
|
|
*NextSndwCodecInfo = NULL;
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
This function is the entry point of this DXE Sndw Init Driver.
|
|
|
|
@param ImageHandle The firmware allocated handle for the EFI image.
|
|
@param SystemTable A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_DEVICE_ERROR Not able to enable DSP memory space.
|
|
@retval EFI_UNSUPPORTED Requested Sndw link not exists.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DxeSndwInitEntryPoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
SNDW_ACCESS_CONTEXT *SndwAccessContext;
|
|
EFI_HANDLE SndwAccessHandle;
|
|
|
|
DEBUG ((DEBUG_INFO, "%a () Start.\n", __FUNCTION__));
|
|
|
|
SndwAccessHandle = NULL;
|
|
SndwAccessContext = AllocateZeroPool (sizeof (SNDW_ACCESS_CONTEXT));
|
|
if (NULL == SndwAccessContext) {
|
|
DEBUG ((DEBUG_INFO, "%a () - End. Memory pool allocation error.\n", __FUNCTION__));
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
SndwAccessContext->Signature = SNDW_ACCESS_SIGNATURE;
|
|
SndwAccessContext->SndwAccessProtocol.Enable = DxeSndwAccessEnable;
|
|
SndwAccessContext->SndwAccessProtocol.Disable = DxeSndwAccessDisable;
|
|
SndwAccessContext->SndwAccessProtocol.Send = DxeSndwSend;
|
|
SndwAccessContext->SndwAccessProtocol.Receive = DxeSndwReceive;
|
|
SndwAccessContext->SndwAccessProtocol.SendWithAck = DxeSndwSendWithAck;
|
|
SndwAccessContext->SndwAccessProtocol.GetFirstCodec = DxeSndwGetFirstCodec;
|
|
SndwAccessContext->SndwAccessProtocol.GetNextCodec = DxeSndwGetNextCodec;
|
|
SndwAccessContext->CodecListHead = NULL;
|
|
SndwAccessContext->EnableCounter = 0;
|
|
|
|
//
|
|
// Install on a new handle
|
|
//
|
|
Status = gBS->InstallProtocolInterface (
|
|
&SndwAccessHandle,
|
|
&gSndwAccessProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
&SndwAccessContext->SndwAccessProtocol
|
|
);
|
|
DEBUG ((DEBUG_INFO, "Sndw access Protocol Installattion Status = %r\n", Status));
|
|
if (EFI_ERROR (Status)) {
|
|
FreePool (SndwAccessContext);
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "%a () - End. Status = %r.\n", __FUNCTION__, Status));
|
|
return Status;
|
|
} |