blob: 1b7ff7c1d729b38a587bbefed5f48270021b023a [file] [log] [blame]
zbao7d94cf92012-07-02 14:19:14 +08001/* $NoKeywords:$ */
2/**
3 * @file
4 *
5 * Config FCH HD Audio Controller
6 *
7 *
8 *
9 * @xrefitem bom "File Content Label" "Release Content"
10 * @e project: AGESA
11 * @e sub-project: FCH
12 * @e \$Revision: 63425 $ @e \$Date: 2011-12-22 11:24:10 -0600 (Thu, 22 Dec 2011) $
13 *
14 */
15/*
16*****************************************************************************
17*
Siyuan Wang641f00c2013-06-08 11:50:55 +080018 * Copyright (c) 2008 - 2012, Advanced Micro Devices, Inc.
19 * All rights reserved.
20 *
21 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions are met:
23 * * Redistributions of source code must retain the above copyright
24 * notice, this list of conditions and the following disclaimer.
25 * * Redistributions in binary form must reproduce the above copyright
26 * notice, this list of conditions and the following disclaimer in the
27 * documentation and/or other materials provided with the distribution.
28 * * Neither the name of Advanced Micro Devices, Inc. nor the names of
29 * its contributors may be used to endorse or promote products derived
30 * from this software without specific prior written permission.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
34 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
36 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
39 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
zbao7d94cf92012-07-02 14:19:14 +080042****************************************************************************
43*/
44#include "FchPlatform.h"
45#define FILECODE (0xB003)
46//
47// Declaration of local functions
48//
49
zbao7598bea2012-08-09 15:08:20 +080050VOID
51ConfigureAzaliaPinCmd (
52 IN FCH_DATA_BLOCK *FchDataPtr,
53 IN UINT32 BAR0,
54 IN UINT8 ChannelNum
55 );
zbao7d94cf92012-07-02 14:19:14 +080056
zbao7598bea2012-08-09 15:08:20 +080057VOID
58ConfigureAzaliaSetConfigD4Dword (
59 IN CODEC_ENTRY *TempAzaliaCodecEntryPtr,
60 IN UINT32 ChannelNumDword,
61 IN UINT32 BAR0,
62 IN AMD_CONFIG_PARAMS *StdHeader
63 );
zbao7d94cf92012-07-02 14:19:14 +080064
zbao7598bea2012-08-09 15:08:20 +080065/**
66 * FchInitMidAzalia - Config Azalia controller after PCI
67 * emulation
68 *
69 *
70 *
71 * @param[in] FchDataPtr Fch configuration structure pointer.
72 *
73 */
74VOID
75FchInitMidAzalia (
76 IN VOID *FchDataPtr
77 )
78{
79 UINT8 Index;
80 BOOLEAN EnableAzalia;
81 UINT32 PinRouting;
82 UINT8 ChannelNum;
83 UINT8 AzaliaTempVariableByte;
84 UINT16 AzaliaTempVariableWord;
85 UINT32 BAR0;
86 FCH_DATA_BLOCK *LocalCfgPtr;
87 AMD_CONFIG_PARAMS *StdHeader;
zbao7d94cf92012-07-02 14:19:14 +080088
zbao7598bea2012-08-09 15:08:20 +080089 LocalCfgPtr = (FCH_DATA_BLOCK *) FchDataPtr;
90 StdHeader = LocalCfgPtr->StdHeader;
zbao7d94cf92012-07-02 14:19:14 +080091
zbao7598bea2012-08-09 15:08:20 +080092 EnableAzalia = FALSE;
93 ChannelNum = 0;
94 AzaliaTempVariableByte = 0;
95 AzaliaTempVariableWord = 0;
96 BAR0 = 0;
zbao7d94cf92012-07-02 14:19:14 +080097
zbao7598bea2012-08-09 15:08:20 +080098 if ( LocalCfgPtr->Azalia.AzaliaEnable == AzDisable) {
99 return;
100 } else {
101 RwPci ((((0x14<<3)+2) << 16) + 0x04, AccessWidth8, (UINT32)~BIT1, (UINT32)BIT1, StdHeader);
102
103 if ( LocalCfgPtr->Azalia.AzaliaSsid != 0 ) {
104 RwPci ((((0x14<<3)+2) << 16) + 0x2C, AccessWidth32, 0x00, LocalCfgPtr->Azalia.AzaliaSsid, StdHeader);
105 }
106
107 ReadPci ((((0x14<<3)+2) << 16) + 0x10, AccessWidth32, &BAR0, StdHeader);
108
109 if ( BAR0 != 0 ) {
110 if ( BAR0 != 0xFFFFFFFF ) {
111 BAR0 &= ~(0x03FFF);
112 EnableAzalia = TRUE;
113 }
114 }
115 }
116
117 if ( EnableAzalia ) {
118 //
119 // Get SDIN Configuration
120 //
121 if ( LocalCfgPtr->Azalia.AzaliaConfig.AzaliaSdin0 == 2 ) {
122 RwMem (ACPI_MMIO_BASE + GPIO_BASE + FCH_GPIO_REG167, AccessWidth8, 0, 0x3E);
123 RwMem (ACPI_MMIO_BASE + IOMUX_BASE + FCH_GPIO_REG167, AccessWidth8, 0, 0x00);
124 } else {
125 RwMem (ACPI_MMIO_BASE + GPIO_BASE + FCH_GPIO_REG167, AccessWidth8, 0, 0x0);
126 RwMem (ACPI_MMIO_BASE + IOMUX_BASE + FCH_GPIO_REG167, AccessWidth8, 0, 0x01);
127 }
128
129 if ( LocalCfgPtr->Azalia.AzaliaConfig.AzaliaSdin1 == 2 ) {
130 RwMem (ACPI_MMIO_BASE + GPIO_BASE + FCH_GPIO_REG168, AccessWidth8, 0, 0x3E);
131 RwMem (ACPI_MMIO_BASE + IOMUX_BASE + FCH_GPIO_REG168, AccessWidth8, 0, 0x00);
132 } else {
133 RwMem (ACPI_MMIO_BASE + GPIO_BASE + FCH_GPIO_REG168, AccessWidth8, 0, 0x0);
134 RwMem (ACPI_MMIO_BASE + IOMUX_BASE + FCH_GPIO_REG168, AccessWidth8, 0, 0x01);
135 }
136
137 if ( LocalCfgPtr->Azalia.AzaliaConfig.AzaliaSdin2 == 2 ) {
138 RwMem (ACPI_MMIO_BASE + GPIO_BASE + FCH_GPIO_REG169, AccessWidth8, 0, 0x3E);
139 RwMem (ACPI_MMIO_BASE + IOMUX_BASE + FCH_GPIO_REG169, AccessWidth8, 0, 0x00);
140 } else {
141 RwMem (ACPI_MMIO_BASE + GPIO_BASE + FCH_GPIO_REG169, AccessWidth8, 0, 0x0);
142 RwMem (ACPI_MMIO_BASE + IOMUX_BASE + FCH_GPIO_REG169, AccessWidth8, 0, 0x01);
143 }
144
145 if ( LocalCfgPtr->Azalia.AzaliaConfig.AzaliaSdin3 == 2 ) {
146 RwMem (ACPI_MMIO_BASE + GPIO_BASE + FCH_GPIO_REG170, AccessWidth8, 0, 0x3E);
147 RwMem (ACPI_MMIO_BASE + IOMUX_BASE + FCH_GPIO_REG170, AccessWidth8, 0, 0x00);
148 } else {
149 RwMem (ACPI_MMIO_BASE + GPIO_BASE + FCH_GPIO_REG170, AccessWidth8, 0, 0x0);
150 RwMem (ACPI_MMIO_BASE + IOMUX_BASE + FCH_GPIO_REG170, AccessWidth8, 0, 0x01);
151 }
152
153 Index = 11;
154 do {
155 ReadMem ( BAR0 + 0x08, AccessWidth8, &AzaliaTempVariableByte);
156 AzaliaTempVariableByte |= BIT0;
157 WriteMem (BAR0 + 0x08, AccessWidth8, &AzaliaTempVariableByte);
158 FchStall (1000, StdHeader);
159 ReadMem (BAR0 + 0x08, AccessWidth8, &AzaliaTempVariableByte);
160 Index--;
161 } while ((! (AzaliaTempVariableByte & BIT0)) && (Index > 0) );
162
163 if ( Index == 0 ) {
164 return;
165 }
166
167 FchStall (1000, StdHeader);
168 ReadMem ( BAR0 + 0x0E, AccessWidth16, &AzaliaTempVariableWord);
169 if ( AzaliaTempVariableWord & 0x0F ) {
170
171 //
172 //at least one azalia codec found
173 //
174 //PinRouting = LocalCfgPtr->Azalia.AZALIA_CONFIG.AzaliaSdinPin;
175 //new structure need make up PinRouting
176 //need adjust later!!!
177 //
178 PinRouting = 0;
179 PinRouting = (UINT32 )LocalCfgPtr->Azalia.AzaliaConfig.AzaliaSdin3;
180 PinRouting <<= 8;
181 PinRouting |= (UINT32 )LocalCfgPtr->Azalia.AzaliaConfig.AzaliaSdin2;
182 PinRouting <<= 8;
183 PinRouting |= (UINT32 )LocalCfgPtr->Azalia.AzaliaConfig.AzaliaSdin1;
184 PinRouting <<= 8;
185 PinRouting |= (UINT32 )LocalCfgPtr->Azalia.AzaliaConfig.AzaliaSdin0;
186
187 do {
188 if ( ( ! (PinRouting & BIT0) ) && (PinRouting & BIT1) ) {
189 ConfigureAzaliaPinCmd (LocalCfgPtr, BAR0, ChannelNum);
190 }
191 PinRouting >>= 8;
192 ChannelNum++;
193 } while ( ChannelNum != 4 );
194 } else {
195 //
196 //No Azalia codec found
197 //
198 if ( LocalCfgPtr->Azalia.AzaliaEnable != AzEnable ) {
199 EnableAzalia = FALSE; ///set flag to disable Azalia
200 }
201 }
202 }
203
204 if ( EnableAzalia ) {
205 if ( LocalCfgPtr->Azalia.AzaliaSnoop == 1 ) {
206 RwPci ((((0x14<<3)+2) << 16) + 0x42, AccessWidth8, 0xFF, BIT1 + BIT0, StdHeader);
207 }
208 } else {
209 //
210 //disable Azalia controller
211 //
212 RwPci ((((0x14<<3)+2) << 16) + 0x04, AccessWidth16, 0, 0, StdHeader);
213 RwMem (ACPI_MMIO_BASE + PMIO_BASE + 0xEB , AccessWidth8, (UINT32)~BIT0, 0);
214 RwMem (ACPI_MMIO_BASE + PMIO_BASE + 0xEB , AccessWidth8, (UINT32)~BIT0, 0);
215 }
216}
217
218/**
219 * Pin Config for ALC880, ALC882 and ALC883.
220 *
221 *
222 *
223 */
224CODEC_ENTRY AzaliaCodecAlc882Table[] =
225{
226 {0x14, 0x01014010},
227 {0x15, 0x01011012},
228 {0x16, 0x01016011},
229 {0x17, 0x01012014},
230 {0x18, 0x01A19030},
231 {0x19, 0x411111F0},
232 {0x1a, 0x01813080},
233 {0x1b, 0x411111F0},
234 {0x1C, 0x411111F0},
235 {0x1d, 0x411111F0},
236 {0x1e, 0x01441150},
237 {0x1f, 0x01C46160},
238 {0xff, 0xffffffff}
239};
240
241/**
242 * Pin Config for ALC0262.
243 *
244 *
245 *
246 */
247CODEC_ENTRY AzaliaCodecAlc262Table[] =
248{
249 {0x14, 0x01014010},
250 {0x15, 0x411111F0},
251 {0x16, 0x411111F0},
252 {0x18, 0x01A19830},
253 {0x19, 0x02A19C40},
254 {0x1a, 0x01813031},
255 {0x1b, 0x02014C20},
256 {0x1c, 0x411111F0},
257 {0x1d, 0x411111F0},
258 {0x1e, 0x0144111E},
259 {0x1f, 0x01C46150},
260 {0xff, 0xffffffff}
261};
262
263/**
264 * Pin Config for ALC0269.
265 *
266 *
267 *
268 */
269CODEC_ENTRY AzaliaCodecAlc269Table[] =
270{
271 {0x12, 0x99A308F0},
272 {0x14, 0x99130010},
273 {0x15, 0x0121101F},
274 {0x16, 0x99036120},
275 {0x18, 0x01A19850},
276 {0x19, 0x99A309F0},
277 {0x1a, 0x01813051},
278 {0x1b, 0x0181405F},
279 {0x1d, 0x40134601},
280 {0x1e, 0x01442130},
281 {0x11, 0x99430140},
282 {0x20, 0x0030FFFF},
283 {0xff, 0xffffffff}
284};
285
286/**
287 * Pin Config for ALC0861.
288 *
289 *
290 *
291 */
292CODEC_ENTRY AzaliaCodecAlc861Table[] =
293{
294 {0x01, 0x8086C601},
295 {0x0B, 0x01014110},
296 {0x0C, 0x01813140},
297 {0x0D, 0x01A19941},
298 {0x0E, 0x411111F0},
299 {0x0F, 0x02214420},
300 {0x10, 0x02A1994E},
301 {0x11, 0x99330142},
302 {0x12, 0x01451130},
303 {0x1F, 0x411111F0},
304 {0x20, 0x411111F0},
305 {0x23, 0x411111F0},
306 {0xff, 0xffffffff}
307};
308
309/**
310 * Pin Config for ALC0889.
311 *
312 *
313 *
314 */
315CODEC_ENTRY AzaliaCodecAlc889Table[] =
316{
317 {0x11, 0x411111F0},
318 {0x14, 0x01014010},
319 {0x15, 0x01011012},
320 {0x16, 0x01016011},
321 {0x17, 0x01013014},
322 {0x18, 0x01A19030},
323 {0x19, 0x411111F0},
324 {0x1a, 0x411111F0},
325 {0x1b, 0x411111F0},
326 {0x1C, 0x411111F0},
327 {0x1d, 0x411111F0},
328 {0x1e, 0x01442150},
329 {0x1f, 0x01C42160},
330 {0xff, 0xffffffff}
331};
332
333/**
334 * Pin Config for ADI1984.
335 *
336 *
337 *
338 */
339CODEC_ENTRY AzaliaCodecAd1984Table[] =
340{
341 {0x11, 0x0221401F},
342 {0x12, 0x90170110},
343 {0x13, 0x511301F0},
344 {0x14, 0x02A15020},
345 {0x15, 0x50A301F0},
346 {0x16, 0x593301F0},
347 {0x17, 0x55A601F0},
348 {0x18, 0x55A601F0},
349 {0x1A, 0x91F311F0},
350 {0x1B, 0x014511A0},
351 {0x1C, 0x599301F0},
352 {0xff, 0xffffffff}
353};
354
355/**
356 * FrontPanel Config table list
357 *
358 *
359 *
360 */
361CODEC_ENTRY FrontPanelAzaliaCodecTableList[] =
362{
363 {0x19, 0x02A19040},
364 {0x1b, 0x02214020},
365 {0xff, 0xffffffff}
366};
367
368/**
369 * Current HD Audio support codec list
370 *
371 *
372 *
373 */
374CODEC_TBL_LIST AzaliaCodecTableList[] =
375{
376 {0x010ec0880, &AzaliaCodecAlc882Table[0]},
377 {0x010ec0882, &AzaliaCodecAlc882Table[0]},
378 {0x010ec0883, &AzaliaCodecAlc882Table[0]},
379 {0x010ec0885, &AzaliaCodecAlc882Table[0]},
380 {0x010ec0889, &AzaliaCodecAlc889Table[0]},
381 {0x010ec0262, &AzaliaCodecAlc262Table[0]},
382 {0x010ec0269, &AzaliaCodecAlc269Table[0]},
383 {0x010ec0861, &AzaliaCodecAlc861Table[0]},
384 {0x011d41984, &AzaliaCodecAd1984Table[0]},
385 { (UINT32) 0x0FFFFFFFF, (CODEC_ENTRY*) (UINTN)0x0FFFFFFFF}
386};
387
388/**
389 * ConfigureAzaliaPinCmd - Configuration HD Audio PIN Command
390 *
391 *
392 * @param[in] FchDataPtr Fch configuration structure pointer.
393 * @param[in] BAR0 HD Audio BAR0 base address.
394 * @param[in] ChannelNum Channel Number.
395 *
396 */
397VOID
398ConfigureAzaliaPinCmd (
399 IN FCH_DATA_BLOCK *FchDataPtr,
400 IN UINT32 BAR0,
401 IN UINT8 ChannelNum
402 )
403{
404 UINT32 AzaliaTempVariable;
405 UINT32 ChannelNumDword;
406 CODEC_TBL_LIST *TempAzaliaOemCodecTablePtr;
407 CODEC_ENTRY *TempAzaliaCodecEntryPtr;
408
409 if ( (FchDataPtr->Azalia.AzaliaPinCfg) != 1 ) {
410 return;
411 }
412
413 ChannelNumDword = ChannelNum << 28;
414 AzaliaTempVariable = 0xF0000;
415 AzaliaTempVariable |= ChannelNumDword;
416
417 WriteMem (BAR0 + 0x60, AccessWidth32, &AzaliaTempVariable);
418 FchStall (600, FchDataPtr->StdHeader);
419 ReadMem (BAR0 + 0x64, AccessWidth32, &AzaliaTempVariable);
420
421 if ( ((FchDataPtr->Azalia.AzaliaOemCodecTablePtr) == NULL) || ((FchDataPtr->Azalia.AzaliaOemCodecTablePtr) == ((CODEC_TBL_LIST*) (UINTN)0xFFFFFFFF))) {
422 TempAzaliaOemCodecTablePtr = (CODEC_TBL_LIST*) (&AzaliaCodecTableList[0]);
423 } else {
424 TempAzaliaOemCodecTablePtr = (CODEC_TBL_LIST*) FchDataPtr->Azalia.AzaliaOemCodecTablePtr;
425 }
426
427 while ( TempAzaliaOemCodecTablePtr->CodecId != 0xFFFFFFFF ) {
428 if ( TempAzaliaOemCodecTablePtr->CodecId == AzaliaTempVariable ) {
429 break;
430 } else {
431 ++TempAzaliaOemCodecTablePtr;
432 }
433 }
434
435 if ( TempAzaliaOemCodecTablePtr->CodecId != 0xFFFFFFFF ) {
436 TempAzaliaCodecEntryPtr = (CODEC_ENTRY*) TempAzaliaOemCodecTablePtr->CodecTablePtr;
437 if ( ((FchDataPtr->Azalia.AzaliaOemCodecTablePtr) == NULL) || ((FchDataPtr->Azalia.AzaliaOemCodecTablePtr) == ((CODEC_TBL_LIST*) (UINTN)0xFFFFFFFF)) ) {
438 TempAzaliaCodecEntryPtr = (CODEC_ENTRY*) (TempAzaliaCodecEntryPtr);
439 }
440
441 ConfigureAzaliaSetConfigD4Dword (TempAzaliaCodecEntryPtr, ChannelNumDword, BAR0, FchDataPtr->StdHeader);
442
443 if ( FchDataPtr->Azalia.AzaliaFrontPanel != 1 ) {
444 if ( (FchDataPtr->Azalia.AzaliaFrontPanel == 2) || (FchDataPtr->Azalia.FrontPanelDetected == 1) ) {
445 if ( ((FchDataPtr->Azalia.AzaliaOemFpCodecTablePtr) == NULL) || ((FchDataPtr->Azalia.AzaliaOemFpCodecTablePtr) == (VOID*) (UINTN)0xFFFFFFFF) ) {
446 TempAzaliaCodecEntryPtr = (CODEC_ENTRY*) (&FrontPanelAzaliaCodecTableList[0]);
447 } else {
448 TempAzaliaCodecEntryPtr = (CODEC_ENTRY*) FchDataPtr->Azalia.AzaliaOemFpCodecTablePtr;
449 }
450
451 ConfigureAzaliaSetConfigD4Dword (TempAzaliaCodecEntryPtr, ChannelNumDword, BAR0, FchDataPtr->StdHeader);
452 }
453 }
454 }
455}
456
457/**
458 * ConfigureAzaliaSetConfigD4Dword - Configuration HD Audio Codec table
459 *
460 *
461 * @param[in] TempAzaliaCodecEntryPtr HD Audio Codec table structure pointer.
462 * @param[in] ChannelNumDword HD Audio Channel Number.
463 * @param[in] BAR0 HD Audio BAR0 base address.
464 * @param[in] StdHeader
465 *
466 */
467VOID
468ConfigureAzaliaSetConfigD4Dword (
469 IN CODEC_ENTRY *TempAzaliaCodecEntryPtr,
470 IN UINT32 ChannelNumDword,
471 IN UINT32 BAR0,
472 IN AMD_CONFIG_PARAMS *StdHeader
473 )
474{
475 UINT8 TempByte1;
476 UINT8 TempByte2;
477 UINT8 Index;
478 UINT32 TempDword1;
479 UINT32 TempDword2;
480
481 TempDword1 = 0;
482 TempDword2 = 0;
483
484 while ( (TempAzaliaCodecEntryPtr->Nid) != 0xFF ) {
485 TempByte1 = 0x20;
486 if ( (TempAzaliaCodecEntryPtr->Nid) == 0x1 ) {
487 TempByte1 = 0x24;
488 }
489
490 TempDword1 = TempAzaliaCodecEntryPtr->Nid;
491 TempDword1 &= 0xff;
492 TempDword1 <<= 20;
493 TempDword1 |= ChannelNumDword;
494 TempDword1 |= (0x700 << 8);
495
496 for ( Index = 4; Index > 0; Index-- ) {
497 do {
498 ReadMem (BAR0 + 0x68, AccessWidth32, &TempDword2);
499 } while ( (TempDword2 & BIT0) != 0 );
500
501 TempByte2 = (UINT8) (( (TempAzaliaCodecEntryPtr->Byte40) >> ((4 - Index) * 8 ) ) & 0xff);
502 TempDword1 = (TempDword1 & 0xFFFF0000) + ((TempByte1 - Index) << 8) + TempByte2;
503 WriteMem (BAR0 + 0x60, AccessWidth32, &TempDword1);
504 FchStall (60, StdHeader);
505 }
506
507 ++TempAzaliaCodecEntryPtr;
508 }
509}
zbao7d94cf92012-07-02 14:19:14 +0800510
511