4 * Config Southbridge HD Audio Controller
\r
8 * @xrefitem bom "File Content Label" "Release Content"
\r
9 * @e project: CIMx-SB
\r
11 * @e \$Revision:$ @e \$Date:$
\r
16 *****************************************************************************
\r
18 * This file is part of the coreboot project.
\r
20 * Copyright (C) 2010 Advanced Micro Devices, Inc.
\r
22 * This program is free software; you can redistribute it and/or modify
\r
23 * it under the terms of the GNU General Public License as published by
\r
24 * the Free Software Foundation; version 2 of the License.
\r
26 * This program is distributed in the hope that it will be useful,
\r
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
29 * GNU General Public License for more details.
\r
31 * You should have received a copy of the GNU General Public License
\r
32 * along with this program; if not, write to the Free Software
\r
33 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
\r
34 * ***************************************************************************
\r
39 #include "SBPLATFORM.h"
\r
42 // Declaration of local functions
\r
45 VOID configureAzaliaPinCmd (IN AMDSBCFG* pConfig, IN UINT32 ddBAR0, IN UINT8 dbChannelNum);
\r
46 VOID configureAzaliaSetConfigD4Dword (IN CODECENTRY* tempAzaliaCodecEntryPtr, IN UINT32 ddChannelNum, IN UINT32 ddBAR0);
\r
49 * Pin Config for ALC880, ALC882 and ALC883.
\r
54 CODECENTRY AzaliaCodecAlc882Table[] =
\r
72 * Pin Config for ALC0262.
\r
77 CODECENTRY AzaliaCodecAlc262Table[] =
\r
94 * Pin Config for ALC0269.
\r
99 CODECENTRY AzaliaCodecAlc269Table[] =
\r
101 {0x12, 0x99A30960},
\r
102 {0x14, 0x99130110},
\r
103 {0x15, 0x0221401F},
\r
104 {0x16, 0x99130120},
\r
105 {0x18, 0x01A19850},
\r
106 {0x19, 0x02A15951},
\r
107 {0x1a, 0x01813052},
\r
108 {0x1b, 0x0181405F},
\r
109 {0x1d, 0x40134601},
\r
110 {0x1e, 0x01441130},
\r
111 {0x11, 0x18567140},
\r
112 {0x20, 0x0030FFFF},
\r
117 * Pin Config for ALC0861.
\r
122 CODECENTRY AzaliaCodecAlc861Table[] =
\r
124 {0x01, 0x8086C601},
\r
125 {0x0B, 0x01014110},
\r
126 {0x0C, 0x01813140},
\r
127 {0x0D, 0x01A19941},
\r
128 {0x0E, 0x411111F0},
\r
129 {0x0F, 0x02214420},
\r
130 {0x10, 0x02A1994E},
\r
131 {0x11, 0x99330142},
\r
132 {0x12, 0x01451130},
\r
133 {0x1F, 0x411111F0},
\r
134 {0x20, 0x411111F0},
\r
135 {0x23, 0x411111F0},
\r
140 * Pin Config for ALC0889.
\r
145 CODECENTRY AzaliaCodecAlc889Table[] =
\r
147 {0x11, 0x411111F0},
\r
148 {0x14, 0x01014010},
\r
149 {0x15, 0x01011012},
\r
150 {0x16, 0x01016011},
\r
151 {0x17, 0x01013014},
\r
152 {0x18, 0x01A19030},
\r
153 {0x19, 0x411111F0},
\r
154 {0x1a, 0x411111F0},
\r
155 {0x1b, 0x411111F0},
\r
156 {0x1C, 0x411111F0},
\r
157 {0x1d, 0x411111F0},
\r
158 {0x1e, 0x01442150},
\r
159 {0x1f, 0x01C42160},
\r
164 * Pin Config for ADI1984.
\r
169 CODECENTRY AzaliaCodecAd1984Table[] =
\r
171 {0x11, 0x0221401F},
\r
172 {0x12, 0x90170110},
\r
173 {0x13, 0x511301F0},
\r
174 {0x14, 0x02A15020},
\r
175 {0x15, 0x50A301F0},
\r
176 {0x16, 0x593301F0},
\r
177 {0x17, 0x55A601F0},
\r
178 {0x18, 0x55A601F0},
\r
179 {0x1A, 0x91F311F0},
\r
180 {0x1B, 0x014511A0},
\r
181 {0x1C, 0x599301F0},
\r
186 * FrontPanel Config table list
\r
191 CODECENTRY FrontPanelAzaliaCodecTableList[] =
\r
193 {0x19, 0x02A19040},
\r
194 {0x1b, 0x02214020},
\r
199 * Current HD Audio support codec list
\r
204 CODECTBLLIST azaliaCodecTableList[] =
\r
206 {0x010ec0880, &AzaliaCodecAlc882Table[0]},
\r
207 {0x010ec0882, &AzaliaCodecAlc882Table[0]},
\r
208 {0x010ec0883, &AzaliaCodecAlc882Table[0]},
\r
209 {0x010ec0885, &AzaliaCodecAlc882Table[0]},
\r
210 {0x010ec0889, &AzaliaCodecAlc889Table[0]},
\r
211 {0x010ec0262, &AzaliaCodecAlc262Table[0]},
\r
212 {0x010ec0269, &AzaliaCodecAlc269Table[0]},
\r
213 {0x010ec0861, &AzaliaCodecAlc861Table[0]},
\r
214 {0x011d41984, &AzaliaCodecAd1984Table[0]},
\r
215 { (UINT32) 0x0FFFFFFFF, (CODECENTRY*) (UINTN)0x0FFFFFFFF}
\r
219 * azaliaInitBeforePciEnum - Config HD Audio Before PCI emulation
\r
223 * @param[in] pConfig Southbridge configuration structure pointer.
\r
227 azaliaInitBeforePciEnum (
\r
228 IN AMDSBCFG* pConfig
\r
231 if ( pConfig->AzaliaController == 1 ) {
\r
232 RWMEM (ACPI_MMIO_BASE + PMIO_BASE + SB_PMIOA_REGEB, AccWidthUint8, ~BIT0, 0);
\r
234 RWMEM (ACPI_MMIO_BASE + PMIO_BASE + SB_PMIOA_REGEB, AccWidthUint8, ~BIT0, BIT0);
\r
235 if ( pConfig->BuildParameters.HdAudioMsi) {
\r
236 RWPCI ((AZALIA_BUS_DEV_FUN << 16) + SB_AZ_REG44, AccWidthUint32 | S3_SAVE, ~BIT8, BIT8);
\r
237 RWPCI ((AZALIA_BUS_DEV_FUN << 16) + SB_AZ_REG60, AccWidthUint32 | S3_SAVE, ~BIT16, BIT16);
\r
243 * azaliaInitAfterPciEnum - Config HD Audio after PCI emulation
\r
247 * @param[in] pConfig Southbridge configuration structure pointer.
\r
251 azaliaInitAfterPciEnum (
\r
252 IN AMDSBCFG* pConfig
\r
257 UINT8 dbEnableAzalia;
\r
258 UINT8 dbPinRouting;
\r
259 UINT8 dbChannelNum;
\r
260 UINT8 dbTempVariable;
\r
261 UINT16 dwTempVariable;
\r
263 UINT32 ddTempVariable;
\r
264 dbEnableAzalia = 0;
\r
266 dbTempVariable = 0;
\r
267 dwTempVariable = 0;
\r
269 ddTempVariable = 0;
\r
271 if ( pConfig->AzaliaController == 1 ) {
\r
275 if ( pConfig->AzaliaController != 1 ) {
\r
276 RWPCI ((AZALIA_BUS_DEV_FUN << 16) + SB_AZ_REG04, AccWidthUint8 | S3_SAVE, ~BIT1, BIT1);
\r
277 if ( pConfig->BuildParameters.AzaliaSsid != NULL ) {
\r
278 RWPCI ((AZALIA_BUS_DEV_FUN << 16) + SB_AZ_REG2C, AccWidthUint32 | S3_SAVE, 0x00, pConfig->BuildParameters.AzaliaSsid);
\r
280 ReadPCI ((AZALIA_BUS_DEV_FUN << 16) + SB_AZ_REG10, AccWidthUint32, &ddBAR0);
\r
281 if ( ddBAR0 != 0 ) {
\r
282 if ( ddBAR0 != 0xFFFFFFFF ) {
\r
283 ddBAR0 &= ~(0x03FFF);
\r
284 dbEnableAzalia = 1;
\r
289 if ( dbEnableAzalia ) {
\r
290 // Get SDIN Configuration
\r
291 if ( pConfig->AZALIACONFIG.AzaliaConfig.AzaliaSdin0 == 2 ) {
\r
292 RWMEM (ACPI_MMIO_BASE + GPIO_BASE + SB_GPIO_REG167, AccWidthUint8, 0, 0x3E);
\r
293 RWMEM (ACPI_MMIO_BASE + IOMUX_BASE + SB_GPIO_REG167, AccWidthUint8, 0, 0x00);
\r
295 RWMEM (ACPI_MMIO_BASE + GPIO_BASE + SB_GPIO_REG167, AccWidthUint8, 0, 0x0);
\r
296 RWMEM (ACPI_MMIO_BASE + IOMUX_BASE + SB_GPIO_REG167, AccWidthUint8, 0, 0x01);
\r
298 if ( pConfig->AZALIACONFIG.AzaliaConfig.AzaliaSdin1 == 2 ) {
\r
299 RWMEM (ACPI_MMIO_BASE + GPIO_BASE + SB_GPIO_REG168, AccWidthUint8, 0, 0x3E);
\r
300 RWMEM (ACPI_MMIO_BASE + IOMUX_BASE + SB_GPIO_REG168, AccWidthUint8, 0, 0x00);
\r
302 RWMEM (ACPI_MMIO_BASE + GPIO_BASE + SB_GPIO_REG168, AccWidthUint8, 0, 0x0);
\r
303 RWMEM (ACPI_MMIO_BASE + IOMUX_BASE + SB_GPIO_REG168, AccWidthUint8, 0, 0x01);
\r
305 if ( pConfig->AZALIACONFIG.AzaliaConfig.AzaliaSdin2 == 2 ) {
\r
306 RWMEM (ACPI_MMIO_BASE + GPIO_BASE + SB_GPIO_REG169, AccWidthUint8, 0, 0x3E);
\r
307 RWMEM (ACPI_MMIO_BASE + IOMUX_BASE + SB_GPIO_REG169, AccWidthUint8, 0, 0x00);
\r
309 RWMEM (ACPI_MMIO_BASE + GPIO_BASE + SB_GPIO_REG169, AccWidthUint8, 0, 0x0);
\r
310 RWMEM (ACPI_MMIO_BASE + IOMUX_BASE + SB_GPIO_REG169, AccWidthUint8, 0, 0x01);
\r
312 if ( pConfig->AZALIACONFIG.AzaliaConfig.AzaliaSdin3 == 2 ) {
\r
313 RWMEM (ACPI_MMIO_BASE + GPIO_BASE + SB_GPIO_REG170, AccWidthUint8, 0, 0x3E);
\r
314 RWMEM (ACPI_MMIO_BASE + IOMUX_BASE + SB_GPIO_REG170, AccWidthUint8, 0, 0x00);
\r
316 RWMEM (ACPI_MMIO_BASE + GPIO_BASE + SB_GPIO_REG170, AccWidthUint8, 0, 0x0);
\r
317 RWMEM (ACPI_MMIO_BASE + IOMUX_BASE + SB_GPIO_REG170, AccWidthUint8, 0, 0x01);
\r
319 // INT#A Azalia resource
\r
320 Data = 0x93; // Azalia APIC index
\r
321 WriteIO (SB_IOMAP_REGC00, AccWidthUint8, &Data);
\r
322 Data = 0x10; // IRQ16 (INTA#)
\r
323 WriteIO (SB_IOMAP_REGC01, AccWidthUint8, &Data);
\r
327 ReadMEM ( ddBAR0 + SB_AZ_BAR_REG08, AccWidthUint8 | S3_SAVE, &dbTempVariable);
\r
328 dbTempVariable |= BIT0;
\r
329 WriteMEM (ddBAR0 + SB_AZ_BAR_REG08, AccWidthUint8 | S3_SAVE, &dbTempVariable);
\r
331 ReadMEM (ddBAR0 + SB_AZ_BAR_REG08, AccWidthUint8 | S3_SAVE, &dbTempVariable);
\r
333 } while ((! (dbTempVariable & BIT0)) && (i > 0) );
\r
340 ReadMEM ( ddBAR0 + SB_AZ_BAR_REG0E, AccWidthUint16, &dwTempVariable);
\r
341 if ( dwTempVariable & 0x0F ) {
\r
343 //atleast one azalia codec found
\r
344 // ?? E0 is not real register what we expect. we have change to GPIO/and program GPIO Mux
\r
345 //ReadMEM (ACPI_MMIO_BASE + PMIO_BASE + SB_PMIOA_REGE0, AccWidthUint8, &dbPinRouting);
\r
346 dbPinRouting = pConfig->AZALIACONFIG.AzaliaSdinPin;
\r
348 if ( ( ! (dbPinRouting & BIT0) ) && (dbPinRouting & BIT1) ) {
\r
349 // dbChannelNum = 3;
\r
350 configureAzaliaPinCmd (pConfig, ddBAR0, dbChannelNum);
\r
352 dbPinRouting >>= 2;
\r
354 } while ( dbChannelNum != 4 );
\r
356 //No Azalia codec found
\r
357 if ( pConfig->AzaliaController != 2 ) {
\r
358 dbEnableAzalia = 0; //set flag to disable Azalia
\r
363 if ( dbEnableAzalia ) {
\r
366 dwTempVariable = 0;
\r
367 WriteMEM ( ddBAR0 + SB_AZ_BAR_REG0C, AccWidthUint16 | S3_SAVE, &dwTempVariable);
\r
368 ReadMEM (ddBAR0 + SB_AZ_BAR_REG08, AccWidthUint8 | S3_SAVE, &dbTempVariable);
\r
369 dbTempVariable &= ~(BIT0);
\r
370 WriteMEM (ddBAR0 + SB_AZ_BAR_REG08, AccWidthUint8 | S3_SAVE, &dbTempVariable);
\r
371 ReadMEM (ddBAR0 + SB_AZ_BAR_REG08, AccWidthUint8 | S3_SAVE, &dbTempVariable);
\r
372 } while ( dbTempVariable & BIT0 );
\r
374 if ( pConfig->AzaliaSnoop == 1 ) {
\r
375 RWPCI ((AZALIA_BUS_DEV_FUN << 16) + SB_AZ_REG42, AccWidthUint8 | S3_SAVE, 0xFF, BIT1 + BIT0);
\r
378 //disable Azalia controller
\r
379 RWPCI ((AZALIA_BUS_DEV_FUN << 16) + SB_AZ_REG04, AccWidthUint16 | S3_SAVE, 0, 0);
\r
380 // RWPMIO (SB_PMIO_REG59, AccWidthUint8 | S3_SAVE, ~BIT3, 0);
\r
381 RWMEM (ACPI_MMIO_BASE + PMIO_BASE + SB_PMIOA_REGEB, AccWidthUint8, ~BIT0, 0);
\r
382 // RWPCI ((SMBUS_BUS_DEV_FUN << 16) + SB_SMBUS_REGFC, AccWidthUint8 | S3_SAVE, 0, 0x55);
\r
383 RWMEM (ACPI_MMIO_BASE + PMIO_BASE + SB_PMIOA_REGEB, AccWidthUint8, ~BIT0, 0);
\r
388 * configureAzaliaPinCmd - Configuration HD Audio PIN Command
\r
391 * @param[in] pConfig Southbridge configuration structure pointer.
\r
392 * @param[in] ddBAR0 HD Audio BAR0 base address.
\r
393 * @param[in] dbChannelNum Channel Number.
\r
397 configureAzaliaPinCmd (
\r
398 IN AMDSBCFG* pConfig,
\r
400 IN UINT8 dbChannelNum
\r
403 UINT32 ddTempVariable;
\r
404 UINT32 ddChannelNum;
\r
405 CODECTBLLIST* ptempAzaliaOemCodecTablePtr;
\r
406 CODECENTRY* tempAzaliaCodecEntryPtr;
\r
408 if ( (pConfig->AzaliaPinCfg) != 1 ) {
\r
412 ddChannelNum = dbChannelNum << 28;
\r
413 ddTempVariable = 0xF0000;
\r
414 ddTempVariable |= ddChannelNum;
\r
416 WriteMEM (ddBAR0 + SB_AZ_BAR_REG60, AccWidthUint32 | S3_SAVE, &ddTempVariable);
\r
418 ReadMEM (ddBAR0 + SB_AZ_BAR_REG64, AccWidthUint32 | S3_SAVE, &ddTempVariable);
\r
420 if ( ((pConfig->AZOEMTBL.pAzaliaOemCodecTablePtr) == NULL) || ((pConfig->AZOEMTBL.pAzaliaOemCodecTablePtr) == ((CODECTBLLIST*) (UINTN)0xFFFFFFFF))) {
\r
421 ptempAzaliaOemCodecTablePtr = (CODECTBLLIST*) FIXUP_PTR (&azaliaCodecTableList[0]);
\r
423 ptempAzaliaOemCodecTablePtr = (CODECTBLLIST*) pConfig->AZOEMTBL.pAzaliaOemCodecTablePtr;
\r
426 while ( ptempAzaliaOemCodecTablePtr->CodecID != 0xFFFFFFFF ) {
\r
427 if ( ptempAzaliaOemCodecTablePtr->CodecID == ddTempVariable ) {
\r
430 ++ptempAzaliaOemCodecTablePtr;
\r
434 if ( ptempAzaliaOemCodecTablePtr->CodecID != 0xFFFFFFFF ) {
\r
435 tempAzaliaCodecEntryPtr = (CODECENTRY*) ptempAzaliaOemCodecTablePtr->CodecTablePtr;
\r
437 if ( ((pConfig->AZOEMTBL.pAzaliaOemCodecTablePtr) == NULL) || ((pConfig->AZOEMTBL.pAzaliaOemCodecTablePtr) == ((CODECTBLLIST*) (UINTN)0xFFFFFFFF)) ) {
\r
438 tempAzaliaCodecEntryPtr = (CODECENTRY*) FIXUP_PTR (tempAzaliaCodecEntryPtr);
\r
440 configureAzaliaSetConfigD4Dword (tempAzaliaCodecEntryPtr, ddChannelNum, ddBAR0);
\r
441 if ( pConfig->AzaliaFrontPanel != 1 ) {
\r
442 if ( (pConfig->AzaliaFrontPanel == 2) || (pConfig->FrontPanelDetected == 1) ) {
\r
443 if ( ((pConfig->AZOEMFPTBL.pAzaliaOemFpCodecTablePtr) == NULL) || ((pConfig->AZOEMFPTBL.pAzaliaOemFpCodecTablePtr) == (VOID*) (UINTN)0xFFFFFFFF) ) {
\r
444 tempAzaliaCodecEntryPtr = (CODECENTRY*) FIXUP_PTR (&FrontPanelAzaliaCodecTableList[0]);
\r
446 tempAzaliaCodecEntryPtr = (CODECENTRY*) pConfig->AZOEMFPTBL.pAzaliaOemFpCodecTablePtr;
\r
448 configureAzaliaSetConfigD4Dword (tempAzaliaCodecEntryPtr, ddChannelNum, ddBAR0);
\r
455 * configureAzaliaSetConfigD4Dword - Configuration HD Audio Codec table
\r
458 * @param[in] tempAzaliaCodecEntryPtr HD Audio Codec table structure pointer.
\r
459 * @param[in] ddChannelNum HD Audio Channel Number.
\r
460 * @param[in] ddBAR0 HD Audio BAR0 base address.
\r
464 configureAzaliaSetConfigD4Dword (
\r
465 IN CODECENTRY* tempAzaliaCodecEntryPtr,
\r
466 IN UINT32 ddChannelNum,
\r
477 while ( (tempAzaliaCodecEntryPtr->Nid) != 0xFF ) {
\r
479 if ( (tempAzaliaCodecEntryPtr->Nid) == 0x1 ) {
\r
483 ddtemp = tempAzaliaCodecEntryPtr->Nid;
\r
486 ddtemp |= ddChannelNum;
\r
488 ddtemp |= (0x700 << 8);
\r
489 for ( i = 4; i > 0; i-- ) {
\r
491 ReadMEM (ddBAR0 + SB_AZ_BAR_REG68, AccWidthUint32, &ddtemp2);
\r
492 } while ( ddtemp2 & BIT0 );
\r
494 dbtemp2 = (UINT8) (( (tempAzaliaCodecEntryPtr->Byte40) >> ((4 - i) * 8 ) ) & 0xff);
\r
495 ddtemp = (ddtemp & 0xFFFF0000) + ((dbtemp1 - i) << 8) + dbtemp2;
\r
496 WriteMEM (ddBAR0 + SB_AZ_BAR_REG60, AccWidthUint32 | S3_SAVE, &ddtemp);
\r
499 ++tempAzaliaCodecEntryPtr;
\r