blob: 3fe4647aabc913e3cd139ac3e79a4609552f5298 [file] [log] [blame]
/**
* @file
*
* Config Southbridge HD Audio Controller
*
*
*
* @xrefitem bom "File Content Label" "Release Content"
* @e project: CIMx-SB
* @e sub-project:
* @e \$Revision:$ @e \$Date:$
*
*/
/*;********************************************************************************
;
; Copyright (c) 2011, Advanced Micro Devices, Inc.
; All rights reserved.
;
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions are met:
; * Redistributions of source code must retain the above copyright
; notice, this list of conditions and the following disclaimer.
; * Redistributions in binary form must reproduce the above copyright
; notice, this list of conditions and the following disclaimer in the
; documentation and/or other materials provided with the distribution.
; * Neither the name of Advanced Micro Devices, Inc. nor the names of
; its contributors may be used to endorse or promote products derived
; from this software without specific prior written permission.
;
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
; DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;
;*********************************************************************************/
#include "SbPlatform.h"
#include "cbtypes.h"
#include "AmdSbLib.h"
//
// Declaration of local functions
//
VOID configureAzaliaPinCmd (IN AMDSBCFG* pConfig, IN UINT32 ddBAR0, IN UINT8 dbChannelNum);
VOID configureAzaliaSetConfigD4Dword (IN CODECENTRY* tempAzaliaCodecEntryPtr, IN UINT32 ddChannelNum, IN UINT32 ddBAR0);
/**
* Pin Config for ALC880, ALC882 and ALC883.
*
*
*
*/
CODECENTRY AzaliaCodecAlc882Table[] =
{
{0x14, 0x01014010},
{0x15, 0x01011012},
{0x16, 0x01016011},
{0x17, 0x01012014},
{0x18, 0x01A19030},
{0x19, 0x411111F0},
{0x1a, 0x01813080},
{0x1b, 0x411111F0},
{0x1C, 0x411111F0},
{0x1d, 0x411111F0},
{0x1e, 0x01441150},
{0x1f, 0x01C46160},
{0xff, 0xffffffff}
};
/**
* Pin Config for ALC0262.
*
*
*
*/
CODECENTRY AzaliaCodecAlc262Table[] =
{
{0x14, 0x01014010},
{0x15, 0x411111F0},
{0x16, 0x411111F0},
{0x18, 0x01A19830},
{0x19, 0x02A19C40},
{0x1a, 0x01813031},
{0x1b, 0x02014C20},
{0x1c, 0x411111F0},
{0x1d, 0x411111F0},
{0x1e, 0x0144111E},
{0x1f, 0x01C46150},
{0xff, 0xffffffff}
};
/**
* Pin Config for ALC0269.
*
*
*
*/
CODECENTRY AzaliaCodecAlc269Table[] =
{
{0x12, 0x99A308F0},
{0x14, 0x99130010},
{0x15, 0x0121101F},
{0x16, 0x99036120},
{0x18, 0x01A19850},
{0x19, 0x99A309F0},
{0x1a, 0x01813051},
{0x1b, 0x0181405F},
{0x1d, 0x40134601},
{0x1e, 0x01442130},
{0x11, 0x99430140},
{0x20, 0x0030FFFF},
{0xff, 0xffffffff}
};
/**
* Pin Config for ALC0861.
*
*
*
*/
CODECENTRY AzaliaCodecAlc861Table[] =
{
{0x01, 0x8086C601},
{0x0B, 0x01014110},
{0x0C, 0x01813140},
{0x0D, 0x01A19941},
{0x0E, 0x411111F0},
{0x0F, 0x02214420},
{0x10, 0x02A1994E},
{0x11, 0x99330142},
{0x12, 0x01451130},
{0x1F, 0x411111F0},
{0x20, 0x411111F0},
{0x23, 0x411111F0},
{0xff, 0xffffffff}
};
/**
* Pin Config for ALC0889.
*
*
*
*/
CODECENTRY AzaliaCodecAlc889Table[] =
{
{0x11, 0x411111F0},
{0x14, 0x01014010},
{0x15, 0x01011012},
{0x16, 0x01016011},
{0x17, 0x01013014},
{0x18, 0x01A19030},
{0x19, 0x411111F0},
{0x1a, 0x411111F0},
{0x1b, 0x411111F0},
{0x1C, 0x411111F0},
{0x1d, 0x411111F0},
{0x1e, 0x01442150},
{0x1f, 0x01C42160},
{0xff, 0xffffffff}
};
/**
* Pin Config for ADI1984.
*
*
*
*/
CODECENTRY AzaliaCodecAd1984Table[] =
{
{0x11, 0x0221401F},
{0x12, 0x90170110},
{0x13, 0x511301F0},
{0x14, 0x02A15020},
{0x15, 0x50A301F0},
{0x16, 0x593301F0},
{0x17, 0x55A601F0},
{0x18, 0x55A601F0},
{0x1A, 0x91F311F0},
{0x1B, 0x014511A0},
{0x1C, 0x599301F0},
{0xff, 0xffffffff}
};
/**
* FrontPanel Config table list
*
*
*
*/
CODECENTRY FrontPanelAzaliaCodecTableList[] =
{
{0x19, 0x02A19040},
{0x1b, 0x02214020},
{0xff, 0xffffffff}
};
/**
* Current HD Audio support codec list
*
*
*
*/
CODECTBLLIST azaliaCodecTableList[] =
{
{0x010ec0880, &AzaliaCodecAlc882Table[0]},
{0x010ec0882, &AzaliaCodecAlc882Table[0]},
{0x010ec0883, &AzaliaCodecAlc882Table[0]},
{0x010ec0885, &AzaliaCodecAlc882Table[0]},
{0x010ec0889, &AzaliaCodecAlc889Table[0]},
{0x010ec0262, &AzaliaCodecAlc262Table[0]},
{0x010ec0269, &AzaliaCodecAlc269Table[0]},
{0x010ec0861, &AzaliaCodecAlc861Table[0]},
{0x011d41984, &AzaliaCodecAd1984Table[0]},
{ (UINT32) 0x0FFFFFFFF, (CODECENTRY*) (UINTN)0x0FFFFFFFF}
};
/**
* azaliaInitBeforePciEnum - Config HD Audio Before PCI emulation
*
*
*
* @param[in] pConfig Southbridge configuration structure pointer.
*
*/
VOID
azaliaInitBeforePciEnum (
IN AMDSBCFG* pConfig
)
{
if ( pConfig->AzaliaController == 1 ) {
RWMEM (ACPI_MMIO_BASE + PMIO_BASE + SB_PMIOA_REGEB, AccWidthUint8, ~BIT0, 0);
} else {
RWMEM (ACPI_MMIO_BASE + PMIO_BASE + SB_PMIOA_REGEB, AccWidthUint8, ~BIT0, BIT0);
if ( pConfig->BuildParameters.HdAudioMsi) {
RWPCI ((AZALIA_BUS_DEV_FUN << 16) + SB_AZ_REG44, AccWidthUint32 | S3_SAVE, ~BIT8, BIT8);
RWPCI ((AZALIA_BUS_DEV_FUN << 16) + SB_AZ_REG60, AccWidthUint32 | S3_SAVE, ~BIT16, BIT16);
}
}
}
/**
* azaliaInitAfterPciEnum - Config HD Audio after PCI emulation
*
*
*
* @param[in] pConfig Southbridge configuration structure pointer.
*
*/
VOID
azaliaInitAfterPciEnum (
IN AMDSBCFG* pConfig
)
{
UINT8 Data;
UINT8 i;
UINT8 dbEnableAzalia;
UINT8 dbPinRouting;
UINT8 dbChannelNum;
UINT8 dbTempVariable;
UINT16 dwTempVariable;
UINT32 ddBAR0;
UINT32 ddTempVariable;
dbEnableAzalia = 0;
dbChannelNum = 0;
dbTempVariable = 0;
dwTempVariable = 0;
ddBAR0 = 0;
ddTempVariable = 0;
if ( pConfig->AzaliaController == 1 ) {
return;
}
if ( pConfig->AzaliaController != 1 ) {
RWPCI ((AZALIA_BUS_DEV_FUN << 16) + SB_AZ_REG04, AccWidthUint8 | S3_SAVE, ~BIT1, BIT1);
if ( pConfig->BuildParameters.AzaliaSsid != NULL ) {
RWPCI ((AZALIA_BUS_DEV_FUN << 16) + SB_AZ_REG2C, AccWidthUint32 | S3_SAVE, 0x00, pConfig->BuildParameters.AzaliaSsid);
}
ReadPCI ((AZALIA_BUS_DEV_FUN << 16) + SB_AZ_REG10, AccWidthUint32, &ddBAR0);
if ( ddBAR0 != 0 ) {
if ( ddBAR0 != 0xFFFFFFFF ) {
ddBAR0 &= ~(0x03FFF);
dbEnableAzalia = 1;
TRACE ((DMSG_SB_TRACE, "CIMxSB - Enabling Azalia controller (BAR setup is ok) \n"));
}
}
}
if ( dbEnableAzalia ) {
pConfig->AZALIACONFIG.AzaliaConfig.AzaliaSdin0 = 0x03 & (pConfig->AZALIACONFIG.AzaliaSdinPin >> 0);
pConfig->AZALIACONFIG.AzaliaConfig.AzaliaSdin1 = 0x03 & (pConfig->AZALIACONFIG.AzaliaSdinPin >> 2);
pConfig->AZALIACONFIG.AzaliaConfig.AzaliaSdin2 = 0x03 & (pConfig->AZALIACONFIG.AzaliaSdinPin >> 4);
pConfig->AZALIACONFIG.AzaliaConfig.AzaliaSdin3 = 0x03 & (pConfig->AZALIACONFIG.AzaliaSdinPin >> 6);
// Get SDIN Configuration
if ( pConfig->AZALIACONFIG.AzaliaConfig.AzaliaSdin0 == 2 ) {
RWMEM (ACPI_MMIO_BASE + GPIO_BASE + SB_GPIO_REG167, AccWidthUint8, 0, 0x3E);
RWMEM (ACPI_MMIO_BASE + IOMUX_BASE + SB_GPIO_REG167, AccWidthUint8, 0, 0x00);
} else {
RWMEM (ACPI_MMIO_BASE + GPIO_BASE + SB_GPIO_REG167, AccWidthUint8, 0, 0x0);
RWMEM (ACPI_MMIO_BASE + IOMUX_BASE + SB_GPIO_REG167, AccWidthUint8, 0, 0x01);
}
if ( pConfig->AZALIACONFIG.AzaliaConfig.AzaliaSdin1 == 2 ) {
RWMEM (ACPI_MMIO_BASE + GPIO_BASE + SB_GPIO_REG168, AccWidthUint8, 0, 0x3E);
RWMEM (ACPI_MMIO_BASE + IOMUX_BASE + SB_GPIO_REG168, AccWidthUint8, 0, 0x00);
} else {
RWMEM (ACPI_MMIO_BASE + GPIO_BASE + SB_GPIO_REG168, AccWidthUint8, 0, 0x0);
RWMEM (ACPI_MMIO_BASE + IOMUX_BASE + SB_GPIO_REG168, AccWidthUint8, 0, 0x01);
}
if ( pConfig->AZALIACONFIG.AzaliaConfig.AzaliaSdin2 == 2 ) {
RWMEM (ACPI_MMIO_BASE + GPIO_BASE + SB_GPIO_REG169, AccWidthUint8, 0, 0x3E);
RWMEM (ACPI_MMIO_BASE + IOMUX_BASE + SB_GPIO_REG169, AccWidthUint8, 0, 0x00);
} else {
RWMEM (ACPI_MMIO_BASE + GPIO_BASE + SB_GPIO_REG169, AccWidthUint8, 0, 0x0);
RWMEM (ACPI_MMIO_BASE + IOMUX_BASE + SB_GPIO_REG169, AccWidthUint8, 0, 0x01);
}
if ( pConfig->AZALIACONFIG.AzaliaConfig.AzaliaSdin3 == 2 ) {
RWMEM (ACPI_MMIO_BASE + GPIO_BASE + SB_GPIO_REG170, AccWidthUint8, 0, 0x3E);
RWMEM (ACPI_MMIO_BASE + IOMUX_BASE + SB_GPIO_REG170, AccWidthUint8, 0, 0x00);
} else {
RWMEM (ACPI_MMIO_BASE + GPIO_BASE + SB_GPIO_REG170, AccWidthUint8, 0, 0x0);
RWMEM (ACPI_MMIO_BASE + IOMUX_BASE + SB_GPIO_REG170, AccWidthUint8, 0, 0x01);
}
// INT#A Azalia resource
Data = 0x93; // Azalia APIC index
WriteIO (SB_IOMAP_REGC00, AccWidthUint8, &Data);
Data = 0x10; // IRQ16 (INTA#)
WriteIO (SB_IOMAP_REGC01, AccWidthUint8, &Data);
i = 11;
do {
ReadMEM ( ddBAR0 + SB_AZ_BAR_REG08, AccWidthUint8 | S3_SAVE, &dbTempVariable);
dbTempVariable |= BIT0;
WriteMEM (ddBAR0 + SB_AZ_BAR_REG08, AccWidthUint8 | S3_SAVE, &dbTempVariable);
SbStall (1000);
ReadMEM (ddBAR0 + SB_AZ_BAR_REG08, AccWidthUint8 | S3_SAVE, &dbTempVariable);
i--;
} while ((! (dbTempVariable & BIT0)) && (i > 0) );
if ( i == 0 ) {
TRACE ((DMSG_SB_TRACE, "CIMxSB - Problem in resetting Azalia controller\n"));
return;
}
SbStall (1000);
ReadMEM ( ddBAR0 + SB_AZ_BAR_REG0E, AccWidthUint16, &dwTempVariable);
if ( dwTempVariable & 0x0F ) {
TRACE ((DMSG_SB_TRACE, "CIMxSB - At least One Azalia CODEC found \n"));
//atleast one azalia codec found
dbPinRouting = pConfig->AZALIACONFIG.AzaliaSdinPin;
do {
if ( ( ! (dbPinRouting & BIT0) ) && (dbPinRouting & BIT1) ) {
configureAzaliaPinCmd (pConfig, ddBAR0, dbChannelNum);
}
dbPinRouting >>= 2;
dbChannelNum++;
} while ( dbChannelNum != 4 );
} else {
TRACE ((DMSG_SB_TRACE, "CIMxSB - Azalia CODEC NOT found \n"));
//No Azalia codec found
if ( pConfig->AzaliaController != 2 ) {
dbEnableAzalia = 0; //set flag to disable Azalia
}
}
}
if ( dbEnableAzalia ) {
//redo clear reset
do {
dwTempVariable = 0;
WriteMEM ( ddBAR0 + SB_AZ_BAR_REG0C, AccWidthUint16 | S3_SAVE, &dwTempVariable);
ReadMEM (ddBAR0 + SB_AZ_BAR_REG08, AccWidthUint8 | S3_SAVE, &dbTempVariable);
dbTempVariable &= ~(BIT0);
WriteMEM (ddBAR0 + SB_AZ_BAR_REG08, AccWidthUint8 | S3_SAVE, &dbTempVariable);
ReadMEM (ddBAR0 + SB_AZ_BAR_REG08, AccWidthUint8 | S3_SAVE, &dbTempVariable);
} while ( dbTempVariable & BIT0 );
if ( pConfig->AzaliaSnoop == 1 ) {
RWPCI ((AZALIA_BUS_DEV_FUN << 16) + SB_AZ_REG42, AccWidthUint8 | S3_SAVE, 0xFF, BIT1 + BIT0);
}
} else {
//disable Azalia controller
RWPCI ((AZALIA_BUS_DEV_FUN << 16) + SB_AZ_REG04, AccWidthUint16 | S3_SAVE, 0, 0);
RWMEM (ACPI_MMIO_BASE + PMIO_BASE + SB_PMIOA_REGEB, AccWidthUint8, ~BIT0, 0);
RWMEM (ACPI_MMIO_BASE + PMIO_BASE + SB_PMIOA_REGEB, AccWidthUint8, ~BIT0, 0);
}
}
/**
* configureAzaliaPinCmd - Configuration HD Audio PIN Command
*
*
* @param[in] pConfig Southbridge configuration structure pointer.
* @param[in] ddBAR0 HD Audio BAR0 base address.
* @param[in] dbChannelNum Channel Number.
*
*/
VOID
configureAzaliaPinCmd (
IN AMDSBCFG* pConfig,
IN UINT32 ddBAR0,
IN UINT8 dbChannelNum
)
{
UINT32 ddTempVariable;
UINT32 ddChannelNum;
CODECTBLLIST* ptempAzaliaOemCodecTablePtr;
CODECENTRY* tempAzaliaCodecEntryPtr;
if ( (pConfig->AzaliaPinCfg) != 1 ) {
return;
}
ddChannelNum = dbChannelNum << 28;
ddTempVariable = 0xF0000;
ddTempVariable |= ddChannelNum;
WriteMEM (ddBAR0 + SB_AZ_BAR_REG60, AccWidthUint32 | S3_SAVE, &ddTempVariable);
SbStall (600);
ReadMEM (ddBAR0 + SB_AZ_BAR_REG64, AccWidthUint32 | S3_SAVE, &ddTempVariable);
if ( ((pConfig->AZOEMTBL.pAzaliaOemCodecTablePtr) == NULL) || ((pConfig->AZOEMTBL.pAzaliaOemCodecTablePtr) == ((CODECTBLLIST*) (UINTN)0xFFFFFFFF))) {
ptempAzaliaOemCodecTablePtr = (CODECTBLLIST*) FIXUP_PTR (&azaliaCodecTableList[0]);
} else {
ptempAzaliaOemCodecTablePtr = (CODECTBLLIST*) pConfig->AZOEMTBL.pAzaliaOemCodecTablePtr;
}
TRACE ((DMSG_SB_TRACE, "CIMxSB - Azalia CODEC table pointer is %X \n", ptempAzaliaOemCodecTablePtr));
while ( ptempAzaliaOemCodecTablePtr->CodecID != 0xFFFFFFFF ) {
if ( ptempAzaliaOemCodecTablePtr->CodecID == ddTempVariable ) {
break;
} else {
++ptempAzaliaOemCodecTablePtr;
}
}
if ( ptempAzaliaOemCodecTablePtr->CodecID != 0xFFFFFFFF ) {
TRACE ((DMSG_SB_TRACE, "CIMxSB - Matching CODEC ID found \n"));
tempAzaliaCodecEntryPtr = (CODECENTRY*) ptempAzaliaOemCodecTablePtr->CodecTablePtr;
TRACE ((DMSG_SB_TRACE, "CIMxSB - Matching Azalia CODEC table pointer is %X \n", tempAzaliaCodecEntryPtr));
if ( ((pConfig->AZOEMTBL.pAzaliaOemCodecTablePtr) == NULL) || ((pConfig->AZOEMTBL.pAzaliaOemCodecTablePtr) == ((CODECTBLLIST*) (UINTN)0xFFFFFFFF)) ) {
tempAzaliaCodecEntryPtr = (CODECENTRY*) FIXUP_PTR (tempAzaliaCodecEntryPtr);
}
configureAzaliaSetConfigD4Dword (tempAzaliaCodecEntryPtr, ddChannelNum, ddBAR0);
if ( pConfig->AzaliaFrontPanel != 1 ) {
if ( (pConfig->AzaliaFrontPanel == 2) || (pConfig->FrontPanelDetected == 1) ) {
if ( ((pConfig->AZOEMFPTBL.pAzaliaOemFpCodecTablePtr) == NULL) || ((pConfig->AZOEMFPTBL.pAzaliaOemFpCodecTablePtr) == (VOID*) (UINTN)0xFFFFFFFF) ) {
tempAzaliaCodecEntryPtr = (CODECENTRY*) FIXUP_PTR (&FrontPanelAzaliaCodecTableList[0]);
} else {
tempAzaliaCodecEntryPtr = (CODECENTRY*) pConfig->AZOEMFPTBL.pAzaliaOemFpCodecTablePtr;
}
configureAzaliaSetConfigD4Dword (tempAzaliaCodecEntryPtr, ddChannelNum, ddBAR0);
}
}
}
}
/**
* configureAzaliaSetConfigD4Dword - Configuration HD Audio Codec table
*
*
* @param[in] tempAzaliaCodecEntryPtr HD Audio Codec table structure pointer.
* @param[in] ddChannelNum HD Audio Channel Number.
* @param[in] ddBAR0 HD Audio BAR0 base address.
*
*/
VOID
configureAzaliaSetConfigD4Dword (
IN CODECENTRY* tempAzaliaCodecEntryPtr,
IN UINT32 ddChannelNum,
IN UINT32 ddBAR0
)
{
UINT8 dbtemp1;
UINT8 dbtemp2;
UINT8 i;
UINT32 ddtemp;
UINT32 ddtemp2;
ddtemp = 0;
ddtemp2 = 0;
while ( (tempAzaliaCodecEntryPtr->Nid) != 0xFF ) {
dbtemp1 = 0x20;
if ( (tempAzaliaCodecEntryPtr->Nid) == 0x1 ) {
dbtemp1 = 0x24;
}
ddtemp = tempAzaliaCodecEntryPtr->Nid;
ddtemp &= 0xff;
ddtemp <<= 20;
ddtemp |= ddChannelNum;
ddtemp |= (0x700 << 8);
for ( i = 4; i > 0; i-- ) {
do {
ReadMEM (ddBAR0 + SB_AZ_BAR_REG68, AccWidthUint32, &ddtemp2);
} while ( ddtemp2 & BIT0 );
dbtemp2 = (UINT8) (( (tempAzaliaCodecEntryPtr->Byte40) >> ((4 - i) * 8 ) ) & 0xff);
ddtemp = (ddtemp & 0xFFFF0000) + ((dbtemp1 - i) << 8) + dbtemp2;
WriteMEM (ddBAR0 + SB_AZ_BAR_REG60, AccWidthUint32 | S3_SAVE, &ddtemp);
SbStall (60);
}
++tempAzaliaCodecEntryPtr;
}
}