ea9afd24e3d7c93bfcb925c22b73225c212a0d41
[coreboot.git] / src / vendorcode / amd / agesa / f14 / Proc / GNB / Nb / Feature / NbFuseTable.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * Fuse table initialization
6  *
7  *
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project:     AGESA
11  * @e sub-project: GNB
12  * @e \$Revision: 48498 $   @e \$Date: 2011-03-09 12:44:53 -0700 (Wed, 09 Mar 2011) $
13  *
14  */
15 /*
16  *****************************************************************************
17  *
18  * Copyright (c) 2011, 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.
42  * 
43  * ***************************************************************************
44  *
45  */
46
47 /*----------------------------------------------------------------------------------------
48  *                             M O D U L E S    U S E D
49  *----------------------------------------------------------------------------------------
50  */
51
52 #include  "AGESA.h"
53 #include  "amdlib.h"
54 #include  "Ids.h"
55 #include  "heapManager.h"
56 #include  "Gnb.h"
57 #include  "GnbFuseTable.h"
58 #include  GNB_MODULE_DEFINITIONS (GnbCommonLib)
59 #include  "GnbRegistersON.h"
60 #include  "NbSmuLib.h"
61 #include  "NbConfigData.h"
62 #include  "NbFuseTable.h"
63 #include  "NbFamilyServices.h"
64 #include  "GfxLib.h"
65 #include  "Filecode.h"
66
67 #define FILECODE PROC_GNB_NB_FEATURE_NBFUSETABLE_FILECODE
68 /*----------------------------------------------------------------------------------------
69  *                   D E F I N I T I O N S    A N D    M A C R O S
70  *----------------------------------------------------------------------------------------
71  */
72
73 /*----------------------------------------------------------------------------------------
74  *                  T Y P E D E F S     A N D     S T R U C T U  R E S
75  *----------------------------------------------------------------------------------------
76  */
77
78 /*----------------------------------------------------------------------------------------
79  *           P R O T O T Y P E S     O F     L O C A L     F U  N C T I O N S
80  *----------------------------------------------------------------------------------------
81  */
82
83 VOID
84 NbFuseLoadDefaultFuseTable (
85   OUT     PP_FUSE_ARRAY       *PpFuseArray,
86   IN      AMD_CONFIG_PARAMS   *StdHeader
87   );
88
89 VOID
90 NbFuseLoadFuseTableFromFcr (
91   OUT     PP_FUSE_ARRAY       *PpFuseArray,
92   IN      AMD_CONFIG_PARAMS   *StdHeader
93   );
94
95 VOID
96 NbFuseDebugDump (
97   IN       PP_FUSE_ARRAY       *PpFuseArray,
98   IN       AMD_CONFIG_PARAMS   *StdHeader
99   );
100
101 VOID
102 NbFuseAdjustFuseTableToCurrentMainPllVco (
103   IN  OUT   PP_FUSE_ARRAY      *PpFuseArray,
104   IN       AMD_CONFIG_PARAMS   *StdHeader
105   );
106
107 PP_FUSE_ARRAY  DefaultPpFuseArray = {
108   0,                              ///< PP table revision
109   {1,    0,  0,  0,  0,  0},      ///< Valid DPM states
110   {0x40, 0,  0,  0,  0},          ///< Sclk DPM DID
111   {0,    0,  0,  0,  0},          ///< Sclk DPM VID
112   {0,    0,  0,  0,  0},          ///< Sclk DPM Cac
113   {1,    0,  0,  0,  0,  0},      ///< State policy flags
114   {2,    0,  0,  0,  0,  0},      ///< State policy label
115   {0x40, 0,  0,  0},              ///< VCLK DID
116   {0x40, 0,  0,  0},              ///< DCLK DID
117   0,                              ///< Thermal SCLK
118   {0,    0,  0,  0,  0,  0},      ///< Vclk/Dclk selector
119   {0,    0,  0,  0},              ///< Valid Lclk DPM states
120   {0,    0,  0,  0},              ///< Lclk DPM DID
121   {0,    0,  0,  0},              ///< Lclk DPM VID
122   {0,    0,  0,  0},              ///< Displclk DID
123   3,                              ///< Pcie Gen 2 VID
124   0x10                            ///< Main PLL id for 3200 VCO
125 };
126
127
128 /*----------------------------------------------------------------------------------------*/
129 /**
130  * Fuse Table Init
131  *
132  *
133  *
134  * @param[in] StdHeader        Pointer to Standard configuration
135  * @retval    AGESA_STATUS
136  */
137
138 AGESA_STATUS
139 NbFuseTableFeature (
140   IN      AMD_CONFIG_PARAMS   *StdHeader
141   )
142 {
143   PP_FUSE_ARRAY          *PpFuseArray;
144   D18F3xA0_STRUCT        D18F3xA0;
145   BOOLEAN                LoadDefaultFuses;
146   IDS_HDT_CONSOLE (GNB_TRACE, "NbFuseTableFeature Enter\n");
147
148   PpFuseArray = (PP_FUSE_ARRAY *) GnbAllocateHeapBuffer (AMD_PP_FUSE_TABLE_HANDLE, sizeof (PP_FUSE_ARRAY), StdHeader);
149   ASSERT (PpFuseArray != NULL);
150   if (PpFuseArray == NULL) {
151     IDS_HDT_CONSOLE (GNB_TRACE, "  ERROR!!! Heap Allocation\n");
152     return AGESA_ERROR;
153   }
154   LibAmdMemFill (PpFuseArray, 0x00, sizeof (PP_FUSE_ARRAY), StdHeader);
155   GnbLibPciRead (
156        MAKE_SBDFO ( 0, 0, 0x18, 3, D18F3xA0_ADDRESS),
157        AccessWidth32,
158        &D18F3xA0.Value,
159        StdHeader
160      );
161
162 #ifndef  GNB_FORCE_DEFAULT_FUSE
163   LoadDefaultFuses = FALSE;
164   if (D18F3xA0.Field.CofVidProg == 1) {
165     IDS_HDT_CONSOLE (NB_MISC, "  Processor Fused\n");
166     NbFuseLoadFuseTableFromFcr (PpFuseArray, StdHeader);
167     if (PpFuseArray->PPlayTableRev == 0) {
168       IDS_HDT_CONSOLE (NB_MISC, "  PowerPlay Table Unfused\n");
169       LoadDefaultFuses = TRUE;
170     }
171   } else {
172     IDS_HDT_CONSOLE (NB_MISC, "  Processor Unfuse\n");
173     LoadDefaultFuses = TRUE;
174   }
175 #else
176   LoadDefaultFuses = TRUE;
177 #endif
178   if (LoadDefaultFuses) {
179     IDS_HDT_CONSOLE (NB_MISC, "  Load default fuses\n");
180     NbFuseLoadDefaultFuseTable (PpFuseArray, StdHeader);
181   }
182   NbFmFuseAdjustFuseTablePatch (PpFuseArray, StdHeader);
183   NbFuseAdjustFuseTableToCurrentMainPllVco (PpFuseArray, StdHeader);
184   IDS_OPTION_CALLOUT (IDS_CALLOUT_GNB_PPFUSE_OVERRIDE, PpFuseArray, StdHeader);
185   GNB_DEBUG_CODE (
186     NbFuseDebugDump (PpFuseArray, StdHeader)
187     );
188   IDS_HDT_CONSOLE (GNB_TRACE, "NbFuseTableFeature Exit\n");
189   return AGESA_SUCCESS;
190 }
191
192
193 /*----------------------------------------------------------------------------------------*/
194 /**
195  * Load Fuse Table From FCRs
196  *
197  *
198  * @param[out] PpFuseArray      Pointer to save fuse table
199  * @param[in]  StdHeader        Pointer to Standard configuration
200  * @retval     AGESA_STATUS
201  */
202
203 VOID
204 NbFuseLoadFuseTableFromFcr (
205      OUT   PP_FUSE_ARRAY       *PpFuseArray,
206   IN       AMD_CONFIG_PARAMS   *StdHeader
207   )
208 {
209   FUSE_TABLE             *FuseTable;
210   UINTN                  RegisterIndex;
211   FuseTable = NbFmGetFuseTranslationTable ();
212   for (RegisterIndex = 0; RegisterIndex < FuseTable->FuseTableLength; RegisterIndex++ ) {
213     UINTN   FieldIndex;
214     UINTN   FuseRegisterTableLength;
215     UINT32  FuseValue;
216     FuseRegisterTableLength = FuseTable->FuseTable[RegisterIndex].FuseRegisterTableLength;
217     FuseValue = NbSmuReadEfuse (
218                   FuseTable->FuseTable[RegisterIndex].Register,
219                   StdHeader
220                   );
221     for (FieldIndex = 0; FieldIndex < FuseRegisterTableLength;  FieldIndex++) {
222       FUSE_REGISTER_ENTRY   RegisterEntry;
223       UINT8                 *FuseArrayPtr;
224       UINT32                FuseArrauValue;
225       RegisterEntry = FuseTable->FuseTable[RegisterIndex].FuseRegisterTable[FieldIndex];
226       FuseArrayPtr = (UINT8*) PpFuseArray + RegisterEntry.FuseOffset;
227       FuseArrauValue = (FuseValue >> RegisterEntry.FieldOffset) & ((1 << RegisterEntry.FieldWidth) - 1);
228       if (RegisterEntry.FieldWidth > 16) {
229         *((UINT32 *) FuseArrayPtr) = FuseArrauValue;
230       } else if (RegisterEntry.FieldWidth > 8) {
231         *((UINT16 *) FuseArrayPtr) = (UINT16) FuseArrauValue;
232       } else {
233         *((UINT8 *) FuseArrayPtr) = (UINT8) FuseArrauValue;
234       }
235     }
236   }
237 }
238
239 /*----------------------------------------------------------------------------------------*/
240 /**
241  * Load Default Fuse Table
242  *
243  *
244  * @param[out] PpFuseArray      Pointer to save fuse table
245  * @param[in]  StdHeader        Pointer to Standard configuration
246  * @retval     AGESA_STATUS
247  */
248
249 VOID
250 NbFuseLoadDefaultFuseTable (
251      OUT   PP_FUSE_ARRAY       *PpFuseArray,
252   IN       AMD_CONFIG_PARAMS   *StdHeader
253   )
254 {
255   D18F3x15C_STRUCT  D18F3x15C;
256   UINT8             MaxVidIndex;
257   LibAmdMemCopy (PpFuseArray, &DefaultPpFuseArray, sizeof (PP_FUSE_ARRAY), StdHeader);
258   GnbLibPciRead (
259     MAKE_SBDFO ( 0, 0, 0x18, 3, D18F3x15C_ADDRESS),
260     AccessWidth32,
261     &D18F3x15C.Value,
262     StdHeader
263     );
264   if (D18F3x15C.Value == 0) {
265     D18F3x15C.Value = 0x24242424;
266     GnbLibPciWrite (
267       MAKE_SBDFO ( 0, 0, 0x18, 3, D18F3x15C_ADDRESS),
268       AccessWidth32,
269       &D18F3x15C.Value,
270       StdHeader
271       );
272   }
273   MaxVidIndex = GfxLibMaxVidIndex (StdHeader);
274   PpFuseArray->SclkDpmVid[0] = MaxVidIndex;
275   PpFuseArray->PcieGen2Vid = MaxVidIndex;
276
277 }
278
279 /*----------------------------------------------------------------------------------------*/
280 /**
281  * Adjust DIDs to current main PLL VCO
282  *
283  *  Main PLL VCO can be changed for debug perpouses
284  *
285  * @param[in,out] PpFuseArray      Pointer to save fuse table
286  * @param[in]     StdHeader        Pointer to Standard configuration
287  */
288
289 VOID
290 NbFuseAdjustFuseTableToCurrentMainPllVco (
291   IN OUT   PP_FUSE_ARRAY       *PpFuseArray,
292   IN       AMD_CONFIG_PARAMS   *StdHeader
293   )
294 {
295   UINT32  EffectiveMainPllFreq10KHz;
296   UINT32  FusedMainPllFreq10KHz;
297   UINT32  TempVco;
298   UINTN   Index;
299   EffectiveMainPllFreq10KHz = GfxLibGetMainPllFreq (StdHeader) * 100;
300   FusedMainPllFreq10KHz = (PpFuseArray->MainPllId + 0x10) * 100 * 100;
301   if (FusedMainPllFreq10KHz != EffectiveMainPllFreq10KHz) {
302     IDS_HDT_CONSOLE (NB_MISC, "  WARNING! Adjusting fuse table for reprogrammed VCO\n");
303     IDS_HDT_CONSOLE (NB_MISC, "  Actual main Freq %d \n", EffectiveMainPllFreq10KHz);
304     IDS_HDT_CONSOLE (NB_MISC, "  Fused  main Freq %d \n", FusedMainPllFreq10KHz);
305     for (Index = 0; Index < 5; Index++) {
306       if (PpFuseArray->SclkDpmDid[Index] != 0) {
307         TempVco = GfxLibCalculateClk (PpFuseArray->SclkDpmDid[Index], FusedMainPllFreq10KHz);
308         PpFuseArray->SclkDpmDid[Index] = GfxLibCalculateDid (TempVco, EffectiveMainPllFreq10KHz);
309       }
310     }
311     for (Index = 0; Index < 4; Index++) {
312       if (PpFuseArray->VclkDid[Index] != 0) {
313         TempVco = GfxLibCalculateClk (PpFuseArray->VclkDid[Index], FusedMainPllFreq10KHz);
314         PpFuseArray->VclkDid[Index] = GfxLibCalculateDid (TempVco, EffectiveMainPllFreq10KHz);
315       }
316       if (PpFuseArray->DclkDid[Index] != 0) {
317         TempVco = GfxLibCalculateClk (PpFuseArray->DclkDid[Index], FusedMainPllFreq10KHz);
318         PpFuseArray->DclkDid[Index] = GfxLibCalculateDid (TempVco, EffectiveMainPllFreq10KHz);
319       }
320       if (PpFuseArray->LclkDpmDid[Index] != 0) {
321         TempVco = GfxLibCalculateClk (PpFuseArray->LclkDpmDid[Index], FusedMainPllFreq10KHz);
322         PpFuseArray->LclkDpmDid[Index] = GfxLibCalculateDid (TempVco, EffectiveMainPllFreq10KHz);
323       }
324       if (PpFuseArray->DisplclkDid[Index] != 0) {
325         TempVco = GfxLibCalculateClk (PpFuseArray->DisplclkDid[Index], FusedMainPllFreq10KHz);
326         PpFuseArray->DisplclkDid[Index] = GfxLibCalculateDid (TempVco, EffectiveMainPllFreq10KHz);
327       }
328     }
329     if (PpFuseArray->SclkThermDid != 0) {
330       TempVco = GfxLibCalculateClk (PpFuseArray->SclkThermDid , FusedMainPllFreq10KHz);
331       PpFuseArray->SclkThermDid = GfxLibCalculateDid (TempVco, EffectiveMainPllFreq10KHz);
332     }
333   }
334 }
335
336 /*----------------------------------------------------------------------------------------*/
337 /**
338  * Debug dump fuse table
339  *
340  *
341  * @param[out] PpFuseArray      Pointer to save fuse table
342  * @param[in]  StdHeader        Pointer to Standard configuration
343  */
344
345 VOID
346 NbFuseDebugDump (
347   IN       PP_FUSE_ARRAY       *PpFuseArray,
348   IN       AMD_CONFIG_PARAMS   *StdHeader
349   )
350 {
351   UINTN   Index;
352   UINT32  EffectiveMainPllFreq10KHz;
353
354   EffectiveMainPllFreq10KHz = GfxLibGetMainPllFreq (StdHeader) * 100;
355   IDS_HDT_CONSOLE (NB_MISC, "<------------ GNB FUSE TABLE------------>\n");
356   for (Index = 0; Index < 4; Index++) {
357     if (PpFuseArray->LclkDpmValid[Index]  != 0) {
358       IDS_HDT_CONSOLE (
359         NB_MISC,
360         "  LCLK DID[%d] - 0x%02x (%dMHz)\n",
361         Index,
362         PpFuseArray->LclkDpmDid[Index],
363         GfxLibCalculateClk (PpFuseArray->LclkDpmDid[Index], EffectiveMainPllFreq10KHz) / 100);
364       IDS_HDT_CONSOLE (NB_MISC, "  LCLK VID[%d] - 0x02%x\n", Index, PpFuseArray->LclkDpmVid[Index]);
365     }
366   }
367   for (Index = 0; Index < 4; Index++) {
368     IDS_HDT_CONSOLE (
369       NB_MISC,
370       "  VCLK DID[%d] - 0x%02x (%dMHz)\n",
371       Index,
372       PpFuseArray->VclkDid[Index],
373       (PpFuseArray->VclkDid[Index] != 0) ? (GfxLibCalculateClk (PpFuseArray->VclkDid[Index], EffectiveMainPllFreq10KHz) / 100) : 0
374       );
375     IDS_HDT_CONSOLE (
376       NB_MISC,
377       "  DCLK DID[%d] - 0x%02x (%dMHz)\n",
378       Index,
379       PpFuseArray->DclkDid[Index],
380       (PpFuseArray->DclkDid[Index] != 0) ? (GfxLibCalculateClk (PpFuseArray->DclkDid[Index], EffectiveMainPllFreq10KHz) / 100) : 0
381     );
382   }
383   for (Index = 0; Index < 4; Index++) {
384     IDS_HDT_CONSOLE (
385       NB_MISC,
386       "  DISPCLK DID[%d] - 0x%02x (%dMHz)\n",
387       Index,
388       PpFuseArray->DisplclkDid[Index],
389       (PpFuseArray->DisplclkDid[Index] != 0) ? (GfxLibCalculateClk (PpFuseArray->DisplclkDid[Index], EffectiveMainPllFreq10KHz) / 100) : 0
390       );
391   }
392   for (Index = 0; Index < 6; Index++) {
393     IDS_HDT_CONSOLE (
394       NB_MISC,
395       "  SCLK DID[%d] - 0x%02x (%dMHz)\n",
396       Index,
397       PpFuseArray->SclkDpmDid[Index],
398       (PpFuseArray->SclkDpmDid[Index] != 0) ? (GfxLibCalculateClk (PpFuseArray->SclkDpmDid[Index], EffectiveMainPllFreq10KHz) / 100) : 0
399     );
400     IDS_HDT_CONSOLE (
401       NB_MISC,
402       "  SCLK TDP[%d] - 0x%x \n",
403       Index,
404       PpFuseArray->SclkDpmTdpLimit[Index]
405     );
406     IDS_HDT_CONSOLE (NB_MISC, "  SCLK VID[%d] - 0x%02x\n", Index, PpFuseArray->SclkDpmVid[Index]);
407   }
408   for (Index = 0; Index < 6; Index++) {
409     IDS_HDT_CONSOLE (NB_MISC, "  State #%d\n", Index);
410     IDS_HDT_CONSOLE (NB_MISC, "    Policy Label    - 0x%x\n", PpFuseArray->PolicyLabel[Index]);
411     IDS_HDT_CONSOLE (NB_MISC, "    Policy Flag     - 0x%x\n", PpFuseArray->PolicyFlags[Index]);
412     IDS_HDT_CONSOLE (NB_MISC, "    Valid SCLK      - 0x%x\n", PpFuseArray->SclkDpmValid[Index]);
413     IDS_HDT_CONSOLE (NB_MISC, "    Vclk/Dclk Index - 0x%x\n", PpFuseArray->VclkDclkSel[Index]);
414   }
415   IDS_HDT_CONSOLE (NB_MISC, "  GEN2 VID - 0x%x\n", PpFuseArray->PcieGen2Vid);
416   IDS_HDT_CONSOLE (NB_MISC, "  Main PLL Id - 0x%x\n", PpFuseArray->MainPllId);
417   IDS_HDT_CONSOLE (NB_MISC, "  GpuBoostCap  - %x\n", PpFuseArray->GpuBoostCap);
418   IDS_HDT_CONSOLE (NB_MISC, "  SclkDpmBoostMargin    - %x\n", PpFuseArray->SclkDpmBoostMargin);
419   IDS_HDT_CONSOLE (NB_MISC, "  SclkDpmThrottleMargin - %x\n", PpFuseArray->SclkDpmThrottleMargin);
420   IDS_HDT_CONSOLE (NB_MISC, "  SclkDpmTdpLimitPG     - %x\n", PpFuseArray->SclkDpmTdpLimitPG);
421   IDS_HDT_CONSOLE (
422     NB_MISC, "  SclkThermDid          - %x(%dMHz)\n",
423     PpFuseArray->SclkThermDid,
424     (PpFuseArray->SclkThermDid != 0) ? (GfxLibCalculateClk (PpFuseArray->SclkThermDid, EffectiveMainPllFreq10KHz) / 100) : 0
425     );
426   IDS_HDT_CONSOLE (NB_MISC, "<------------ GNB FUSE END-------------->\n");
427 }