blob: e7ff2eaab21fb406bd89be3f713679d1f32850e5 [file] [log] [blame]
Frank Vibrans2b4c8312011-02-14 18:30:54 +00001
2/**
3 * @file
4 *
5 * Config Southbridge GPP controller
6 *
7 * Init GPP features.
8 *
9 * @xrefitem bom "File Content Label" "Release Content"
10 * @e project: CIMx-SB
11 * @e sub-project
12 * @e \$Revision:$ @e \$Date:$
13 *
14 */
15/*
16 *****************************************************************************
17 *
18 * Copyright (c) 2011, Advanced Micro Devices, Inc.
19 * All rights reserved.
Edward O'Callaghanef5981b2014-07-06 19:20:52 +100020 *
Frank Vibrans2b4c8312011-02-14 18:30:54 +000021 * 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.
Edward O'Callaghanef5981b2014-07-06 19:20:52 +100028 * * Neither the name of Advanced Micro Devices, Inc. nor the names of
29 * its contributors may be used to endorse or promote products derived
Frank Vibrans2b4c8312011-02-14 18:30:54 +000030 * from this software without specific prior written permission.
Edward O'Callaghanef5981b2014-07-06 19:20:52 +100031 *
Frank Vibrans2b4c8312011-02-14 18:30:54 +000032 * 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.
Edward O'Callaghanef5981b2014-07-06 19:20:52 +100042 *
Frank Vibrans2b4c8312011-02-14 18:30:54 +000043 * ***************************************************************************
44 *
45 */
Edward O'Callaghanef5981b2014-07-06 19:20:52 +100046
Frank Vibrans2b4c8312011-02-14 18:30:54 +000047#include "SBPLATFORM.h"
48#include "cbtypes.h"
49
50/**
51 * PCIE_CAP_ID - PCIe Cap ID
52 *
53 */
54#define PCIE_CAP_ID 0x10
55
56//
57// Declaration of local functions
58//
59
60/**
61 * PreInitGppLink - Enable GPP link training.
62 *
63 * @param[in] pConfig Southbridge configuration structure pointer.
64 *
65 */
66 VOID PreInitGppLink (IN AMDSBCFG* pConfig);
67 UINT8 CheckGppLinkStatus (IN AMDSBCFG* pConfig);
68 VOID AfterGppLinkInit (IN AMDSBCFG* pConfig);
69 VOID sbGppForceGen2 (IN UINT32 portId );
70 VOID sbGppForceGen1 (IN UINT32 portId );
71 VOID sbGppDisableUnusedPadMap (IN AMDSBCFG* pConfig );
72 VOID sbGppSetAspm (IN UINT32 pciAddress, IN UINT8 LxState);
73 UINT8 sbFindPciCap (IN UINT32 pciAddress, IN UINT8 targetCapId);
74
75//
76// Declaration of external functions
77//
78
79//
80//-----------------------------------------------------------------------------------
81// Early SB800 GPP initialization sequence:
82//
83// 1) Set port enable bit fields by current GPP link configuration mode
84// 2) Deassert GPP reset and pull EP out of reset - Clear GPP_RESET (abcfg:0xC0[8] = 0)
85// 3) Loop polling for the link status of all ports
86// 4) Misc operations after link training:
87// - (optional) Detect GFX device
88// - Hide empty GPP configuration spaces (Disable empty GPP ports)
89// - (optional) Power down unused GPP ports
90// - (optional) Configure PCIE_P2P_Int_Map (abcfg:0xC4[7:0])
91// 5) GPP init completed
92//
93//
94// *) Gen2 vs Gen1
95// Gen2 mode Gen1 mode
96// ---------------------------------------------------------------
97// STRAP_PHY_PLL_CLKF[6:0] 7'h32 7'h19
98// STRAP_BIF_GEN2_EN 1 0
99//
100// PCIE_PHY_PLL clock locks @ 5GHz
101//
102//
103
104/**
105 * GPP early programming and link training. On exit all populated EPs should be fully operational.
106 *
107 *
108 *
109 * @param[in] pConfig Southbridge configuration structure pointer.
110 *
111 */
112VOID
113sbPcieGppEarlyInit (
114 IN AMDSBCFG* pConfig
115 )
116{
117 UINT8 TogglePort;
118 UINT8 portNum;
119 UINT32 reg32Value;
120 UINT8 retryCount;
121 UINT8 cimGppMemWrImprove;
122 UINT8 cimGppLaneReversal;
123 UINT8 cimAlinkPhyPllPowerDown;
124
125 cimGppMemWrImprove = pConfig->GppMemWrImprove;
126 cimGppLaneReversal = (UINT8) pConfig->GppLaneReversal;
127 cimAlinkPhyPllPowerDown = (UINT8) pConfig->AlinkPhyPllPowerDown;
128#if SB_CIMx_PARAMETER == 0
129 cimGppMemWrImprove = cimGppMemWrImproveDefault;
130 cimGppLaneReversal = cimGppLaneReversalDefault;
131 cimAlinkPhyPllPowerDown = cimAlinkPhyPllPowerDownDefault;
132#endif
133
134//
135// Configure NB-SB link PCIE PHY PLL power down for L1
136//
137 if ( cimAlinkPhyPllPowerDown == TRUE ) {
138 UINT32 abValue;
139 // Set PCIE_P_CNTL in Alink PCIEIND space
Paul Menzel4715c622021-03-05 01:22:29 +0100140 writeAlink (SB_AX_INDXC_REG30 | ((UINT32) AXINDC << 29), 0x40);
141 abValue = readAlink (SB_AX_DATAC_REG34 | ((UINT32) AXINDC << 29));
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000142 abValue |= BIT12 + BIT3 + BIT0;
143 abValue &= ~(BIT9 + BIT4);
Paul Menzel4715c622021-03-05 01:22:29 +0100144 writeAlink (SB_AX_DATAC_REG34 | ((UINT32) AXINDC << 29), abValue);
145 rwAlink (SB_AX_INDXC_REG02 | ((UINT32) AXINDC << 29), ~BIT8, (BIT8));
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000146 }
147
148//
149// Set ABCFG 0x031C[0] = 1 enable the lane reversal support.
150//
Paul Menzel4715c622021-03-05 01:22:29 +0100151 reg32Value = readAlink (SB_ABCFG_REG31C | ((UINT32) ABCFG << 29));
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000152 if ( cimGppLaneReversal ) {
Paul Menzel4715c622021-03-05 01:22:29 +0100153 writeAlink (SB_ABCFG_REG31C | ((UINT32) ABCFG << 29), reg32Value | BIT0);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000154 } else {
Paul Menzel4715c622021-03-05 01:22:29 +0100155 writeAlink (SB_ABCFG_REG31C | ((UINT32) ABCFG << 29), reg32Value | 0x00);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000156 }
157//
158// Set abcfg:0x90[20] = 1 to enable GPP bridge multi-function
159//
Paul Menzel4715c622021-03-05 01:22:29 +0100160 reg32Value = readAlink (SB_ABCFG_REG90 | ((UINT32) ABCFG << 29));
161 writeAlink (SB_ABCFG_REG90 | ((UINT32) ABCFG << 29), reg32Value | BIT20);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000162
163
164//
165// Initialize and configure GPP
166//
167 if (pConfig->GppFunctionEnable) {
168 // PreInit - Enable GPP link training
169 PreInitGppLink (pConfig);
170
171//
172// GPP Upstream Memory Write Arbitration Enhancement ABCFG 0x54[26] = 1
173// GPP Memory Write Max Payload Improvement RCINDC_Reg 0x10[12:10] = 0x4
174//
175 if ( cimGppMemWrImprove == TRUE ) {
Paul Menzel4715c622021-03-05 01:22:29 +0100176 rwAlink (SB_ABCFG_REG54 | ((UINT32) ABCFG << 29), ~BIT26, (BIT26));
177 rwAlink (SB_RCINDXC_REG10 | ((UINT32) RCINDXC << 29), ~(BIT12 + BIT11 + BIT10), (BIT12));
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000178 }
179
180 if ( pConfig->S3Resume ) {
181 for ( portNum = 0; portNum < MAX_GPP_PORTS; portNum++ ) {
Paul Menzel4715c622021-03-05 01:22:29 +0100182 reg32Value = readAlink ((SB_ABCFG_REG340 + portNum * 4) | ((UINT32) ABCFG << 29));
183 writeAlink ((SB_ABCFG_REG340 + portNum * 4) | ((UINT32) ABCFG << 29), reg32Value & ~BIT21);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000184 }
185 }
186 //
187 // a) Loop polling regA5 -> LcState (timeout ~100ms);
188 // b) if (LcState[5:0] == 0x10), training successful, go to g);
189 // c) if any of (LcState[13:8], [21:16], [29:24]) == 0x29 or 0x2A:
190 // d) Clear De-emphasis bit for relevant ports;
191 // e) Toggle GPP reset signal (via OEM callback);
192 // f) go back to a);
193 // g) exit;
194 //
195 for (retryCount = 0; retryCount < MAX_GPP_RESETS; retryCount++) {
196 // Polling each GPP port for link status
197 TogglePort = CheckGppLinkStatus (pConfig);
198
199 if (TogglePort == 0) {
200 break;
201 } else {
202 // Check failure port and clear STRAP_BIF_DE_EMPHASIS_SEL_x_GPP bit (abcfg:0x34[0, 4, 8, C][21]=0)
203 for ( portNum = 0; portNum < MAX_GPP_PORTS; portNum++ ) {
204 if (TogglePort & (1 << portNum)) {
Paul Menzel4715c622021-03-05 01:22:29 +0100205 reg32Value = readAlink ((SB_ABCFG_REG340 + portNum * 4) | ((UINT32) ABCFG << 29));
206 writeAlink ((SB_ABCFG_REG340 + portNum * 4) | ((UINT32) ABCFG << 29), reg32Value & ~BIT21);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000207 }
208 sbGppForceGen1 (portNum);
209 }
210
211 // Toggle GPP reset (Note this affects all SB800 GPP ports)
212 CallBackToOEM (CB_SBGPP_RESET_ASSERT, (UINT32)TogglePort, pConfig);
213 SbStall (500);
214 CallBackToOEM (CB_SBGPP_RESET_DEASSERT, (UINT32)TogglePort, pConfig);
215 }
216 };
217
218 // Misc operations after link training
219 AfterGppLinkInit (pConfig);
220 } else {
221
222// RPR 5.11 Power Saving With GPP Disable
223// ABCFG 0xC0[8] = 0x0
224// ABCFG 0xC0[15:12] = 0xF
225// Enable "Power Saving Feature for A-Link Express Lanes"
226// Enable "Power Saving Feature for GPP Lanes"
227// ABCFG 0x90[19] = 1
228// ABCFG 0x90[6] = 1
229// RCINDC_Reg 0x65 [27:0] = 0xFFFFFFF
230// ABCFG 0xC0[7:4] = 0x0
231
Paul Menzel4715c622021-03-05 01:22:29 +0100232 rwAlink (SB_ABCFG_REGC0 | ((UINT32) ABCFG << 29), ~BIT8, (BIT4 + BIT5 + BIT6 + BIT7));
233 rwAlink (SB_ABCFG_REGC0 | ((UINT32) ABCFG << 29), 0xFFFFFFFF, (BIT12 + BIT13 + BIT14 + BIT15));
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000234 rwAlink (SB_AX_INDXC_REG40, ~(BIT9 + BIT4), (BIT0 + BIT3 + BIT12));
235 rwAlink (RC_INDXC_REG40, ~(BIT9 + BIT4), (BIT0 + BIT3 + BIT12));
Paul Menzel4715c622021-03-05 01:22:29 +0100236 rwAlink ((SB_ABCFG_REG90 | ((UINT32) ABCFG << 29)), 0xFFFFFFFF, (BIT6 + BIT19));
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000237 rwAlink (RC_INDXC_REG65, 0xFFFFFFFF, 0x0fffffff);
Paul Menzel4715c622021-03-05 01:22:29 +0100238 rwAlink ((SB_ABCFG_REGC0 | ((UINT32) ABCFG << 29)), ~(BIT4 + BIT5 + BIT6 + BIT7), 0);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000239 }
240 sbGppDisableUnusedPadMap ( pConfig );
241}
242
243/**
244 * PreInitGppLink - Enable GPP link training.
245 *
246 *
247 *
248 * @param[in] pConfig Southbridge configuration structure pointer.
249 *
250 */
251VOID
252PreInitGppLink (
253 IN AMDSBCFG* pConfig
254 )
255{
256 UINT8 portMask[5] = {0x01,
257 0x00,
258 0x03,
259 0x07,
260 0x0F
261 };
262 UINT8 cfgMode;
263 UINT8 portId;
264 UINT32 reg32Value;
265 UINT16 tmp16Value;
266
267// PCIE_GPP_ENABLE (abcfg:0xC0):
268//
269// GPP_LINK_CONFIG ([3:0]) PortA PortB PortC PortD Description
270// ----------------------------------------------------------------------------------
271// 0000 0-3 x4 Config
272// 0001 N/A
273// 0010 0-1 2-3 0 2:2 Config
274// 0011 0-1 2 3 2:1:1 Config
275// 0100 0 1 2 3 1:1:1:1 Config
276//
277// For A12 and above:
278// ABCFG:0xC0[12] - Port A hold training (default 1)
279// ABCFG:0xC0[13] - Port B hold training (default 1)
280// ABCFG:0xC0[14] - Port C hold training (default 1)
281// ABCFG:0xC0[15] - Port D hold training (default 1)
282//
283//
284 //
285 // Set port enable bit fields based on current GPP link configuration mode
286 //
287 cfgMode = (UINT8) pConfig->GppLinkConfig;
288 if ( cfgMode > GPP_CFGMODE_X1111 || cfgMode == 1 ) {
289 cfgMode = GPP_CFGMODE_X4000;
290 pConfig->GppLinkConfig = GPP_CFGMODE_X4000;
291 }
292 reg32Value = (UINT32) portMask[cfgMode];
293
294 // Mask out non-applicable ports according to the target link configuration mode
295 for ( portId = 0; portId < MAX_GPP_PORTS; portId++ ) {
Kyösti Mälkki8dba7092015-02-07 07:07:16 +0200296 if (!(reg32Value & (1 << portId)))
297 pConfig->PORTCONFIG[portId].PortCfg.PortPresent = false;
298 else if (!pConfig->PORTCONFIG[portId].PortCfg.PortPresent)
299 reg32Value &= ~(1 << portId);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000300 }
301
302 //
303 // Deassert GPP reset and pull EP out of reset - Clear GPP_RESET (abcfg:0xC0[8] = 0)
304 //
305 tmp16Value = (UINT16) (~reg32Value << 12);
306 reg32Value = (UINT32) (tmp16Value + (reg32Value << 4) + cfgMode);
Paul Menzel4715c622021-03-05 01:22:29 +0100307 writeAlink (SB_ABCFG_REGC0 | ((UINT32) ABCFG << 29), reg32Value);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000308
Paul Menzel4715c622021-03-05 01:22:29 +0100309 reg32Value = readAlink (0xC0 | ((UINT32) RCINDXC << 29));
310 writeAlink (0xC0 | ((UINT32) RCINDXC << 29), reg32Value | 0x400); // Set STRAP_F0_MSI_EN
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000311
312 // A-Link L1 Entry Delay Shortening
313 // AXINDP_Reg 0xA0[7:4] = 0x3
314 rwAlink (SB_AX_INDXP_REGA0, 0xFFFFFF0F, 0x30);
315 rwAlink (SB_AX_INDXP_REGB1, 0xFFFFFFFF, BIT19);
316 rwAlink (SB_AX_INDXP_REGB1, 0xFFFFFFFF, BIT28);
317
318 // RPR5.22 GPP L1 Entry Delay Shortening
319 // RCINDP_Reg 0xA0[7:4] = 0x1 Enter L1 sooner after ACK'ing PM request.
320 // This is done to reduce number of NAK received with L1 enabled.
321 for ( portId = 0; portId < MAX_GPP_PORTS; portId++ ) {
322 rwAlink (SB_RCINDXP_REGA0 | portId << 24, 0xFFFFFF0F, 0x10);
323 }
324}
325
326/**
327 * CheckGppLinkStatus - loop polling the link status for each GPP port
328 *
329 *
330 * Return: ToggleStatus[3:0] = Port bitmap for those need to clear De-emphasis
331 *
332 * @param[in] pConfig Southbridge configuration structure pointer.
333 *
334 */
335UINT8
336CheckGppLinkStatus (
337 IN AMDSBCFG* pConfig
338 )
339{
340 UINT32 retryCounter;
341 UINT32 portId;
342 UINT32 abIndex;
343 UINT32 Data32;
344 UINT8 portScanMap;
345 UINT8 portScanMap2;
346 UINT8 ToggleStatus;
347 UINT16 i;
348 SBGPPPORTCONFIG *portCfg;
349
350
351 portScanMap = 0;
352 retryCounter = MAX_TRAINING_RETRY;
353 ToggleStatus = 0;
354
355 // Obtain a list of ports to be checked
356 for ( portId = 0; portId < MAX_GPP_PORTS; portId++ ) {
357 portCfg = &pConfig->PORTCONFIG[portId].PortCfg;
358 if ( portCfg->PortPresent == TRUE && portCfg->PortDetected == FALSE ) {
359 portScanMap |= 1 << portId;
360 }
361 }
362 portScanMap2 = portScanMap;
363
364 //
365 // After training is enabled, Check LCSTATE for each port, if LCSTATE<= 4, then keep
366 // polling for up to 40ms. If LCSTATE still <= 4, then assume the port to be empty.
367 //
368 i = 400;
369 while ( --i && portScanMap2) {
370 for (portId = 0; portId < MAX_GPP_PORTS; portId++) {
371 portCfg = &pConfig->PORTCONFIG[portId].PortCfg;
372 if (((portCfg->PortHotPlug == FALSE) || ((portCfg->PortHotPlug == TRUE) && (pConfig->S3Resume == FALSE)) ) && (portScanMap2 & (1 << portId))) {
373 //
374 // Get port link state (reading LC_CURRENT_STATE of PCIEIND_P)
375 //
Paul Menzel4715c622021-03-05 01:22:29 +0100376 abIndex = SB_RCINDXP_REGA5 | ((UINT32) RCINDXP << 29) | (portId << 24);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000377 Data32 = readAlink (abIndex) & 0x3F;
378 if ((UINT8) (Data32) > 4) {
379 portScanMap2 &= ~(1 << portId); // This port is not empty
380 break;
381 }
382 SbStall (100); // Delay 100us
383 }
384 }
385 }
386 portScanMap &= ~portScanMap2; // Mark remaining ports as empty
387
388
389 while ( --retryCounter && portScanMap ) {
390 for ( portId = 0; portId < MAX_GPP_PORTS; portId++ ) {
391 portCfg = &pConfig->PORTCONFIG[portId].PortCfg;
392 if (( portCfg->PortHotPlug == TRUE ) && ( pConfig->S3Resume )) {
393 continue;
394 }
395 if ( portCfg->PortPresent == TRUE && portCfg->PortDetected == FALSE ) {
396 //
397 // Get port link state (reading LC_CURRENT_STATE of PCIEIND_P)
398 //
399 SbStall (1000); // Delay 400us
Paul Menzel4715c622021-03-05 01:22:29 +0100400 abIndex = SB_RCINDXP_REGA5 | ((UINT32) RCINDXP << 29) | (portId << 24);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000401 Data32 = readAlink (abIndex) & 0x3F3F3F3F;
402
403 if ( (UINT8) (Data32) == 0x10 ) {
404 portCfg->PortDetected = TRUE;
405 portScanMap &= ~(1 << portId);
406 } else {
407 for (i = 0; i < 4; i++) {
408 //
409 // Compliance mode (0x7), downgrade from Gen2 to Gen1 (*A12)
410 //
411 if ((UINT8) (Data32) == 0x29 || (UINT8) (Data32) == 0x2A || (UINT8) (Data32) == 0x7 ) {
412 ToggleStatus |= (1 << portId); // A11 only: need to toggle GPP reset
413 portScanMap &= ~(1 << portId);
414 }
415 Data32 >>= 8;
416 }
417 }
418 }
419 }
420 }
421 return ToggleStatus;
422}
423
424
425/**
426 * AfterGppLinkInit
427 * - Search for display device behind each GPP port
428 * - If the port is empty AND not hotplug-capable:
429 * * Turn off link training
430 * * (optional) Power down the port
431 * * Hide the configuration space (Turn off the port)
432 *
433 * @param[in] pConfig Southbridge configuration structure pointer.
434 *
435 */
436VOID
437AfterGppLinkInit (
438 IN AMDSBCFG* pConfig
439 )
440{
441 UINT32 portId;
442 SBGPPPORTCONFIG *portCfg;
443 UINT32 regBusNumber;
444 UINT32 abValue;
445 UINT32 abIndex;
446 UINT32 i;
447 UINT32 Data32;
448 UINT8 bValue;
449 UINT8 cimGppGen2;
450
451 cimGppGen2 = pConfig->GppGen2;
452#if SB_CIMx_PARAMETER == 0
453 cimGppGen2 = cimGppGen2Default;
454#endif
455
456 bValue = GPP_EFUSE_LOCATION;
457 getEfuseStatus (&bValue);
458 if ( (bValue & GPP_GEN2_EFUSE_BIT) != 0 ) {
459 cimGppGen2 = FALSE;
460 } else {
461 pConfig->CoreGen2Enable = TRUE; // Output for platform use
462 }
463
464//GPP Gen2 Speed Change
465// if ((GPP Gen2 == enabled) and (RCINDP_Reg 0xA4[0] == 0x1)) {
466// PCIe_Cfg 0x88[3:0] = 0x2
467// RCINDP_Reg 0xA2[13] = 0x0
468// RCINDP_Reg 0xC0[15] = 0x0
469// RCINDP_Reg 0xA4[29] = 0x1
470// } else {
471// PCIe_Cfg 0x88[3:0] = 0x1
472// RCINDP_Reg 0xA4[0] = 0x0
473// RCINDP_Reg 0xA2[13] = 0x1
474// RCINDP_Reg 0xC0[15] = 0x0
475// RCINDP_Reg 0xA4[29] = 0x1
476// }
477 for ( portId = 0; portId < MAX_GPP_PORTS; portId++ ) {
478 portCfg = &pConfig->PORTCONFIG[portId].PortCfg;
479 abValue = readAlink (SB_RCINDXP_REGA4 | portId << 24) & BIT0;
480 if (( cimGppGen2 == TRUE ) && (abValue == BIT0) && (portCfg->PortDetected == TRUE)) {
481 portCfg->PortIsGen2 = TRUE; // Output for platform use
482 sbGppForceGen2 (portId);
483 //_asm {jmp $};
484 SbStall (400); // Delay 400us
485 i = 500;
486 Data32 = 0;
487 while ( --i ) {
Paul Menzel4715c622021-03-05 01:22:29 +0100488 abIndex = SB_RCINDXP_REGA5 | ((UINT32) RCINDXP << 29) | (portId << 24);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000489 Data32 = readAlink (abIndex) & 0x3F;
490 if ((UINT8) (Data32) == 0x10) {
491 break;
492 }
493 SbStall (400); // Delay 100us
494 }
495 if (!( (UINT8) (Data32) == 0x10 )) {
496 if (pConfig->GppCompliance == FALSE) {
497 portCfg->PortIsGen2 = FALSE; // Revert to default; output for platform use
498 sbGppForceGen1 (portId);
499 }
500 }
501 } else {
502 if (pConfig->GppCompliance == FALSE) {
503 sbGppForceGen1 (portId);
504 }
505 }
506//RPR 5.9 Link Bandwidth Notification Capability Enable
507//RCINDC 0xC1[0] = 1
508//PCIe Cfg 0x68[10] = 0
509//PCIe Cfg 0x68[11] = 0
510
511 rwAlink (SB_RCINDXC_REGC1, 0xFFFFFFFF, BIT0);
512 RWPCI (PCI_ADDRESS (0, GPP_DEV_NUM, portId, 0x68), AccWidthUint16, ~(BIT10 + BIT11), 0);
513 }
514
515// Status = AGESA_SUCCESS;
516 pConfig->GppFoundGfxDev = 0;
Paul Menzel4715c622021-03-05 01:22:29 +0100517 abValue = readAlink (SB_ABCFG_REGC0 | ((UINT32) ABCFG << 29));
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000518
519 for ( portId = 0; portId < MAX_GPP_PORTS; portId++ ) {
520 portCfg = &pConfig->PORTCONFIG[portId].PortCfg;
521 // Check if there is GFX device behind each GPP port
522 if ( portCfg->PortDetected == TRUE ) {
523 regBusNumber = (SBTEMP_BUS << 16) + (SBTEMP_BUS << 8);
524 WritePCI (PCI_ADDRESS (0, GPP_DEV_NUM, portId, 0x18), AccWidthUint32, &regBusNumber);
525 // *** Stall ();
526 ReadPCI (PCI_ADDRESS (SBTEMP_BUS, 0, 0, 0x0B), AccWidthUint8, &bValue);
527 if ( bValue == 3 ) {
528 pConfig->GppFoundGfxDev |= (1 << portId);
529 }
530 regBusNumber = 0;
531 WritePCI (PCI_ADDRESS (0, GPP_DEV_NUM, portId, 0x18), AccWidthUint32, &regBusNumber);
532 }
533
534 // Mask off non-applicable ports
535 else if ( portCfg->PortPresent == FALSE ) {
536 abValue &= ~(1 << (portId + 4));
537 }
538 // Mask off empty port if the port is not hotplug-capable
539 else if ( portCfg->PortHotPlug == FALSE ) {
540 abValue &= ~(1 << (portId + 4));
541 }
542 // Clear STRAP_BIF_DE_EMPHASIS_SEL_x_GPP bit (abcfg:0x34[0, 4, 8, C][21]=0) to make hotplug working
543 if ( portCfg->PortHotPlug == TRUE ) {
Paul Menzel4715c622021-03-05 01:22:29 +0100544 rwAlink ((SB_ABCFG_REG340 + portId * 4) | ((UINT32) ABCFG << 29), ~BIT21, 0);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000545
546// RPR5.12 Hot Plug: PCIe Native Support
547// RCINDP_Reg 0x10[3] = 0x1
548// PCIe_Cfg 0x5A[8] = 0x1
549// PCIe_Cfg 0x6C[6] = 0x1
550// RCINDP_Reg 0x20[19] = 0x0
551
Paul Menzel4715c622021-03-05 01:22:29 +0100552 rwAlink ((SB_RCINDXP_REG10 | ((UINT32) RCINDXP << 29) | (portId << 24)), 0xFFFFFFFF, BIT3);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000553 RWPCI (PCI_ADDRESS (0, GPP_DEV_NUM, portId, 0x5b), AccWidthUint8, 0xff, BIT0);
554 RWPCI (PCI_ADDRESS (0, GPP_DEV_NUM, portId, 0x6c), AccWidthUint8, 0xff, BIT6);
Paul Menzel4715c622021-03-05 01:22:29 +0100555 rwAlink ((SB_RCINDXP_REG20 | ((UINT32) RCINDXP << 29) | (portId << 24)), ~BIT19, 0);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000556 }
557 }
558 if ( pConfig->GppUnhidePorts == FALSE ) {
559 if ((abValue & 0xF0) == 0) {
560 abValue = BIT8; // if all ports are empty set GPP_RESET
561 } else if ((abValue & 0xE0) != 0 && (abValue & 0x10) == 0) {
562 abValue |= BIT4; // PortA should always be visible whenever other ports are exist
563 }
564
565 // Update GPP_Portx_Enable (abcfg:0xC0[7:5])
Paul Menzel4715c622021-03-05 01:22:29 +0100566 writeAlink (SB_ABCFG_REGC0 | ((UINT32) ABCFG << 29), abValue);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000567 }
568
569 //
570 // Common initialization for open GPP ports
571 //
572 for ( portId = 0; portId < MAX_GPP_PORTS; portId++ ) {
573 ReadPCI (PCI_ADDRESS (0, GPP_DEV_NUM, portId, 0x80), AccWidthUint8, &bValue);
574 if (bValue != 0xff) {
575 // Set pciCfg:PCIE_DEVICE_CNTL2[3:0] = 4'h6 (0x80[3:0])
576 bValue &= 0xf0;
577 bValue |= 0x06;
578 WritePCI (PCI_ADDRESS (0, GPP_DEV_NUM, portId, 0x80), AccWidthUint8, &bValue);
579
580 // Set PCIEIND_P:PCIE_RX_CNTL[RX_RCB_CPL_TIMEOUT_MODE] (0x70:[19]) = 1
Paul Menzel4715c622021-03-05 01:22:29 +0100581 abIndex = SB_RCINDXP_REG70 | ((UINT32) RCINDXP << 29) | (portId << 24);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000582 abValue = readAlink (abIndex) | BIT19;
583 writeAlink (abIndex, abValue);
584
585 // Set PCIEIND_P:PCIE_TX_CNTL[TX_FLUSH_TLP_DIS] (0x20:[19]) = 0
Paul Menzel4715c622021-03-05 01:22:29 +0100586 abIndex = SB_RCINDXP_REG20 | ((UINT32) RCINDXP << 29) | (portId << 24);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000587 abValue = readAlink (abIndex) & ~BIT19;
588 writeAlink (abIndex, abValue);
589
590 }
591 }
592}
593
594
595/**
596 * sbPcieGppLateInit - Late PCIE initialization for SB800 GPP component
597 *
598 *
599 * @param[in] pConfig Southbridge configuration structure pointer.
600 *
601 */
602VOID
603sbPcieGppLateInit (
604 IN AMDSBCFG* pConfig
605 )
606{
607 UINT32 reg32Value;
608 UINT8 portId;
609 UINT8 busNum;
610 UINT8 aspmValue;
611 UINT8 reg8Value;
612 UINT8 cimGppPhyPllPowerDown;
613
614 reg8Value = 0x01;
615//
616// Configure ASPM
617//
Paul Menzel4715c622021-03-05 01:22:29 +0100618// writeAlink (0xC0 | ((UINT32) RCINDXC << 29), 0x400); // Set STRAP_F0_MSI_EN
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000619 aspmValue = (UINT8)pConfig->GppPortAspm;
620 cimGppPhyPllPowerDown = (UINT8) pConfig->GppPhyPllPowerDown;
621#if SB_CIMx_PARAMETER == 0
622 aspmValue = cimGppPortAspmDefault;
623 cimGppPhyPllPowerDown = cimGppPhyPllPowerDownDefault;
624#endif
625
626 for ( portId = 0; portId < MAX_GPP_PORTS; portId++ ) {
627 // write pci_reg3d with 0x01 to fix yellow mark for GPP bridge under Vista
628 // when native PCIE is enabled but MSI is not available
629 // SB02029: SB800 BIF/GPP allowing strap STRAP_BIF_INTERRUPT_PIN_SB controlled by AB reg
630 WritePCI (PCI_ADDRESS (0, 21, portId, 0x3d), AccWidthUint8, &reg8Value);
631 ReadPCI (PCI_ADDRESS (0, 21, portId, 0x19), AccWidthUint8, &busNum);
632 if (busNum != 0xFF) {
633 ReadPCI (PCI_ADDRESS (busNum, 0, 0, 0x00), AccWidthUint32, &reg32Value);
634 if (reg32Value != 0xffffffff) {
635 // Set ASPM on EP side
636 sbGppSetAspm (PCI_ADDRESS (busNum, 0, 0, 0), aspmValue & 0x3);
637 // Set ASPM on port side
638 sbGppSetAspm (PCI_ADDRESS (0, 21, portId, 0), aspmValue & 0x3);
639 }
640 }
641 aspmValue = aspmValue >> 2;
642 }
643
644//
645// Configure Lock HWInit registers
646//
Paul Menzel4715c622021-03-05 01:22:29 +0100647 reg32Value = readAlink (SB_ABCFG_REGC0 | ((UINT32) ABCFG << 29));
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000648 if (reg32Value & 0xF0) {
Paul Menzel4715c622021-03-05 01:22:29 +0100649 reg32Value = readAlink (SB_RCINDXC_REG10 | ((UINT32) RCINDXC << 29));
650 writeAlink (SB_RCINDXC_REG10 | ((UINT32) RCINDXC << 29), reg32Value | BIT0); // Set HWINIT_WR_LOCK
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000651
652 if ( cimGppPhyPllPowerDown == TRUE ) {
653//
654// RPR 5.4 Power Saving Feature for GPP Lanes
655//
656 UINT32 abValue;
657 // Set PCIE_P_CNTL in Alink PCIEIND space
Paul Menzel4715c622021-03-05 01:22:29 +0100658 abValue = readAlink (RC_INDXC_REG40 | ((UINT32) RCINDXC << 29));
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000659 abValue |= BIT12 + BIT3 + BIT0;
660 abValue &= ~(BIT9 + BIT4);
Paul Menzel4715c622021-03-05 01:22:29 +0100661 writeAlink (RC_INDXC_REG40 | ((UINT32) RCINDXC << 29), abValue);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000662 }
663 }
664
665//
666// Configure Lock HWInit registers
667//
Paul Menzel4715c622021-03-05 01:22:29 +0100668 reg32Value = readAlink (SB_ABCFG_REGC0 | ((UINT32) ABCFG << 29));
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000669//
670// Disable hidden register decode and serial number capability
671//
Paul Menzel4715c622021-03-05 01:22:29 +0100672 reg32Value = readAlink (SB_ABCFG_REG330 | ((UINT32) ABCFG << 29));
673 writeAlink (SB_ABCFG_REG330 | ((UINT32) ABCFG << 29), reg32Value & ~(BIT26 + BIT10));
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000674}
675
676/**
677 * sbGppSetAspm - Set SPP ASPM
678 *
679 *
680 * @param[in] pciAddress PCI Address.
681 * @param[in] LxState Lane State.
682 *
683 */
684VOID
685sbGppSetAspm (
686 IN UINT32 pciAddress,
687 IN UINT8 LxState
688 )
689{
690 UINT8 pcieCapOffset;
691 UINT8 value8;
692 UINT8 maxFuncs;
693 UINT32 devBDF;
694
695 maxFuncs = 1;
696 ReadPCI (pciAddress + 0x0E, AccWidthUint8, &value8);
697
698 if (value8 & BIT7) {
699 maxFuncs = 8; // multi-function device
700 }
701 while (maxFuncs != 0) {
702 devBDF = pciAddress + (UINT32) ((maxFuncs - 1) << 16);
703 pcieCapOffset = sbFindPciCap (devBDF, PCIE_CAP_ID);
704 if (pcieCapOffset) {
705 // Read link capabilities register (0x0C[11:10] - ASPM support)
706 ReadPCI (devBDF + pcieCapOffset + 0x0D, AccWidthUint8, &value8);
707 if (value8 & BIT2) {
708 value8 = (value8 >> 2) & (BIT1 + BIT0);
709 // Set ASPM state in link control register
710 RWPCI (devBDF + pcieCapOffset + 0x10, AccWidthUint8, 0xffffffff, LxState & value8);
711 }
712 }
713 maxFuncs--;
714 }
715}
716
717/**
718 * sbFindPciCap - Find PCI Cap
719 *
720 *
721 * @param[in] pciAddress PCI Address.
722 * @param[in] targetCapId Target Cap ID.
723 *
724 */
725UINT8
726sbFindPciCap (
727 IN UINT32 pciAddress,
728 IN UINT8 targetCapId
729 )
730{
731 UINT8 NextCapPtr;
732 UINT8 CapId;
733
734 NextCapPtr = 0x34;
735 while (NextCapPtr != 0) {
736 ReadPCI (pciAddress + NextCapPtr, AccWidthUint8, &NextCapPtr);
737 if (NextCapPtr == 0xff) {
738 return 0;
739 }
740 if (NextCapPtr != 0) {
741 ReadPCI (pciAddress + NextCapPtr, AccWidthUint8, &CapId);
742 if (CapId == targetCapId) {
743 break;
744 } else {
745 NextCapPtr++;
746 }
747 }
748 }
749 return NextCapPtr;
750}
751
752/**
753 * sbGppForceGen2 - Set SPP to GENII
754 *
755 *
756 * @param[in] portId
757 *
758 */
759VOID
760sbGppForceGen2 (
761 IN UINT32 portId
762 )
763{
764 RWPCI (PCI_ADDRESS (0, GPP_DEV_NUM, portId, 0x88), AccWidthUint8, 0xf0, 0x02);
765 rwAlink (SB_RCINDXP_REGA2 | portId << 24, ~BIT13, 0);
766 rwAlink (SB_RCINDXP_REGC0 | portId << 24, ~BIT15, 0);
767 rwAlink (SB_RCINDXP_REGA4 | portId << 24, 0xFFFFFFFF, BIT29);
768}
769
770/**
771 * sbGppForceGen1 - Set SPP to GENI
772 *
773 *
774 * @param[in] portId
775 *
776 */
777VOID
778sbGppForceGen1 (
779 IN UINT32 portId
780 )
781{
782 RWPCI (PCI_ADDRESS (0, GPP_DEV_NUM, portId, 0x88), AccWidthUint8, 0xf0, 0x01);
783 rwAlink (SB_RCINDXP_REGA4 | portId << 24, ~BIT0, 0);
784 rwAlink (SB_RCINDXP_REGA2 | portId << 24, 0xFFFFFFFF, BIT13);
785 rwAlink (SB_RCINDXP_REGC0 | portId << 24, ~BIT15, 0);
786 rwAlink (SB_RCINDXP_REGA4 | portId << 24, 0xFFFFFFFF, BIT29);
787}
788
789/**
790 * sbGppDisableUnusedPadMap - Return GPP Pad Map
791 *
792 *
793 * @param[in] pConfig
794 *
795 */
796VOID
797sbGppDisableUnusedPadMap (
798 IN AMDSBCFG* pConfig
799 )
800{
801 UINT32 Data32;
802 UINT32 HoldData32;
803 SBGPPPORTCONFIG *portCfg;
804 UINT8 cimGppLaneReversal;
805 UINT8 cimAlinkPhyPllPowerDown;
806 UINT8 cimGppPhyPllPowerDown;
807
808 cimAlinkPhyPllPowerDown = (UINT8) pConfig->AlinkPhyPllPowerDown;
809 cimGppLaneReversal = (UINT8) pConfig->GppLaneReversal;
810 cimGppPhyPllPowerDown = (UINT8) pConfig->GppPhyPllPowerDown;
811#if SB_CIMx_PARAMETER == 0
812 cimGppLaneReversal = cimGppLaneReversalDefault;
813 cimAlinkPhyPllPowerDown = cimAlinkPhyPllPowerDownDefault;
814 cimGppPhyPllPowerDown = cimGppPhyPllPowerDownDefault;
815#endif
816
817 Data32 = 0;
818 HoldData32 = 0;
819 switch ( pConfig->GppLinkConfig ) {
820 case GPP_CFGMODE_X4000:
821 portCfg = &pConfig->PORTCONFIG[0].PortCfg;
822 if ( portCfg->PortDetected == FALSE ) {
823 Data32 |= 0x0f0f;
824 HoldData32 |= 0x1000;
825 }
826 break;
827 case GPP_CFGMODE_X2200:
828 portCfg = &pConfig->PORTCONFIG[0].PortCfg;
829 if ( portCfg->PortDetected == FALSE ) {
830 Data32 |= ( cimGppLaneReversal )? 0x0c0c:0x0303;
831 HoldData32 |= 0x1000;
832 }
833 portCfg = &pConfig->PORTCONFIG[1].PortCfg;
834 if ( portCfg->PortDetected == FALSE ) {
835 Data32 |= ( cimGppLaneReversal )? 0x0303:0x0c0c;
836 HoldData32 |= 0x2000;
837 }
838 break;
839 case GPP_CFGMODE_X2110:
840 portCfg = &pConfig->PORTCONFIG[0].PortCfg;
841 if ( portCfg->PortDetected == FALSE ) {
842 Data32 |= ( cimGppLaneReversal )? 0x0c0c:0x0303;
843 HoldData32 |= 0x1000;
844 }
845 portCfg = &pConfig->PORTCONFIG[1].PortCfg;
846 if ( portCfg->PortDetected == FALSE ) {
847 Data32 |= ( cimGppLaneReversal )? 0x0202:0x0404;
848 HoldData32 |= 0x2000;
849 }
850 portCfg = &pConfig->PORTCONFIG[2].PortCfg;
851 if ( portCfg->PortDetected == FALSE ) {
852 Data32 |= ( cimGppLaneReversal )? 0x0101:0x0808;
853 HoldData32 |= 0x4000;
854 }
855 break;
856 case GPP_CFGMODE_X1111:
857 portCfg = &pConfig->PORTCONFIG[0].PortCfg;
858 if ( portCfg->PortDetected == FALSE ) {
859 Data32 |= ( cimGppLaneReversal )? 0x0808:0x0101;
860 HoldData32 |= 0x1000;
861 }
862 portCfg = &pConfig->PORTCONFIG[1].PortCfg;
863 if ( portCfg->PortDetected == FALSE ) {
864 Data32 |= ( cimGppLaneReversal )? 0x0404:0x0202;
865 HoldData32 |= 0x2000;
866 }
867 portCfg = &pConfig->PORTCONFIG[2].PortCfg;
868 if ( portCfg->PortDetected == FALSE ) {
869 Data32 |= ( cimGppLaneReversal )? 0x0202:0x0404;
870 HoldData32 |= 0x4000;
871 }
872 portCfg = &pConfig->PORTCONFIG[3].PortCfg;
873 if ( portCfg->PortDetected == FALSE ) {
874 Data32 |= ( cimGppLaneReversal )? 0x0101:0x0808;
875 HoldData32 |= 0x8000;
876 }
877 break;
878 default:
879 break;
880 }
881
882// RPR 5.11 Power Saving With GPP Disable
883// ABCFG 0xC0[8] = 0x0
884// ABCFG 0xC0[15:12] = 0xF
885// Enable "Power Saving Feature for A-Link Express Lanes"
886// Enable "Power Saving Feature for GPP Lanes"
887// ABCFG 0x90[19] = 1
888// ABCFG 0x90[6] = 1
889// RCINDC_Reg 0x65 [27:0] = 0xFFFFFFF
890// ABCFG 0xC0[7:4] = 0x0
891 if ( (Data32 & 0xf) == 0xf ) Data32 |= 0x0cff0000;
892 if ( cimAlinkPhyPllPowerDown && cimGppPhyPllPowerDown ) {
Paul Menzel4715c622021-03-05 01:22:29 +0100893 rwAlink (SB_ABCFG_REGC0 | ((UINT32) ABCFG << 29), ~BIT8, 0);
894 rwAlink (SB_ABCFG_REGC0 | ((UINT32) ABCFG << 29), 0xFFFFFFFF, HoldData32);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000895 rwAlink (SB_AX_INDXC_REG40, ~(BIT9 + BIT4), (BIT0 + BIT3 + BIT12));
896 rwAlink (RC_INDXC_REG40, ~(BIT9 + BIT4), (BIT0 + BIT3 + BIT12));
Paul Menzel4715c622021-03-05 01:22:29 +0100897 rwAlink ((SB_ABCFG_REG90 | ((UINT32) ABCFG << 29)), 0xFFFFFFFF, (BIT6 + BIT19));
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000898 rwAlink (RC_INDXC_REG65, 0xFFFFFFFF, Data32);
899 }
900}