blob: 76d7e518e0a7c587242b28741cff5f66733bed9a [file] [log] [blame]
zbao7d94cf92012-07-02 14:19:14 +08001/* $NoKeywords:$ */
2/**
3 * @file
4 *
5 * mpmaxfreq.c
6 *
7 * A sub-engine which extracts max. frequency limit value.
8 *
9 * @xrefitem bom "File Content Label" "Release Content"
10 * @e project: AGESA
11 * @e sub-project: (Mem/Ps)
12 * @e \$Revision: 63425 $ @e \$Date: 2011-12-22 11:24:10 -0600 (Thu, 22 Dec 2011) $
13 *
14 **/
15/*****************************************************************************
16*
Siyuan Wang641f00c2013-06-08 11:50:55 +080017 * Copyright (c) 2008 - 2012, Advanced Micro Devices, Inc.
18 * All rights reserved.
19 *
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions are met:
22 * * Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * * Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
27 * * Neither the name of Advanced Micro Devices, Inc. nor the names of
28 * its contributors may be used to endorse or promote products derived
29 * from this software without specific prior written permission.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
35 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
38 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
40 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
zbao7d94cf92012-07-02 14:19:14 +080041* ***************************************************************************
42*
43*/
44/*
45 *----------------------------------------------------------------------------
46 * MODULES USED
47 *
48 *----------------------------------------------------------------------------
49 */
50
51
52
53#include "AGESA.h"
54#include "AdvancedApi.h"
55#include "amdlib.h"
56#include "Ids.h"
57#include "cpuFamRegisters.h"
58#include "cpuRegisters.h"
59#include "OptionMemory.h"
60#include "PlatformMemoryConfiguration.h"
61#include "mu.h"
62#include "ma.h"
63#include "mp.h"
64#include "GeneralServices.h"
65#include "Filecode.h"
66CODE_GROUP (G2_PEI)
67RDATA_GROUP (G2_PEI)
68#define FILECODE PROC_MEM_PS_MPMAXFREQ_FILECODE
69
70
71/*----------------------------------------------------------------------------
72 * DEFINITIONS AND MACROS
73 *
74 *----------------------------------------------------------------------------
75 */
76
77/*----------------------------------------------------------------------------
78 * TYPEDEFS AND STRUCTURES
79 *
80 *----------------------------------------------------------------------------
81 */
82typedef struct {
83 UINT16 Dimms:4;
84 UINT16 SR:4;
85 UINT16 DR:4;
86 UINT16 QR:4;
87} CDNMaxFreq;
88
89typedef struct {
90 UINT16 Dimms:4;
91 UINT16 LR:12;
92} CDNLMaxFreq;
93/*----------------------------------------------------------------------------
94 * PROTOTYPES OF LOCAL FUNCTIONS
95 *
96 *----------------------------------------------------------------------------
97 */
98BOOLEAN
99MemPGetMaxFreqSupported (
100 IN OUT MEM_NB_BLOCK *NBPtr,
101 IN MEM_PSC_TABLE_BLOCK *EntryOfTables
102 );
103
104/*----------------------------------------------------------------------------
105 * EXPORTED FUNCTIONS
106 *
107 *----------------------------------------------------------------------------
108 */
109
110/* -----------------------------------------------------------------------------*/
111/**
112 *
113 * A sub-function which extracts the value of max frequency supported from a input table and
114 * compares it with DCTPtr->Timings.TargetSpeed
115 *
116 * @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
117 * @param[in] *EntryOfTables - Pointer to MEM_PSC_TABLE_BLOCK
118 *
119 * @return TRUE - Succeed in extracting the table value
120 * @return FALSE - Fail to extract the table value
121 *
122 */
123BOOLEAN
124MemPGetMaxFreqSupported (
125 IN OUT MEM_NB_BLOCK *NBPtr,
126 IN MEM_PSC_TABLE_BLOCK *EntryOfTables
127 )
128{
129 UINT8 i;
130 UINT8 MaxDimmSlotPerCh;
131 UINT8 MaxDimmPerCh;
132 UINT8 NOD;
133 UINT8 TableSize;
134 PSCFG_TYPE Type;
135 UINT16 CDN;
136 UINT16 MaxFreqSupported;
137 UINT16 *SpeedArray;
138 UINT8 DDR3Voltage;
139 UINT8 CurrentVoltage;
140 DIMM_TYPE DimmType;
141 CPU_LOGICAL_ID LogicalCpuid;
142 UINT8 PackageType;
143 BOOLEAN DisDct;
144 UINT8 PsoMaskMaxFreq;
145 UINT16 PsoMaskMaxFreq16;
146 UINT8 NumDimmSlotInTable;
147 UINT16 DimmPopInTable;
148 PSCFG_MAXFREQ_ENTRY *TblPtr;
149 CH_DEF_STRUCT *CurrentChannel;
150 PSC_TBL_ENTRY **TblEntryOfMaxFreq;
151
152 CurrentChannel = NBPtr->ChannelPtr;
153
154 DisDct = FALSE;
155 Type = PSCFG_MAXFREQ;
156 TblPtr = NULL;
157 TableSize = 0;
158 PackageType = 0;
159 NumDimmSlotInTable = 0;
160 DimmPopInTable = 0;
161 LogicalCpuid.Family = AMD_FAMILY_UNKNOWN;
162 SpeedArray = NULL;
163
164 MaxDimmPerCh = GetMaxDimmsPerChannel (NBPtr->RefPtr->PlatformMemoryConfiguration, NBPtr->MCTPtr->SocketId, CurrentChannel->ChannelID);
165 MaxDimmSlotPerCh = MaxDimmPerCh - GetMaxSolderedDownDimmsPerChannel (NBPtr->RefPtr->PlatformMemoryConfiguration,
166 NBPtr->MCTPtr->SocketId, CurrentChannel->ChannelID);
167
168 if (CurrentChannel->RegDimmPresent != 0) {
169 DimmType = RDIMM_TYPE;
170 } else if (CurrentChannel->SODimmPresent != 0) {
171 DimmType = SODIMM_TYPE;
172 } else if (CurrentChannel->LrDimmPresent != 0) {
173 DimmType = LRDIMM_TYPE;
174 } else {
175 DimmType = UDIMM_TYPE;
176 }
177
178 // Check if it is "SODIMM plus soldered-down DRAM" or "Soldered-down DRAM only" configuration,
179 // DimmType is changed to 'SODWN_SODIMM_TYPE' if soldered-down DRAM exist
180 if (MaxDimmSlotPerCh != MaxDimmPerCh) {
181 // SODIMM plus soldered-down DRAM
182 DimmType = SODWN_SODIMM_TYPE;
183 } else if (FindPSOverrideEntry (NBPtr->RefPtr->PlatformMemoryConfiguration, PSO_SOLDERED_DOWN_SODIMM_TYPE, NBPtr->MCTPtr->SocketId, NBPtr->ChannelPtr->ChannelID, 0, NULL, NULL) != NULL) {
184 // Soldered-down DRAM only
185 DimmType = SODWN_SODIMM_TYPE;
186 MaxDimmSlotPerCh = 0;
187 }
188 NOD = (UINT8) (MaxDimmSlotPerCh != 0) ? (1 << (MaxDimmSlotPerCh - 1)) : _DIMM_NONE;
189
190 TblEntryOfMaxFreq = EntryOfTables->TblEntryOfMaxFreq;
191 IDS_OPTION_HOOK (IDS_GET_STRETCH_FREQUENCY_LIMIT, &TblEntryOfMaxFreq, &NBPtr->MemPtr->StdHeader);
192
193 i = 0;
194 // Obtain table pointer, table size, Logical Cpuid and PSC type according to Dimm, NB and package type.
195 while (TblEntryOfMaxFreq[i] != NULL) {
196 if (((TblEntryOfMaxFreq[i])->Header.DimmType & DimmType) != 0) {
197 if (((TblEntryOfMaxFreq[i])->Header.NumOfDimm & NOD) != 0) {
198 //
199 // Determine if this is the expected NB Type
200 //
201 LogicalCpuid = (TblEntryOfMaxFreq[i])->Header.LogicalCpuid;
202 PackageType = (TblEntryOfMaxFreq[i])->Header.PackageType;
203 if (MemPIsIdSupported (NBPtr, LogicalCpuid, PackageType)) {
204 TblPtr = (PSCFG_MAXFREQ_ENTRY *) ((TblEntryOfMaxFreq[i])->TBLPtr);
205 TableSize = (TblEntryOfMaxFreq[i])->TableSize;
206 Type = (TblEntryOfMaxFreq[i])->Header.PSCType;
207 break;
208 }
209 }
210 }
211 i++;
212 }
213
214 // Check whether no table entry is found.
215 if (TblEntryOfMaxFreq[i] == NULL) {
216 IDS_HDT_CONSOLE (MEM_FLOW, "\nDCT %d: No MaxFreq table. This channel will be disabled.\n", NBPtr->Dct);
217 return FALSE;
218 }
219
220 MaxFreqSupported = UNSUPPORTED_DDR_FREQUENCY;
221 CDN = 0;
222 DDR3Voltage = (UINT8) CONVERT_VDDIO_TO_ENCODED (NBPtr->RefPtr->DDR3Voltage);
223
224 // Construct the condition value
225 ((CDNMaxFreq *)&CDN)->Dimms = CurrentChannel->Dimms;
226 if (Type == PSCFG_MAXFREQ) {
227 for (i = 0; i < MAX_DIMMS_PER_CHANNEL; i++) {
228 if ((CurrentChannel->DimmSRPresent & (UINT8) (1 << i)) != 0) {
229 ((CDNMaxFreq *)&CDN)->SR += 1;
230 }
231 if ((CurrentChannel->DimmDrPresent & (UINT16) (1 << i)) != 0) {
232 ((CDNMaxFreq *)&CDN)->DR += 1;
233 }
234 if ((CurrentChannel->DimmQrPresent & (UINT16) (1 << i)) != 0) {
235 if (i < 2) {
236 ((CDNMaxFreq *)&CDN)->QR += 1;
237 }
238 }
239 }
240 } else {
241 ((CDNLMaxFreq *)&CDN)->LR = CurrentChannel->Dimms;
242 }
243
244 for (i = 0; i < TableSize; i++) {
245 NumDimmSlotInTable = TblPtr->MAXFREQ_ENTRY.DimmSlotPerCh;
246 DimmPopInTable = (Type == PSCFG_MAXFREQ) ? TblPtr->MAXFREQ_ENTRY.CDN : ((PSCFG_LR_MAXFREQ_ENTRY *)TblPtr)->LR_MAXFREQ_ENTRY.CDN;
247 if (((NumDimmSlotInTable & NOD) != 0) && (CDN == DimmPopInTable)) {
248 if (Type == PSCFG_MAXFREQ) {
249 SpeedArray = TblPtr->MAXFREQ_ENTRY.Speed;
250 } else {
251 SpeedArray = ((PSCFG_LR_MAXFREQ_ENTRY *)TblPtr)->LR_MAXFREQ_ENTRY.Speed;
252 }
253 break;
254 }
255 TblPtr++;
256 }
257
258 PsoMaskMaxFreq16 = MemPProceedTblDrvOverride (NBPtr, NBPtr->RefPtr->PlatformMemoryConfiguration, PSO_TBLDRV_SPEEDLIMIT);
259 if ((PsoMaskMaxFreq16 & INVALID_CONFIG_FLAG) == 0) {
260 PsoMaskMaxFreq = (UINT8) PsoMaskMaxFreq16;
261 if (PsoMaskMaxFreq != 0) {
262 SpeedArray = NBPtr->PsPtr->SpeedLimit;
263 }
264 } else {
265 SpeedArray = NULL;
266 }
267
268 if (SpeedArray != NULL) {
269 if (NBPtr->SharedPtr->VoltageMap != VDDIO_DETERMINED) {
270 IDS_HDT_CONSOLE (MEM_FLOW, "\nCheck speed supported for each VDDIO for Node%d DCT%d: ", NBPtr->Node, NBPtr->Dct);
271 for (CurrentVoltage = VOLT1_5_ENCODED_VAL; CurrentVoltage <= VOLT1_25_ENCODED_VAL; CurrentVoltage ++) {
272 if (NBPtr->SharedPtr->VoltageMap & (1 << CurrentVoltage)) {
273 IDS_HDT_CONSOLE (MEM_FLOW, "%s -> %dMHz ", (CurrentVoltage == VOLT1_5_ENCODED_VAL) ? "1.5V" : ((CurrentVoltage == VOLT1_35_ENCODED_VAL) ? "1.35V" : "1.25V"), SpeedArray[CurrentVoltage]);
274 if (NBPtr->DCTPtr->Timings.TargetSpeed > SpeedArray[CurrentVoltage]) {
275 MaxFreqSupported = SpeedArray[CurrentVoltage];
276 } else {
277 MaxFreqSupported = NBPtr->DCTPtr->Timings.TargetSpeed;
278 }
279 if (NBPtr->MaxFreqVDDIO[CurrentVoltage] > MaxFreqSupported) {
280 NBPtr->MaxFreqVDDIO[CurrentVoltage] = MaxFreqSupported;
281 }
282 } else {
283 NBPtr->MaxFreqVDDIO[CurrentVoltage] = 0;
284 }
285 }
286 IDS_HDT_CONSOLE (MEM_FLOW, "\n");
287 }
288 ASSERT (DDR3Voltage <= VOLT1_25_ENCODED_VAL);
Martin Rothfecc24a2016-01-06 21:18:21 -0700289 if (DDR3Voltage > VOLT1_25_ENCODED_VAL)
290 DDR3Voltage = VOLT1_5_ENCODED_VAL; // if unknown, fall back to 1.5v
zbao7d94cf92012-07-02 14:19:14 +0800291 MaxFreqSupported = SpeedArray[DDR3Voltage];
292 }
293
294 if (MaxFreqSupported == UNSUPPORTED_DDR_FREQUENCY) {
295 // No entry in the table for current dimm population is found
296 IDS_HDT_CONSOLE (MEM_FLOW, "\nDCT %d: No entry is found in the Max Frequency table\n", NBPtr->Dct);
297 DisDct = TRUE;
298 } else if (MaxFreqSupported != 0) {
299 if (NBPtr->DCTPtr->Timings.TargetSpeed > MaxFreqSupported) {
300 NBPtr->DCTPtr->Timings.TargetSpeed = MaxFreqSupported;
301 }
302 } else if (NBPtr->SharedPtr->VoltageMap == VDDIO_DETERMINED) {
303 // Dimm population is not supported at current voltage
304 // Also if there is no performance optimization, disable the DCT
305 DisDct = TRUE;
306 }
307
308 if (DisDct) {
309 NBPtr->DCTPtr->Timings.DimmExclude |= NBPtr->DCTPtr->Timings.DctDimmValid;
310 PutEventLog (AGESA_ERROR, MEM_ERROR_UNSUPPORTED_DIMM_CONFIG, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, 0, &NBPtr->MemPtr->StdHeader);
311 SetMemError (AGESA_ERROR, NBPtr->MCTPtr);
312 // Change target speed to highest value so it won't affect other channels when leveling frequency across the node.
313 NBPtr->DCTPtr->Timings.TargetSpeed = UNSUPPORTED_DDR_FREQUENCY;
314 }
315
316 return TRUE;
317}