/** * AbCfgTbl - Program ABCFG by input table. * * * @param[in] ABTbl ABCFG config table. * @param[in] StdHeader * */ VOID AbCfgTbl ( IN AB_TBL_ENTRY *ABTbl, IN AMD_CONFIG_PARAMS *StdHeader ) { UINT32 AbValue; while ( (ABTbl->RegType) != 0xFF ) { if ( ABTbl->RegType == AXINDC ) { AbValue = 0x30 | (ABTbl->RegType << 29); WriteAlink (AbValue, (ABTbl->RegIndex & 0x00FFFFFF), StdHeader); AbValue = 0x34 | (ABTbl->RegType << 29); WriteAlink (AbValue, ((ReadAlink (AbValue, StdHeader)) & (0xFFFFFFFF^ (ABTbl->RegMask))) | ABTbl->RegData, StdHeader); } else if ( ABTbl->RegType == AXINDP ) { AbValue = 0x38 | (ABTbl->RegType << 29); WriteAlink (AbValue, (ABTbl->RegIndex & 0x00FFFFFF), StdHeader); AbValue = 0x3C | (ABTbl->RegType << 29); WriteAlink (AbValue, ((ReadAlink (AbValue, StdHeader)) & (0xFFFFFFFF^ (ABTbl->RegMask))) | ABTbl->RegData, StdHeader); } else { AbValue = ABTbl->RegIndex | (ABTbl->RegType << 29); WriteAlink (AbValue, ((ReadAlink (AbValue, StdHeader)) & (0xFFFFFFFF^ (ABTbl->RegMask))) | ABTbl->RegData, StdHeader); } ++ABTbl; } // //Clear ALink Access Index // AbValue = 0; LibAmdIoWrite (AccessWidth32, ALINK_ACCESS_INDEX, &AbValue, StdHeader); }
/** * FchAbLateProgram - Set ABCFG registers during late POST * * * @param[in] FchDataPtr Fch configuration structure pointer. * */ VOID FchAbLateProgram ( IN VOID *FchDataPtr ) { UINT32 AbValue; FCH_DATA_BLOCK *LocalCfgPtr; AMD_CONFIG_PARAMS *StdHeader; LocalCfgPtr = (FCH_DATA_BLOCK *) FchDataPtr; StdHeader = LocalCfgPtr->StdHeader; AbValue = ReadAlink (FCH_ABCFG_REGC0 | (UINT32) (ABCFG << 29), StdHeader); AbValue &= 0xf0; if ( LocalCfgPtr->Ab.PcieOrderRule && AbValue ) { AbValue = ReadAlink (FCH_RCINDXC_REG02, StdHeader); AbValue = AbValue | BIT9; WriteAlink (FCH_RCINDXC_REG02, AbValue, StdHeader); } }
/** * Is UMI One Lane GEN1 Mode? * * * @retval TRUE or FALSE * */ BOOLEAN IsUmiOneLaneGen1Mode ( IN AMD_CONFIG_PARAMS *StdHeader ) { UINT32 AbValue; AbValue = ReadAlink ((UINT32) (FCH_AX_CFG_REG68), StdHeader); AbValue >>= 16; if (((AbValue & 0x0f) == 1) && ((AbValue & 0x03f0) == 0x0010)) { return (TRUE); } else { return (FALSE); } }
EFI_STATUS EFIAPI AmdSmiEinjChkErr ( IN OUT VOID ) { UINT8 Value8; UINT8 PortId; UINT32 Value32; EFI_STATUS Status; AMD_CONFIG_PARAMS StdHeader; Status = EFI_SUCCESS; PortId = 7; ReadMem (ACPI_MMIO_BASE + SMI_BASE + 0x3C, AccessWidth8, &Value8); if (Value8 & BIT2) { Value32 = ReadAlink (0x104C | (UINT32) (ABCFG << 29), &StdHeader); if (Value32 & BIT4) { PortId = 0; WriteAlink (0x104C | (UINT32) (ABCFG << 29), BIT4, &StdHeader); } else if (Value32 & BIT5) { PortId = 1; WriteAlink (0x104C | (UINT32) (ABCFG << 29), BIT5, &StdHeader); } else if (Value32 & BIT6) { PortId = 2; WriteAlink (0x104C | (UINT32) (ABCFG << 29), BIT6, &StdHeader); } else if (Value32 & BIT7) { PortId = 3; WriteAlink (0x104C | (UINT32) (ABCFG << 29), BIT7, &StdHeader); } Value8 = BIT2; WriteMem (ACPI_MMIO_BASE + SMI_BASE + 0x3C, AccessWidth8, &Value8); AmdFchWheaElogGpp (PortId); } return Status; }
/** * GppPortPollingLtssmR - Loop polling the LTSSM for each GPP * port marked in PortMap * * * @param[in] FchGpp Pointer to Fch GPP configuration structure * @param[in] ActivePorts A bitmap of ports which should be polled * @param[in] IsGen2 TRUE if the polling is in Gen2 mode * @param[in] StdHeader Pointer to AMD_CONFIG_PARAMS * * @retval FailedPorts A bitmap of ports which failed to train * */ UINT8 GppPortPollingLtssmR ( IN FCH_GPP_R *FchGpp, IN UINT8 ActivePorts, IN BOOLEAN IsGen2, IN AMD_CONFIG_PARAMS *StdHeader ) { UINT32 RetryCounter; UINT8 PortId; UINT8 FailedPorts; UINT8 HotPlugPorts; FCH_GPP_PORT_CONFIG_R *PortCfg; UINT32 AbIndex; UINT32 GppData32; UINT8 EmptyPorts; UINT8 Index; UINT8 FixedPolling; FailedPorts = 0; HotPlugPorts = 0; RetryCounter = MAX_LT_POLLINGS; EmptyPorts = ActivePorts; FixedPolling = FchGpp->GppPortMinPollingTime; while (RetryCounter-- && ActivePorts) { for (PortId = 0; PortId < MAX_GPP_PORTS; PortId++) { if (ActivePorts & (1 << PortId)) { PortCfg = &FchGpp->PortCfg[PortId]; if ( PortCfg->PortHotPlug == TRUE ) { HotPlugPorts |= ( 1 << PortId); } AbIndex = FCH_RCINDXP_REGA5 | (UINT32) (PortId << 24); GppData32 = ReadAlink (AbIndex, StdHeader) & 0x3F3F3F3F; if ((UINT8) (GppData32) > 0x04) { EmptyPorts &= ~(1 << PortId); } if ((UINT8) (GppData32) == 0x10) { ActivePorts &= ~(1 << PortId); PortCfg->PortDetected = TRUE; break; } if (IsGen2) { for (Index = 0; Index < 4; Index++) { if ((UINT8) (GppData32) == 0x29 || (UINT8) (GppData32) == 0x2A ) { ActivePorts &= ~(1 << PortId); FailedPorts |= (1 << PortId); break; } GppData32 >>= 8; } } } } if (EmptyPorts && RetryCounter < (MAX_LT_POLLINGS - (UINT32) FixedPolling)) { ActivePorts &= ~EmptyPorts; } FchStall (1000, StdHeader); }
/** * FchGppDynamicPowerSaving - GPP Dynamic Power Saving * * * @param[in] FchDataPtr * */ VOID FchGppDynamicPowerSaving ( IN VOID *FchDataPtr ) { FCH_GPP_PORT_CONFIG *PortCfg; UINT8 FchGppLaneReversal; UINT8 FchAlinkPhyPllPowerDown; UINT8 FchGppPhyPllPowerDown; UINT32 GppData32; UINT32 HoldGppData32; UINT32 AbValue; FCH_DATA_BLOCK *LocalCfgPtr; AMD_CONFIG_PARAMS *StdHeader; LocalCfgPtr = (FCH_DATA_BLOCK *) FchDataPtr; StdHeader = LocalCfgPtr->StdHeader; if (!LocalCfgPtr->Gpp.GppDynamicPowerSaving || LocalCfgPtr->SerialDb.SerialDebugBusEnable) { return; } FchAlinkPhyPllPowerDown = (UINT8) LocalCfgPtr->Ab.UmiPhyPllPowerDown; FchGppLaneReversal = (UINT8) LocalCfgPtr->Gpp.GppLaneReversal; FchGppPhyPllPowerDown = (UINT8) LocalCfgPtr->Gpp.GppPhyPllPowerDown; if (LocalCfgPtr->Gpp.GppHardwareDownGrade) { PortCfg = &LocalCfgPtr->Gpp.PortCfg[LocalCfgPtr->Gpp.GppHardwareDownGrade - 1]; PortCfg->PortDetected = TRUE; } GppData32 = 0; HoldGppData32 = 0; switch ( LocalCfgPtr->Gpp.GppLinkConfig ) { case PortA4: PortCfg = &LocalCfgPtr->Gpp.PortCfg[0]; if ( PortCfg->PortDetected == FALSE ) { GppData32 |= 0x0f0f; HoldGppData32 |= 0x1000; } break; case PortA2B2: PortCfg = &LocalCfgPtr->Gpp.PortCfg[0]; if ( PortCfg->PortDetected == FALSE ) { GppData32 |= ( FchGppLaneReversal )? 0x0c0c:0x0303; HoldGppData32 |= 0x1000; } PortCfg = &LocalCfgPtr->Gpp.PortCfg[1]; if ( PortCfg->PortDetected == FALSE ) { GppData32 |= ( FchGppLaneReversal )? 0x0303:0x0c0c; HoldGppData32 |= 0x2000; } break; case PortA2B1C1: PortCfg = &LocalCfgPtr->Gpp.PortCfg[0]; if ( PortCfg->PortDetected == FALSE ) { GppData32 |= ( FchGppLaneReversal )? 0x0c0c:0x0303; HoldGppData32 |= 0x1000; } PortCfg = &LocalCfgPtr->Gpp.PortCfg[1]; if ( PortCfg->PortDetected == FALSE ) { GppData32 |= ( FchGppLaneReversal )? 0x0202:0x0404; HoldGppData32 |= 0x2000; } PortCfg = &LocalCfgPtr->Gpp.PortCfg[2]; if ( PortCfg->PortDetected == FALSE ) { GppData32 |= ( FchGppLaneReversal )? 0x0101:0x0808; HoldGppData32 |= 0x4000; } break; case PortA1B1C1D1: PortCfg = &LocalCfgPtr->Gpp.PortCfg[0]; if ( PortCfg->PortDetected == FALSE ) { GppData32 |= ( FchGppLaneReversal )? 0x0808:0x0101; HoldGppData32 |= 0x1000; } PortCfg = &LocalCfgPtr->Gpp.PortCfg[1]; if ( PortCfg->PortDetected == FALSE ) { GppData32 |= ( FchGppLaneReversal )? 0x0404:0x0202; HoldGppData32 |= 0x2000; } PortCfg = &LocalCfgPtr->Gpp.PortCfg[2]; if ( PortCfg->PortDetected == FALSE ) { GppData32 |= ( FchGppLaneReversal )? 0x0202:0x0404; HoldGppData32 |= 0x4000; } PortCfg = &LocalCfgPtr->Gpp.PortCfg[3]; if ( PortCfg->PortDetected == FALSE ) { GppData32 |= ( FchGppLaneReversal )? 0x0101:0x0808; HoldGppData32 |= 0x8000; } break; default: ASSERT (FALSE); break; } // // Power Saving With GPP Disable // ABCFG 0xC0[8] = 0x0 // ABCFG 0xC0[15:12] = 0xF // Enable "Power Saving Feature for A-Link Express Lanes" // Enable "Power Saving Feature for GPP Lanes" // ABCFG 0x90[19] = 1 // ABCFG 0x90[6] = 1 // RCINDC_Reg 0x65 [27:0] = 0xFFFFFFF // ABCFG 0xC0[7:4] = 0x0 // if ( FchAlinkPhyPllPowerDown && FchGppPhyPllPowerDown ) { AbValue = ReadAlink (FCH_ABCFG_REGC0 | (UINT32) (ABCFG << 29), StdHeader); WriteAlink (FCH_ABCFG_REGC0 | (UINT32) (ABCFG << 29), (( AbValue | HoldGppData32 ) & (~ BIT8 )), StdHeader); RwAlink (FCH_AX_INDXC_REG40, ~(BIT9 + BIT4), (BIT0 + BIT3 + BIT12), StdHeader); RwAlink ((FCH_ABCFG_REG90 | (UINT32) (ABCFG << 29)), 0xFFFFFFFF, (BIT6 + BIT19), StdHeader); RwAlink (RC_INDXC_REG65, 0xFFFFFFFF, ((GppData32 & 0x0F) == 0x0F) ? GppData32 | 0x0CFF0000 : GppData32, StdHeader); RwAlink (RC_INDXC_REG40, ~(BIT9 + BIT4), (BIT0 + BIT3 + BIT12), StdHeader); } }
/** * FchInitLateGpp - Prepare Gpp controller to boot to OS. * * PcieGppLateInit * * @param[in] FchDataPtr Fch configuration structure pointer. * */ VOID FchInitLateGpp ( IN VOID *FchDataPtr ) { UINT8 PortId; UINT8 BusNum; UINT8 AspmValue; UINT8 PortAspmValue; UINT8 AllowStrapControlByAB; UINT8 FchGppPhyPllPowerDown; FCH_GPP_PORT_CONFIG *PortCfg; UINT32 PciAspmValue; UINT32 AbValue; FCH_DATA_BLOCK *LocalCfgPtr; AMD_CONFIG_PARAMS *StdHeader; LocalCfgPtr = (FCH_DATA_BLOCK *) FchDataPtr; StdHeader = LocalCfgPtr->StdHeader; // // Disable hidden register decode and serial number capability // AbValue = ReadAlink (FCH_ABCFG_REG330 | (UINT32) (ABCFG << 29), StdHeader); WriteAlink (FCH_ABCFG_REG330 | (UINT32) (ABCFG << 29), AbValue & ~(BIT26 + BIT10), StdHeader); if (ReadAlink (FCH_ABCFG_REGC0 | (UINT32) (ABCFG << 29), StdHeader) & BIT8) { return; } // // Configure ASPM // AspmValue = (UINT8)LocalCfgPtr->Gpp.GppPortAspm; FchGppPhyPllPowerDown = (UINT8) LocalCfgPtr->Gpp.GppPhyPllPowerDown; AllowStrapControlByAB = 0x01; for ( PortId = 0; PortId < MAX_GPP_PORTS; PortId++ ) { // // write pci_reg3d with 0x01 to fix yellow mark for GPP bridge under some OS // when native PCIE is enabled but MSI is not available // BIF/GPP allowing strap STRAP_BIF_INTERRUPT_PIN_SB controlled by AB reg // PortCfg = &LocalCfgPtr->Gpp.PortCfg[PortId]; if (PortCfg->PortHotPlug) { RwPci (PCI_ADDRESS (0, 21, PortId, 0x04), AccessWidth8, 0xFE, 0x00, StdHeader); ///clear IO enable to fix possible hotplug hang } WritePci (PCI_ADDRESS (0, 21, PortId, 0x3d), AccessWidth8, &AllowStrapControlByAB, StdHeader); ReadPci (PCI_ADDRESS (0, 21, PortId, 0x19), AccessWidth8, &BusNum, StdHeader); if (BusNum != 0xFF) { ReadPci (PCI_ADDRESS (BusNum, 0, 0, 0x00), AccessWidth32, &PciAspmValue, StdHeader); if (PciAspmValue != 0xffffffff) { PortAspmValue = AspmValue; // // Validate ASPM support on EP side // FchGppValidateAspm (PCI_ADDRESS (BusNum, 0, 0, 0), &PortAspmValue, StdHeader); // // Set ASPM on EP side // FchGppSetEpAspm (PCI_ADDRESS (BusNum, 0, 0, 0), PortAspmValue, StdHeader); // // Set ASPM on port side // FchGppSetAspm (PCI_ADDRESS (0, 21, PortId, 0), PortAspmValue, StdHeader); } } RwAlink ((FCH_RCINDXP_REG02 | (UINT32) (RCINDXP << 29) | (PortId << 24) ), ~(BIT15), (BIT15), StdHeader); } RwAlink ((FCH_RCINDXC_REG02 | (UINT32) (RCINDXC << 29)), ~(BIT0), (BIT0), StdHeader); // // Configure Lock HWInit registers // AbValue = ReadAlink (FCH_ABCFG_REGC0 | (UINT32) (ABCFG << 29), StdHeader); if (AbValue & 0xF0) { AbValue = ReadAlink (FCH_RCINDXC_REG10 | (UINT32) (RCINDXC << 29), StdHeader); WriteAlink (FCH_RCINDXC_REG10 | (UINT32) (RCINDXC << 29), AbValue | BIT0, StdHeader); /// Set HWINIT_WR_LOCK if ( FchGppPhyPllPowerDown == TRUE ) { // // Power Saving Feature for GPP Lanes // // Set PCIE_P_CNTL in Alink PCIEIND space // AbValue = ReadAlink (RC_INDXC_REG40 | (UINT32) (RCINDXC << 29), StdHeader); AbValue |= BIT12 + BIT3 + BIT0; AbValue &= ~(BIT9 + BIT4); WriteAlink (RC_INDXC_REG40 | (UINT32) (RCINDXC << 29), AbValue, StdHeader); RwAlink (FCH_RCINDXC_REG02, ~(BIT8), (BIT8), StdHeader); RwAlink (FCH_RCINDXC_REG02, ~(BIT3), (BIT3), StdHeader); } } // // Restore strap0 via override // if (LocalCfgPtr->Gpp.PcieAer) { RwAlink (FCH_ABCFG_REG310 | (UINT32) (ABCFG << 29), 0xFFFFFFFF, BIT7, StdHeader); RwAlink (RC_INDXC_REGC0, 0xFFFFFFFF, BIT9, StdHeader); } }