12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508 |
- /** @file
- Copyright (c) 2020 - 2023, Ampere Computing LLC. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include <PiDxe.h>
- #include <Guid/PlatformInfoHob.h>
- #include <Guid/RootComplexInfoHob.h>
- #include <IndustryStandard/Pci.h>
- #include <Library/ArmGenericTimerCounterLib.h>
- #include <Library/BaseLib.h>
- #include <Library/BaseMemoryLib.h>
- #include <Library/BoardPcieLib.h>
- #include <Library/DebugLib.h>
- #include <Library/HobLib.h>
- #include <Library/IoLib.h>
- #include <Library/PciePhyLib.h>
- #include <Library/SystemFirmwareInterfaceLib.h>
- #include <Library/TimerLib.h>
- #include "PcieCore.h"
- VOID
- EnableDbiAccess (
- AC01_ROOT_COMPLEX *RootComplex,
- UINT32 PcieIndex,
- BOOLEAN EnableDbi
- );
- BOOLEAN
- EndpointCfgReady (
- IN AC01_ROOT_COMPLEX *RootComplex,
- IN UINT8 PcieIndex,
- IN UINT32 Timeout
- );
- BOOLEAN
- PcieLinkUpCheck (
- IN AC01_PCIE_CONTROLLER *Pcie
- );
- /**
- Return the next extended capability base address
- @param RootComplex Pointer to AC01_ROOT_COMPLEX structure
- @param PcieIndex PCIe controller index
- @param IsRootComplex TRUE: Checking RootComplex configuration space
- FALSE: Checking EP configuration space
- @param ExtCapabilityId
- **/
- PHYSICAL_ADDRESS
- GetCapabilityBase (
- IN AC01_ROOT_COMPLEX *RootComplex,
- IN UINT8 PcieIndex,
- IN BOOLEAN IsRootComplex,
- IN UINT16 ExtCapabilityId
- )
- {
- BOOLEAN IsExtCapability = FALSE;
- PHYSICAL_ADDRESS CfgBase;
- PHYSICAL_ADDRESS Ret = 0;
- PHYSICAL_ADDRESS RootComplexCfgBase;
- UINT32 CapabilityId;
- UINT32 NextCapabilityPtr;
- UINT32 Val;
- UINT32 RestoreVal;
- RootComplexCfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT);
- if (!IsRootComplex) {
- // Allow programming to config space
- EnableDbiAccess (RootComplex, PcieIndex, TRUE);
- Val = MmioRead32 (RootComplexCfgBase + SEC_LAT_TIMER_SUB_BUS_SEC_BUS_PRI_BUS_REG);
- RestoreVal = Val;
- Val = SUB_BUS_SET (Val, DEFAULT_SUB_BUS);
- Val = SEC_BUS_SET (Val, RootComplex->Pcie[PcieIndex].DevNum);
- Val = PRIM_BUS_SET (Val, 0x0);
- MmioWrite32 (RootComplexCfgBase + SEC_LAT_TIMER_SUB_BUS_SEC_BUS_PRI_BUS_REG, Val);
- CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << BUS_SHIFT);
- if (!EndpointCfgReady (RootComplex, PcieIndex, EP_LINKUP_TIMEOUT)) {
- goto _CheckCapEnd;
- }
- } else {
- CfgBase = RootComplexCfgBase;
- }
- // Check if device provide capability
- Val = MmioRead32 (CfgBase + PCI_COMMAND_OFFSET);
- Val = GET_HIGH_16_BITS (Val); /* Status */
- if (!(Val & EFI_PCI_STATUS_CAPABILITY)) {
- goto _CheckCapEnd;
- }
- Val = MmioRead32 (CfgBase + TYPE1_CAP_PTR_REG);
- NextCapabilityPtr = GET_LOW_8_BITS (Val);
- // Loop untill desired capability is found else return 0
- while (1) {
- if ((NextCapabilityPtr & WORD_ALIGN_MASK) != 0) {
- // Not alignment, just return
- Ret = 0;
- goto _CheckCapEnd;
- }
- Val = MmioRead32 (CfgBase + NextCapabilityPtr);
- if (NextCapabilityPtr < EXT_CAPABILITY_START_BASE) {
- CapabilityId = GET_LOW_8_BITS (Val);
- } else {
- CapabilityId = GET_LOW_16_BITS (Val);
- }
- if (CapabilityId == ExtCapabilityId) {
- Ret = (CfgBase + NextCapabilityPtr);
- goto _CheckCapEnd;
- }
- if (NextCapabilityPtr < EXT_CAPABILITY_START_BASE) {
- NextCapabilityPtr = GET_CAPABILITY_PTR (Val);
- } else {
- NextCapabilityPtr = GET_EXT_CAPABILITY_PTR (Val);
- }
- if ((NextCapabilityPtr == 0) && !IsExtCapability) {
- IsExtCapability = TRUE;
- NextCapabilityPtr = EXT_CAPABILITY_START_BASE;
- }
- if ((NextCapabilityPtr == 0) && IsExtCapability) {
- Ret = 0;
- goto _CheckCapEnd;
- }
- }
- _CheckCapEnd:
- if (!IsRootComplex) {
- MmioWrite32 (RootComplexCfgBase + SEC_LAT_TIMER_SUB_BUS_SEC_BUS_PRI_BUS_REG, RestoreVal);
- // Disable programming to config space
- EnableDbiAccess (RootComplex, PcieIndex, FALSE);
- }
- return Ret;
- }
- /**
- Configure equalization settings for Gen3 and Gen4
- @param RootComplex Pointer to AC01_ROOT_COMPLEX structure
- @param PcieIndex PCIe controller index
- **/
- STATIC
- VOID
- ConfigureEqualization (
- IN AC01_ROOT_COMPLEX *RootComplex,
- IN UINT8 PcieIndex
- )
- {
- PHYSICAL_ADDRESS CfgBase;
- PHYSICAL_ADDRESS Gen3RelatedAddr;
- PHYSICAL_ADDRESS Gen3EqControlAddr;
- UINT32 Val;
- CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT);
- //
- // Gen3 and Gen4 EQ process use the same setting registers which are
- // GEN3_RELATED_OFF and GEN3_EQ_CONTROL_OFF. Both are shadow registers
- // and controlled by GEN3_RELATED_OFF[25:24].
- //
- Gen3RelatedAddr = CfgBase + GEN3_RELATED_OFF;
- Gen3EqControlAddr = CfgBase + GEN3_EQ_CONTROL_OFF;
- //
- // Equalization setting for Gen3
- //
- Val = MmioRead32 (Gen3RelatedAddr);
- Val = RATE_SHADOW_SEL_SET (Val, GEN3_DATA_RATE);
- MmioWrite32 (Gen3RelatedAddr, Val);
- Val = EQ_PHASE_2_3_SET (Val, ENABLE_EQ_PHASE_2_3);
- Val = RXEQ_REGRDLESS_SET (Val, ASSERT_RXEQ);
- MmioWrite32 (Gen3RelatedAddr, Val);
- Val = MmioRead32 (Gen3EqControlAddr);
- Val = GEN3_EQ_FB_MODE (Val, FOM_METHOD);
- Val = GEN3_EQ_PRESET_VEC (Val, EQ_DEFAULT_PRESET_VECTOR);
- Val = GEN3_EQ_INIT_EVAL (Val, INCLUDE_INIT_FOM);
- MmioWrite32 (Gen3EqControlAddr, Val);
- //
- // Equalization setting for Gen4
- //
- Val = MmioRead32 (Gen3RelatedAddr);
- Val = RATE_SHADOW_SEL_SET (Val, GEN4_DATA_RATE);
- MmioWrite32 (Gen3RelatedAddr, Val);
- Val = EQ_PHASE_2_3_SET (Val, ENABLE_EQ_PHASE_2_3);
- Val = RXEQ_REGRDLESS_SET (Val, ASSERT_RXEQ);
- MmioWrite32 (Gen3RelatedAddr, Val);
- Val = MmioRead32 (Gen3EqControlAddr);
- Val = GEN3_EQ_FB_MODE (Val, FOM_METHOD);
- Val = GEN3_EQ_PRESET_VEC (Val, EQ_DEFAULT_PRESET_VECTOR);
- Val = GEN3_EQ_INIT_EVAL (Val, INCLUDE_INIT_FOM);
- MmioWrite32 (Gen3EqControlAddr, Val);
- }
- /**
- Configure presets for Gen3 equalization
- @param RootComplex Pointer to AC01_ROOT_COMPLEX structure
- @param PcieIndex PCIe controller index
- **/
- STATIC
- VOID
- ConfigurePresetGen3 (
- IN AC01_ROOT_COMPLEX *RootComplex,
- IN UINT8 PcieIndex
- )
- {
- PHYSICAL_ADDRESS LaneEqControlAddr;
- PHYSICAL_ADDRESS SpcieCapabilityBase;
- UINT32 Idx;
- UINT32 LinkWidth;
- UINT32 Val;
- // Get the Secondary PCI Express Extended capability base address
- SpcieCapabilityBase = GetCapabilityBase (RootComplex, PcieIndex, TRUE, SPCIE_CAPABILITY_ID);
- if (SpcieCapabilityBase == 0) {
- DEBUG ((
- DEBUG_ERROR,
- "PCIE%d.%d: Cannot get SPCIE capability address\n",
- RootComplex->ID,
- PcieIndex
- ));
- return;
- }
- LinkWidth = RootComplex->Pcie[PcieIndex].MaxWidth;
- // Each register holds the Preset for 2 lanes
- for (Idx = 0; Idx < (LinkWidth / 2); Idx++) {
- LaneEqControlAddr = SpcieCapabilityBase + SPCIE_CAP_OFF_0C_REG + Idx * sizeof (UINT32);
- Val = MmioRead32 (LaneEqControlAddr);
- Val = DSP_TX_PRESET0_SET (Val, DEFAULT_GEN3_PRESET);
- Val = DSP_TX_PRESET1_SET (Val, DEFAULT_GEN3_PRESET);
- MmioWrite32 (LaneEqControlAddr, Val);
- }
- }
- /**
- Configure presets for Gen4 equalization
- @param RootComplex Pointer to AC01_ROOT_COMPLEX structure
- @param PcieIndex PCIe controller index
- **/
- STATIC
- VOID
- ConfigurePresetGen4 (
- IN AC01_ROOT_COMPLEX *RootComplex,
- IN UINT8 PcieIndex
- )
- {
- PHYSICAL_ADDRESS LaneEqControlAddr;
- PHYSICAL_ADDRESS Pl16gCapabilityBase;
- UINT32 Idx;
- UINT32 LinkWidth;
- UINT32 Val;
- UINT8 Preset;
- // Get the Physical Layer 16.0 GT/s Extended capability base address
- Pl16gCapabilityBase = GetCapabilityBase (RootComplex, PcieIndex, TRUE, PL16G_CAPABILITY_ID);
- if (Pl16gCapabilityBase == 0) {
- DEBUG ((
- DEBUG_ERROR,
- "PCIE%d.%d: Cannot get PL16G capability address\n",
- RootComplex->ID,
- PcieIndex
- ));
- return;
- }
- if (RootComplex->PresetGen4[PcieIndex] == PRESET_INVALID) {
- Preset = DEFAULT_GEN4_PRESET;
- } else {
- Preset = RootComplex->PresetGen4[PcieIndex];
- }
- LinkWidth = RootComplex->Pcie[PcieIndex].MaxWidth;
- if (LinkWidth == CAP_MAX_LINK_WIDTH_X2) {
- LaneEqControlAddr = Pl16gCapabilityBase + PL16G_CAP_OFF_20H_REG;
- Val = MmioRead32 (LaneEqControlAddr);
- Val = DSP_16G_RXTX_PRESET0_SET (Val, Preset);
- Val = DSP_16G_RXTX_PRESET1_SET (Val, Preset);
- MmioWrite32 (LaneEqControlAddr, Val);
- } else {
- // Each register holds the Preset for 4 lanes
- for (Idx = 0; Idx < (LinkWidth / 4); Idx++) {
- LaneEqControlAddr = Pl16gCapabilityBase + PL16G_CAP_OFF_20H_REG + Idx * sizeof (UINT32);
- Val = MmioRead32 (LaneEqControlAddr);
- Val = DSP_16G_RXTX_PRESET0_SET (Val, Preset);
- Val = DSP_16G_RXTX_PRESET1_SET (Val, Preset);
- Val = DSP_16G_RXTX_PRESET2_SET (Val, Preset);
- Val = DSP_16G_RXTX_PRESET3_SET (Val, Preset);
- MmioWrite32 (LaneEqControlAddr, Val);
- }
- }
- }
- VOID
- ProgramHostBridgeInfo (
- AC01_ROOT_COMPLEX *RootComplex
- )
- {
- EFI_STATUS Status;
- PHYSICAL_ADDRESS TargetAddress;
- UINT32 Val;
- // Program Root Complex Bifurcation
- if (RootComplex->Active) {
- if (RootComplex->Type == RootComplexTypeA) {
- TargetAddress = RootComplex->HostBridgeBase + AC01_HOST_BRIDGE_RCA_DEV_MAP_REG;
- Status = MailboxMsgRegisterRead (RootComplex->Socket, TargetAddress, &Val);
- if (!RETURN_ERROR (Status)) {
- Val = RCA_DEV_MAP_SET (Val, RootComplex->DevMapLow);
- MailboxMsgRegisterWrite (RootComplex->Socket, TargetAddress, Val);
- }
- } else {
- TargetAddress = RootComplex->HostBridgeBase + AC01_HOST_BRIDGE_RCB_DEV_MAP_REG;
- Status = MailboxMsgRegisterRead (RootComplex->Socket, TargetAddress, &Val);
- if (!RETURN_ERROR (Status)) {
- Val = RCB_DEV_MAP_LOW_SET (Val, RootComplex->DevMapLow);
- Val = RCB_DEV_MAP_HIGH_SET (Val, RootComplex->DevMapHigh);
- MailboxMsgRegisterWrite (RootComplex->Socket, TargetAddress, Val);
- }
- }
- }
- // Program Vendor ID and Device ID
- TargetAddress = RootComplex->HostBridgeBase + AC01_HOST_BRIDGE_VENDOR_DEVICE_ID_REG;
- Status = MailboxMsgRegisterRead (RootComplex->Socket, TargetAddress, &Val);
- if (!RETURN_ERROR (Status)) {
- Val = VENDOR_ID_SET (Val, AMPERE_PCIE_VENDOR_ID);
- if (RootComplexTypeA == RootComplex->Type) {
- Val = DEVICE_ID_SET (Val, AC01_HOST_BRIDGE_DEVICE_ID_RCA);
- } else {
- Val = DEVICE_ID_SET (Val, AC01_HOST_BRIDGE_DEVICE_ID_RCB);
- }
- MailboxMsgRegisterWrite (RootComplex->Socket, TargetAddress, Val);
- }
- }
- VOID
- ProgramRootPortInfo (
- AC01_ROOT_COMPLEX *RootComplex,
- UINT32 PcieIndex
- )
- {
- PHYSICAL_ADDRESS CfgBase;
- PHYSICAL_ADDRESS TargetAddress;
- UINT32 Val;
- CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT);
- // Program Class Code
- TargetAddress = CfgBase + TYPE1_CLASS_CODE_REV_ID_REG;
- Val = MmioRead32 (TargetAddress);
- Val = REVISION_ID_SET (Val, DEFAULT_REVISION_ID);
- Val = SUB_CLASS_CODE_SET (Val, DEFAULT_SUB_CLASS_CODE);
- Val = BASE_CLASS_CODE_SET (Val, DEFAULT_BASE_CLASS_CODE);
- MmioWrite32 (TargetAddress, Val);
- // Program Vendor ID and Device ID
- TargetAddress = CfgBase + TYPE1_DEV_ID_VEND_ID_REG;
- Val = MmioRead32 (TargetAddress);
- Val = VENDOR_ID_SET (Val, AMPERE_PCIE_VENDOR_ID);
- if (RootComplexTypeA == RootComplex->Type) {
- Val = DEVICE_ID_SET (Val, AC01_PCIE_BRIDGE_DEVICE_ID_RCA + PcieIndex);
- } else {
- Val = DEVICE_ID_SET (Val, AC01_PCIE_BRIDGE_DEVICE_ID_RCB + PcieIndex);
- }
- MmioWrite32 (TargetAddress, Val);
- }
- VOID
- ProgramLinkCapabilities (
- IN AC01_ROOT_COMPLEX *RootComplex,
- IN UINT8 PcieIndex
- )
- {
- PHYSICAL_ADDRESS CfgBase;
- PHYSICAL_ADDRESS TargetAddress;
- UINT32 Val;
- UINT8 MaxWidth;
- UINT8 MaxGen;
- CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT);
- MaxWidth = RootComplex->Pcie[PcieIndex].MaxWidth;
- MaxGen = RootComplex->Pcie[PcieIndex].MaxGen;
- TargetAddress = CfgBase + PORT_LINK_CTRL_OFF;
- Val = MmioRead32 (TargetAddress);
- switch (MaxWidth) {
- case LINK_WIDTH_X2:
- Val = LINK_CAPABLE_SET (Val, LINK_CAPABLE_X2);
- break;
- case LINK_WIDTH_X4:
- Val = LINK_CAPABLE_SET (Val, LINK_CAPABLE_X4);
- break;
- case LINK_WIDTH_X8:
- Val = LINK_CAPABLE_SET (Val, LINK_CAPABLE_X8);
- break;
- case LINK_WIDTH_X16:
- default:
- Val = LINK_CAPABLE_SET (Val, LINK_CAPABLE_X16);
- break;
- }
- MmioWrite32 (TargetAddress, Val);
- TargetAddress = CfgBase + GEN2_CTRL_OFF;
- Val = MmioRead32 (TargetAddress);
- switch (MaxWidth) {
- case LINK_WIDTH_X2:
- Val = NUM_OF_LANES_SET (Val, NUM_OF_LANES_X2);
- break;
- case LINK_WIDTH_X4:
- Val = NUM_OF_LANES_SET (Val, NUM_OF_LANES_X4);
- break;
- case LINK_WIDTH_X8:
- Val = NUM_OF_LANES_SET (Val, NUM_OF_LANES_X8);
- break;
- case LINK_WIDTH_X16:
- default:
- Val = NUM_OF_LANES_SET (Val, NUM_OF_LANES_X16);
- break;
- }
- MmioWrite32 (TargetAddress, Val);
- TargetAddress = CfgBase + PCIE_CAPABILITY_BASE + LINK_CAPABILITIES_REG;
- Val = MmioRead32 (TargetAddress);
- switch (MaxWidth) {
- case LINK_WIDTH_X2:
- Val = CAP_MAX_LINK_WIDTH_SET (Val, CAP_MAX_LINK_WIDTH_X2);
- break;
- case LINK_WIDTH_X4:
- Val = CAP_MAX_LINK_WIDTH_SET (Val, CAP_MAX_LINK_WIDTH_X4);
- break;
- case LINK_WIDTH_X8:
- Val = CAP_MAX_LINK_WIDTH_SET (Val, CAP_MAX_LINK_WIDTH_X8);
- break;
- case LINK_WIDTH_X16:
- default:
- Val = CAP_MAX_LINK_WIDTH_SET (Val, CAP_MAX_LINK_WIDTH_X16);
- break;
- }
- switch (MaxGen) {
- case LINK_SPEED_GEN1:
- Val = CAP_MAX_LINK_SPEED_SET (Val, MAX_LINK_SPEED_25);
- break;
- case LINK_SPEED_GEN2:
- Val = CAP_MAX_LINK_SPEED_SET (Val, MAX_LINK_SPEED_50);
- break;
- case LINK_SPEED_GEN3:
- Val = CAP_MAX_LINK_SPEED_SET (Val, MAX_LINK_SPEED_80);
- break;
- default:
- Val = CAP_MAX_LINK_SPEED_SET (Val, MAX_LINK_SPEED_160);
- break;
- }
- // Enable ASPM Capability
- Val = CAP_ACTIVE_STATE_LINK_PM_SUPPORT_SET (Val, L0S_L1_SUPPORTED);
- MmioWrite32 (TargetAddress, Val);
- TargetAddress = CfgBase + PCIE_CAPABILITY_BASE + LINK_CONTROL2_LINK_STATUS2_REG;
- Val = MmioRead32 (TargetAddress);
- switch (MaxGen) {
- case LINK_SPEED_GEN1:
- Val = CAP_TARGET_LINK_SPEED_SET (Val, MAX_LINK_SPEED_25);
- break;
- case LINK_SPEED_GEN2:
- Val = CAP_TARGET_LINK_SPEED_SET (Val, MAX_LINK_SPEED_50);
- break;
- case LINK_SPEED_GEN3:
- Val = CAP_TARGET_LINK_SPEED_SET (Val, MAX_LINK_SPEED_80);
- break;
- default:
- Val = CAP_TARGET_LINK_SPEED_SET (Val, MAX_LINK_SPEED_160);
- break;
- }
- MmioWrite32 (TargetAddress, Val);
- }
- VOID
- DisableCompletionTimeOut (
- IN AC01_ROOT_COMPLEX *RootComplex,
- IN UINT8 PcieIndex,
- IN BOOLEAN IsMask
- )
- {
- PHYSICAL_ADDRESS CfgBase;
- PHYSICAL_ADDRESS TargetAddress;
- UINT32 Val;
- CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT);
- TargetAddress = CfgBase + AER_CAPABILITY_BASE + UNCORR_ERR_MASK_OFF;
- Val = MmioRead32 (TargetAddress);
- Val = CMPLT_TIMEOUT_ERR_MASK_SET (Val, IsMask ? 1 : 0);
- MmioWrite32 (TargetAddress, Val);
- }
- BOOLEAN
- EnableItsMemory (
- AC01_ROOT_COMPLEX *RootComplex,
- UINT32 PcieIndex
- )
- {
- PHYSICAL_ADDRESS CsrBase;
- PHYSICAL_ADDRESS TargetAddress;
- UINT32 TimeOut;
- UINT32 Val;
- CsrBase = RootComplex->Pcie[PcieIndex].CsrBase;
- // Clear memory shutdown
- TargetAddress = CsrBase + AC01_PCIE_CORE_RAM_SHUTDOWN_REG;
- Val = MmioRead32 (TargetAddress);
- Val = SD_SET (Val, 0);
- MmioWrite32 (TargetAddress, Val);
- // Poll till ITS Memory is ready
- TimeOut = MEMRDY_TIMEOUT;
- do {
- Val = MmioRead32 (CsrBase + AC01_PCIE_CORE_MEM_READY_REG);
- if (Val & MEMORY_READY) {
- return TRUE;
- }
- TimeOut--;
- MicroSecondDelay (1);
- } while (TimeOut > 0);
- return FALSE;
- }
- BOOLEAN
- EnableAxiPipeClock (
- AC01_ROOT_COMPLEX *RootComplex,
- UINT32 PcieIndex
- )
- {
- PHYSICAL_ADDRESS CsrBase;
- PHYSICAL_ADDRESS TargetAddress;
- UINT32 TimeOut;
- UINT32 Val;
- CsrBase = RootComplex->Pcie[PcieIndex].CsrBase;
- // Enable subsystem clock and release reset
- TargetAddress = CsrBase + AC01_PCIE_CORE_CLOCK_REG;
- Val = MmioRead32 (TargetAddress);
- Val = AXIPIPE_SET (Val, 1);
- MmioWrite32 (TargetAddress, Val);
- TargetAddress = CsrBase + AC01_PCIE_CORE_RESET_REG;
- Val = MmioRead32 (TargetAddress);
- Val = DWC_PCIE_SET (Val, 0);
- MmioWrite32 (TargetAddress, Val);
- //
- // Controller does not provide any indicator for reset released.
- // Must wait at least 1us as per EAS.
- //
- MicroSecondDelay (1);
- // Poll till PIPE clock is stable
- TimeOut = PIPE_CLOCK_TIMEOUT;
- do {
- Val = MmioRead32 (CsrBase + AC01_PCIE_CORE_LINK_STAT_REG);
- if (!(Val & PHY_STATUS_MASK)) {
- return TRUE;
- }
- TimeOut--;
- MicroSecondDelay (1);
- } while (TimeOut > 0);
- return FALSE;
- }
- VOID
- SetLinkTimeout (
- AC01_ROOT_COMPLEX *RootComplex,
- UINT32 PcieIndex,
- UINTN Timeout
- )
- {
- PHYSICAL_ADDRESS TargetAddress;
- UINT32 Val;
- TargetAddress = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT)
- + AMBA_LINK_TIMEOUT_OFF;
- Val = MmioRead32 (TargetAddress);
- Val = LINK_TIMEOUT_PERIOD_DEFAULT_SET (Val, Timeout);
- MmioWrite32 (TargetAddress, Val);
- }
- VOID
- StartLinkTraining (
- AC01_ROOT_COMPLEX *RootComplex,
- UINT32 PcieIndex,
- BOOLEAN StartLink
- )
- {
- PHYSICAL_ADDRESS TargetAddress;
- UINT32 Val;
- TargetAddress = RootComplex->Pcie[PcieIndex].CsrBase + AC01_PCIE_CORE_LINK_CTRL_REG;
- Val = MmioRead32 (TargetAddress);
- Val = LTSSMENB_SET (Val, StartLink ? START_LINK_TRAINING : HOLD_LINK_TRAINING);
- MmioWrite32 (TargetAddress, Val);
- }
- VOID
- EnableDbiAccess (
- AC01_ROOT_COMPLEX *RootComplex,
- UINT32 PcieIndex,
- BOOLEAN EnableDbi
- )
- {
- PHYSICAL_ADDRESS TargetAddress;
- UINT32 Val;
- TargetAddress = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT)
- + MISC_CONTROL_1_OFF;
- Val = MmioRead32 (TargetAddress);
- Val = DBI_RO_WR_EN_SET (Val, EnableDbi ? ENABLE_WR : DISABLE_WR);
- MmioWrite32 (TargetAddress, Val);
- }
- /**
- Setup and initialize the AC01 PCIe Root Complex and underneath PCIe controllers
- @param RootComplex Pointer to Root Complex structure
- @param ReInit Re-init status
- @param ReInitPcieIndex PCIe controller index
- @retval RETURN_SUCCESS The Root Complex has been initialized successfully.
- @retval RETURN_DEVICE_ERROR PHY, Memory or PIPE is not ready.
- **/
- RETURN_STATUS
- Ac01PcieCoreSetupRC (
- IN AC01_ROOT_COMPLEX *RootComplex,
- IN BOOLEAN ReInit,
- IN UINT8 ReInitPcieIndex
- )
- {
- PHYSICAL_ADDRESS CfgBase;
- PHYSICAL_ADDRESS CsrBase;
- PHYSICAL_ADDRESS TargetAddress;
- RETURN_STATUS Status;
- UINT32 Val;
- UINT8 PcieIndex;
- DEBUG ((DEBUG_INFO, "Initializing Socket%d RootComplex%d\n", RootComplex->Socket, RootComplex->ID));
- ProgramHostBridgeInfo (RootComplex);
- if (!ReInit) {
- Status = PciePhyInit (RootComplex->SerdesBase);
- if (RETURN_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "%a: Failed to initialize the PCIe PHY\n", __FUNCTION__));
- return RETURN_DEVICE_ERROR;
- }
- }
- // Setup each controller
- for (PcieIndex = 0; PcieIndex < RootComplex->MaxPcieController; PcieIndex++) {
- if (ReInit) {
- PcieIndex = ReInitPcieIndex;
- }
- if (!RootComplex->Pcie[PcieIndex].Active) {
- continue;
- }
- DEBUG ((DEBUG_INFO, "Initializing Controller %d\n", PcieIndex));
- CsrBase = RootComplex->Pcie[PcieIndex].CsrBase;
- CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT);
- // Put Controller into reset if not in reset already
- TargetAddress = CsrBase + AC01_PCIE_CORE_RESET_REG;
- Val = MmioRead32 (TargetAddress);
- if (!(Val & RESET_MASK)) {
- Val = DWC_PCIE_SET (Val, ASSERT_RESET);
- MmioWrite32 (TargetAddress, Val);
- // Delay 50ms to ensure controller finish its reset
- MicroSecondDelay (50000);
- }
- if (!EnableItsMemory (RootComplex, PcieIndex)) {
- DEBUG ((DEBUG_ERROR, "- Pcie[%d] - ITS Memory is not ready\n", PcieIndex));
- return RETURN_DEVICE_ERROR;
- }
- // Hold link training
- StartLinkTraining (RootComplex, PcieIndex, FALSE);
- // Clear BUSCTRL.CfgUrMask to set CRS (Configuration Request Retry Status) to 0xFFFF.FFFF
- // rather than 0xFFFF.0001 as per PCIe specification requirement. Otherwise, this causes
- // device drivers respond incorrectly on timeout due to long device operations.
- TargetAddress = CsrBase + AC01_PCIE_CORE_BUS_CONTROL_REG;
- Val = MmioRead32 (TargetAddress);
- Val &= ~BUS_CTL_CFG_UR_MASK;
- MmioWrite32 (TargetAddress, Val);
- if (!EnableAxiPipeClock (RootComplex, PcieIndex)) {
- DEBUG ((DEBUG_ERROR, "- Pcie[%d] - PIPE clock is not stable\n", PcieIndex));
- return RETURN_DEVICE_ERROR;
- }
- // Start PERST pulse
- BoardPcieAssertPerst (RootComplex, PcieIndex, TRUE);
- // Allow programming to config space
- EnableDbiAccess (RootComplex, PcieIndex, TRUE);
- // Program the power limit
- TargetAddress = CfgBase + PCIE_CAPABILITY_BASE + SLOT_CAPABILITIES_REG;
- Val = MmioRead32 (TargetAddress);
- Val = SLOT_CAP_SLOT_POWER_LIMIT_VALUE_SET (Val, SLOT_POWER_LIMIT_75W);
- MmioWrite32 (TargetAddress, Val);
- // Program DTI for ATS support
- TargetAddress = CfgBase + DTIM_CTRL0_OFF;
- Val = MmioRead32 (TargetAddress);
- Val = DTIM_CTRL0_ROOT_PORT_ID_SET (Val, 0);
- MmioWrite32 (TargetAddress, Val);
- //
- // Program number of lanes used
- // - Reprogram LINK_CAPABLE of PORT_LINK_CTRL_OFF
- // - Reprogram NUM_OF_LANES of GEN2_CTRL_OFF
- // - Reprogram CAP_MAX_LINK_WIDTH of LINK_CAPABILITIES_REG
- //
- ProgramLinkCapabilities (RootComplex, PcieIndex);
- // Set Zero byte request handling
- TargetAddress = CfgBase + FILTER_MASK_2_OFF;
- Val = MmioRead32 (TargetAddress);
- Val = CX_FLT_MASK_VENMSG0_DROP_SET (Val, 0);
- Val = CX_FLT_MASK_VENMSG1_DROP_SET (Val, 0);
- Val = CX_FLT_MASK_DABORT_4UCPL_SET (Val, 0);
- MmioWrite32 (TargetAddress, Val);
- TargetAddress = CfgBase + AMBA_ORDERING_CTRL_OFF;
- Val = MmioRead32 (TargetAddress);
- Val = AX_MSTR_ZEROLREAD_FW_SET (Val, 0);
- MmioWrite32 (TargetAddress, Val);
- //
- // Set Completion with CRS handling for CFG Request
- // Set Completion with CA/UR handling non-CFG Request
- //
- TargetAddress = CfgBase + AMBA_ERROR_RESPONSE_DEFAULT_OFF;
- Val = MmioRead32 (TargetAddress);
- // 0x2: OKAY with FFFF_0001 and FFFF_FFFF
- Val = AMBA_ERROR_RESPONSE_CRS_SET (Val, 0x2);
- MmioWrite32 (TargetAddress, Val);
- // Set Legacy PCIE interrupt map to INTA
- TargetAddress = CfgBase + BRIDGE_CTRL_INT_PIN_INT_LINE_REG;
- Val = MmioRead32 (TargetAddress);
- Val = INT_PIN_SET (Val, IRQ_INT_A);
- MmioWrite32 (TargetAddress, Val);
- TargetAddress = CsrBase + AC01_PCIE_CORE_IRQ_SEL_REG;
- Val = MmioRead32 (TargetAddress);
- Val = INTPIN_SET (Val, IRQ_INT_A);
- MmioWrite32 (TargetAddress, Val);
- if (RootComplex->Pcie[PcieIndex].MaxGen >= LINK_SPEED_GEN2) {
- ConfigureEqualization (RootComplex, PcieIndex);
- if (RootComplex->Pcie[PcieIndex].MaxGen >= LINK_SPEED_GEN3) {
- ConfigurePresetGen3 (RootComplex, PcieIndex);
- if (RootComplex->Pcie[PcieIndex].MaxGen >= LINK_SPEED_GEN4) {
- ConfigurePresetGen4 (RootComplex, PcieIndex);
- }
- }
- }
- // Link timeout after 1ms
- SetLinkTimeout (RootComplex, PcieIndex, 1);
- DisableCompletionTimeOut (RootComplex, PcieIndex, TRUE);
- ProgramRootPortInfo (RootComplex, PcieIndex);
- // Enable common clock for downstream
- TargetAddress = CfgBase + PCIE_CAPABILITY_BASE + LINK_CONTROL_LINK_STATUS_REG;
- Val = MmioRead32 (TargetAddress);
- Val = CAP_SLOT_CLK_CONFIG_SET (Val, 1);
- Val = CAP_COMMON_CLK_SET (Val, 1);
- MmioWrite32 (TargetAddress, Val);
- // Match aux_clk to system
- TargetAddress = CfgBase + AUX_CLK_FREQ_OFF;
- Val = MmioRead32 (TargetAddress);
- Val = AUX_CLK_FREQ_SET (Val, AUX_CLK_500MHZ);
- MmioWrite32 (TargetAddress, Val);
- // Assert PERST low to reset endpoint
- BoardPcieAssertPerst (RootComplex, PcieIndex, FALSE);
- // Start link training
- StartLinkTraining (RootComplex, PcieIndex, TRUE);
- // Complete the PERST pulse
- BoardPcieAssertPerst (RootComplex, PcieIndex, TRUE);
- // Lock programming of config space
- EnableDbiAccess (RootComplex, PcieIndex, FALSE);
- if (ReInit) {
- return RETURN_SUCCESS;
- }
- }
- return RETURN_SUCCESS;
- }
- BOOLEAN
- PcieLinkUpCheck (
- IN AC01_PCIE_CONTROLLER *Pcie
- )
- {
- PHYSICAL_ADDRESS CsrBase;
- UINT32 BlockEvent;
- UINT32 LinkStat;
- CsrBase = Pcie->CsrBase;
- // Check if card present
- // smlh_ltssm_state[13:8] = 0
- // phy_status[2] = 0
- // smlh_link_up[1] = 0
- // rdlh_link_up[0] = 0
- LinkStat = MmioRead32 (CsrBase + AC01_PCIE_CORE_LINK_STAT_REG);
- LinkStat = LinkStat & (SMLH_LTSSM_STATE_MASK | PHY_STATUS_MASK_BIT |
- SMLH_LINK_UP_MASK_BIT | RDLH_LINK_UP_MASK_BIT);
- if (LinkStat == 0) {
- return FALSE;
- }
- BlockEvent = MmioRead32 (CsrBase + AC01_PCIE_CORE_BLOCK_EVENT_STAT_REG);
- LinkStat = MmioRead32 (CsrBase + AC01_PCIE_CORE_LINK_STAT_REG);
- if (((BlockEvent & LINKUP_MASK) != 0)
- && (SMLH_LTSSM_STATE_GET(LinkStat) == LTSSM_STATE_L0)) {
- return TRUE;
- }
- return FALSE;
- }
- /**
- Callback function when the Host Bridge enumeration end.
- @param RootComplex Pointer to the Root Complex structure
- **/
- VOID
- Ac01PcieCoreEndEnumeration (
- IN AC01_ROOT_COMPLEX *RootComplex
- )
- {
- PHYSICAL_ADDRESS TargetAddress;
- UINT32 PcieIndex;
- UINT32 Val;
- if (RootComplex == NULL || !RootComplex->Active) {
- return;
- }
- // Clear uncorrectable error during enumuration phase. Mainly completion timeout.
- for (PcieIndex = 0; PcieIndex < RootComplex->MaxPcieController; PcieIndex++) {
- if (!RootComplex->Pcie[PcieIndex].Active) {
- continue;
- }
- if (!PcieLinkUpCheck(&RootComplex->Pcie[PcieIndex])) {
- // If link down/disabled after enumeration, disable completed time out
- DisableCompletionTimeOut (RootComplex, PcieIndex, TRUE);
- }
- // Clear all errors
- TargetAddress = RootComplex->MmcfgBase + ((PcieIndex + 1) << DEV_SHIFT) \
- + AER_CAPABILITY_BASE + UNCORR_ERR_STATUS_OFF;
- Val = MmioRead32 (TargetAddress);
- if (Val != 0) {
- // Clear error by writting
- MmioWrite32 (TargetAddress, Val);
- }
- }
- }
- /**
- Comparing current link status with the max capabilities of the link
- @param RootComplex Pointer to AC01_ROOT_COMPLEX structure
- @param PcieIndex PCIe controller index
- @param EpMaxWidth EP max link width
- @param EpMaxGen EP max link speed
- @retval -1: Link status do not match with link max capabilities
- 1: Link capabilites are invalid
- 0: Link status are correct
- **/
- INT32
- Ac01PcieCoreLinkCheck (
- IN AC01_ROOT_COMPLEX *RootComplex,
- IN UINT8 PcieIndex,
- IN UINT8 EpMaxWidth,
- IN UINT8 EpMaxGen
- )
- {
- PHYSICAL_ADDRESS CsrBase, CfgBase;
- UINT32 Val, LinkStat;
- UINT32 MaxWidth, MaxGen;
- CsrBase = RootComplex->Pcie[PcieIndex].CsrBase;
- CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT);
- Val = MmioRead32 (CfgBase + PCIE_CAPABILITY_BASE + LINK_CAPABILITIES_REG);
- if ((CAP_MAX_LINK_WIDTH_GET (Val) == 0) ||
- (CAP_MAX_LINK_SPEED_GET (Val) == 0)) {
- DEBUG ((DEBUG_INFO, "\tPCIE%d.%d: Wrong RootComplex capabilities\n", RootComplex->ID, PcieIndex));
- return LINK_CHECK_WRONG_PARAMETER;
- }
- if ((EpMaxWidth == 0) || (EpMaxGen == 0)) {
- DEBUG ((DEBUG_INFO, "\tPCIE%d.%d: Wrong EP capabilities\n", RootComplex->ID, PcieIndex));
- return LINK_CHECK_FAILED;
- }
- // Compare RootComplex and EP capabilities
- if (CAP_MAX_LINK_WIDTH_GET (Val) > EpMaxWidth) {
- MaxWidth = EpMaxWidth;
- } else {
- MaxWidth = CAP_MAX_LINK_WIDTH_GET (Val);
- }
- // Compare RootComplex and EP capabilities
- if (CAP_MAX_LINK_SPEED_GET (Val) > EpMaxGen) {
- MaxGen = EpMaxGen;
- } else {
- MaxGen = CAP_MAX_LINK_SPEED_GET (Val);
- }
- LinkStat = MmioRead32 (CsrBase + AC01_PCIE_CORE_LINK_STAT_REG);
- Val = MmioRead32 (CfgBase + PCIE_CAPABILITY_BASE + LINK_CONTROL_LINK_STATUS_REG);
- DEBUG ((
- DEBUG_INFO,
- "PCIE%d.%d: Link MaxWidth %d MaxGen %d, AC01_PCIE_CORE_LINK_STAT_REG 0x%x",
- RootComplex->ID,
- PcieIndex,
- MaxWidth,
- MaxGen,
- LinkStat
- ));
- // Checking all conditions of the link
- // If one of them is not sastified, return link up fail
- if ((CAP_NEGO_LINK_WIDTH_GET (Val) != MaxWidth) ||
- (CAP_LINK_SPEED_GET (Val) != MaxGen) ||
- (RDLH_SMLH_LINKUP_STATUS_GET (LinkStat) != (SMLH_LINK_UP_MASK_BIT | RDLH_LINK_UP_MASK_BIT)))
- {
- DEBUG ((DEBUG_INFO, "\tLinkCheck FAILED\n"));
- return LINK_CHECK_FAILED;
- }
- DEBUG ((DEBUG_INFO, "\tLinkCheck SUCCESS\n"));
- return LINK_CHECK_SUCCESS;
- }
- INT32
- PFACounterRead (
- IN AC01_ROOT_COMPLEX *RootComplex,
- IN UINT8 PcieIndex,
- IN UINT64 RasDesCapabilityBase
- )
- {
- INT32 Ret = LINK_CHECK_SUCCESS;
- UINT32 Val;
- UINT8 ErrCode, ErrGrpNum;
- UINT32 ErrCtrlCfg[] = {
- 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, 0x008, 0x009, 0x00A, // Per Lane
- 0x105, 0x106, 0x107, 0x108, 0x109, 0x10A,
- 0x200, 0x201, 0x202, 0x203, 0x204, 0x205, 0x206, 0x207,
- 0x300, 0x301, 0x302, 0x303, 0x304, 0x305,
- 0x400, 0x401, // Per Lane
- 0x500, 0x501, 0x502, 0x503, 0x504, 0x505, 0x506, 0x507, 0x508, 0x509, 0x50A, 0x50B, 0x50C, 0x50D
- };
- for (ErrCode = 0; ErrCode < ARRAY_SIZE (ErrCtrlCfg); ErrCode++) {
- ErrGrpNum = GET_HIGH_8_BITS (ErrCtrlCfg[ErrCode]);
- // Skipping per lane group
- // Checking common lane group because AER error are included in common group only
- if ((ErrGrpNum != 0) && (ErrGrpNum != 4)) {
- Val = MmioRead32 (RasDesCapabilityBase + EVENT_COUNTER_CONTROL_REG);
- if (RootComplex->Type == RootComplexTypeA) {
- // RootComplexTypeA - 4 PCIe controller per port, 1 controller in charge of 4 lanes
- Val = ECCR_LANE_SEL_SET (Val, PcieIndex * 4);
- } else {
- // RootComplexTypeB - 8 PCIe controller per port, 1 controller in charge of 2 lanes
- Val = ECCR_LANE_SEL_SET (Val, PcieIndex * 2);
- }
- Val = ECCR_GROUP_EVENT_SEL_SET (Val, ErrCtrlCfg[ErrCode]);
- MmioWrite32 (RasDesCapabilityBase + EVENT_COUNTER_CONTROL_REG, Val);
- // After setting Counter Control reg
- // This delay just to make sure Counter Data reg is update with new value
- MicroSecondDelay (1);
- Val = MmioRead32 (RasDesCapabilityBase + EVENT_COUNTER_DATA_REG);
- if (Val != 0) {
- Ret = LINK_CHECK_FAILED;
- DEBUG ((
- DEBUG_ERROR,
- "\tSocket%d RootComplex%d RP%d \t%s: %d \tGROUP:%d-EVENT:%d\n",
- RootComplex->Socket,
- RootComplex->ID,
- PcieIndex,
- Val,
- ErrGrpNum,
- GET_LOW_8_BITS (ErrCtrlCfg[ErrCode])
- ));
- }
- }
- }
- return Ret;
- }
- /**
- Handle Predictive Failure Analysis command
- @param RootComplex Pointer to Root Complex structure
- @param PcieIndex PCIe controller index
- @param PFAMode The PFA mode
- @retval The link status
- **/
- INT32
- Ac01PFACommand (
- IN AC01_ROOT_COMPLEX *RootComplex,
- IN UINT8 PcieIndex,
- IN UINT8 PFAMode
- )
- {
- PHYSICAL_ADDRESS RasDesCapabilityBase;
- PHYSICAL_ADDRESS TargetAddress;
- INT32 Ret = LINK_CHECK_SUCCESS;
- UINT32 Val;
- // Allow programming to config space
- EnableDbiAccess (RootComplex, PcieIndex, TRUE);
- // Get the RAS D.E.S. capability base address
- RasDesCapabilityBase = GetCapabilityBase (RootComplex, PcieIndex, TRUE, RAS_DES_CAPABILITY_ID);
- if (RasDesCapabilityBase == 0) {
- DEBUG ((DEBUG_INFO, "PCIE%d.%d: Cannot get RAS DES capability address\n", RootComplex->ID, PcieIndex));
- return LINK_CHECK_WRONG_PARAMETER;
- }
- TargetAddress = RasDesCapabilityBase + EVENT_COUNTER_CONTROL_REG;
- switch (PFAMode) {
- case PFA_MODE_ENABLE:
- Val = MmioRead32 (TargetAddress);
- Val = ECCR_EVENT_COUNTER_ENABLE_SET (Val, EVENT_COUNTER_ENABLE_ALL_ON);
- Val = ECCR_EVENT_COUNTER_CLEAR_SET (Val, EVENT_COUNTER_CLEAR_NO_CHANGE);
- MmioWrite32 (TargetAddress, Val);
- break;
- case PFA_MODE_CLEAR:
- Val = MmioRead32 (TargetAddress);
- Val = ECCR_EVENT_COUNTER_ENABLE_SET (Val, EVENT_COUNTER_ENABLE_NO_CHANGE);
- Val = ECCR_EVENT_COUNTER_CLEAR_SET (Val, EVENT_COUNTER_CLEAR_ALL_CLEAR);
- MmioWrite32 (TargetAddress, Val);
- break;
- case PFA_MODE_READ:
- Ret = PFACounterRead (RootComplex, PcieIndex, RasDesCapabilityBase);
- break;
- default:
- DEBUG ((DEBUG_ERROR, "%a: Invalid PFA mode\n"));
- }
- // Disable programming to config space
- EnableDbiAccess (RootComplex, PcieIndex, FALSE);
- return Ret;
- }
- BOOLEAN
- EndpointCfgReady (
- IN AC01_ROOT_COMPLEX *RootComplex,
- IN UINT8 PcieIndex,
- IN UINT32 TimeOut
- )
- {
- PHYSICAL_ADDRESS CfgBase;
- UINT32 Val;
- CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << BUS_SHIFT);
- // Loop read CfgBase value until got valid value or
- // reach to Timeout (or more depend on card)
- do {
- Val = MmioRead32 (CfgBase);
- if (Val != 0xFFFF0001 && Val != 0xFFFFFFFF) {
- return TRUE;
- }
- TimeOut -= LINK_WAIT_INTERVAL_US;
- MicroSecondDelay (LINK_WAIT_INTERVAL_US);
- } while (TimeOut > 0);
- return FALSE;
- }
- /**
- Get link capabilities link width and speed of endpoint
- @param RootComplex[in] Pointer to AC01_ROOT_COMPLEX structure
- @param PcieIndex[in] PCIe controller index
- @param EpMaxWidth[out] EP max link width
- @param EpMaxGen[out] EP max link speed
- **/
- VOID
- Ac01PcieCoreGetEndpointInfo (
- IN AC01_ROOT_COMPLEX *RootComplex,
- IN UINT8 PcieIndex,
- OUT UINT8 *EpMaxWidth,
- OUT UINT8 *EpMaxGen
- )
- {
- PHYSICAL_ADDRESS CfgBase;
- PHYSICAL_ADDRESS EpCfgAddr;
- PHYSICAL_ADDRESS PcieCapBase;
- PHYSICAL_ADDRESS SecLatTimerAddr;
- PHYSICAL_ADDRESS TargetAddress;
- UINT32 RestoreVal;
- UINT32 Val;
- CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT);
- SecLatTimerAddr = CfgBase + SEC_LAT_TIMER_SUB_BUS_SEC_BUS_PRI_BUS_REG;
- *EpMaxWidth = 0;
- *EpMaxGen = 0;
- // Allow programming to config space
- EnableDbiAccess (RootComplex, PcieIndex, TRUE);
- Val = MmioRead32 (SecLatTimerAddr);
- RestoreVal = Val;
- Val = SUB_BUS_SET (Val, DEFAULT_SUB_BUS);
- Val = SEC_BUS_SET (Val, RootComplex->Pcie[PcieIndex].DevNum);
- Val = PRIM_BUS_SET (Val, DEFAULT_PRIM_BUS);
- MmioWrite32 (SecLatTimerAddr, Val);
- EpCfgAddr = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << BUS_SHIFT);
- if (!EndpointCfgReady (RootComplex, PcieIndex, EP_LINKUP_EXTRA_TIMEOUT)) {
- goto Exit;
- }
- Val = MmioRead32 (EpCfgAddr);
- // Check whether EP config space is accessible or not
- if (Val == 0xFFFFFFFF) {
- *EpMaxWidth = 0; // Invalid Width
- *EpMaxGen = 0; // Invalid Speed
- DEBUG ((DEBUG_ERROR, "PCIE%d.%d Cannot access EP config space!\n", RootComplex->ID, PcieIndex));
- } else if (Val == 0xFFFF0001) {
- *EpMaxWidth = 0; // Invalid Width
- *EpMaxGen = 0; // Invalid Speed
- DEBUG ((DEBUG_ERROR, "PCIE%d.%d EP config space still not ready to access, need poll more time!!!\n", RootComplex->ID, PcieIndex));
- } else {
- PcieCapBase = GetCapabilityBase (RootComplex, PcieIndex, FALSE, PCIE_CAPABILITY_ID);
- if (PcieCapBase == 0) {
- DEBUG ((
- DEBUG_ERROR,
- "PCIE%d.%d Cannot get PCIe capability base address!\n",
- RootComplex->ID,
- PcieIndex
- ));
- } else {
- Val = MmioRead32 (PcieCapBase + LINK_CAPABILITIES_REG);
- *EpMaxWidth = CAP_MAX_LINK_WIDTH_GET (Val);
- *EpMaxGen = CAP_MAX_LINK_SPEED_GET (Val);
- DEBUG ((
- DEBUG_INFO,
- "PCIE%d.%d EP MaxWidth %d EP MaxGen %d \n", RootComplex->ID,
- PcieIndex,
- *EpMaxWidth,
- *EpMaxGen
- ));
- // From EP, enabling common clock for upstream
- TargetAddress = PcieCapBase + LINK_CONTROL_LINK_STATUS_REG;
- Val = MmioRead32 (TargetAddress);
- Val = CAP_SLOT_CLK_CONFIG_SET (Val, 1);
- Val = CAP_COMMON_CLK_SET (Val, 1);
- MmioWrite32 (TargetAddress, Val);
- }
- }
- Exit:
- // Restore value in order to not affect enumeration process
- MmioWrite32 (SecLatTimerAddr, RestoreVal);
- // Disable programming to config space
- EnableDbiAccess (RootComplex, PcieIndex, FALSE);
- }
- VOID
- PollLinkUp (
- IN AC01_ROOT_COMPLEX *RootComplex,
- IN UINT8 PcieIndex
- )
- {
- UINT32 TimeOut;
- // Poll until link up
- // This checking for linkup status and
- // give LTSSM state the time to transit from DECTECT state to L0 state
- // Total delay are 100ms, smaller number of delay cannot always make sure
- // the state transition is completed
- TimeOut = LTSSM_TRANSITION_TIMEOUT;
- do {
- if (PcieLinkUpCheck (&RootComplex->Pcie[PcieIndex])) {
- DEBUG ((
- DEBUG_INFO,
- "\tPCIE%d.%d LinkStat is correct after soft reset, transition time: %d\n",
- RootComplex->ID,
- PcieIndex,
- TimeOut
- ));
- RootComplex->Pcie[PcieIndex].LinkUp = TRUE;
- break;
- }
- MicroSecondDelay (100);
- TimeOut -= 100;
- } while (TimeOut > 0);
- if (TimeOut <= 0) {
- DEBUG ((DEBUG_ERROR, "\tPCIE%d.%d LinkStat TIMEOUT after re-init\n", RootComplex->ID, PcieIndex));
- } else {
- DEBUG ((DEBUG_INFO, "PCIE%d.%d Link re-initialization passed!\n", RootComplex->ID, PcieIndex));
- }
- }
- /**
- Check active PCIe controllers of RootComplex, retrain or soft reset if needed
- @param RootComplex[in] Pointer to AC01_ROOT_COMPLEX structure
- @param PcieIndex[in] PCIe controller index
- @retval -1: Link recovery had failed
- 1: Link width and speed are not correct
- 0: Link recovery succeed
- **/
- INT32
- Ac01PcieCoreQoSLinkCheckRecovery (
- IN AC01_ROOT_COMPLEX *RootComplex,
- IN UINT8 PcieIndex
- )
- {
- INT32 LinkStatusCheck, RasdesChecking;
- INT32 NumberOfReset = MAX_REINIT;
- UINT8 EpMaxWidth, EpMaxGen;
- // PCIe controller is not active or Link is not up
- // Nothing to be done
- if ((!RootComplex->Pcie[PcieIndex].Active) || (!RootComplex->Pcie[PcieIndex].LinkUp)) {
- return LINK_CHECK_WRONG_PARAMETER;
- }
- do {
- if (RootComplex->Pcie[PcieIndex].LinkUp) {
- // Enable all of RASDES register to detect any training error
- Ac01PFACommand (RootComplex, PcieIndex, PFA_MODE_ENABLE);
- // Accessing Endpoint and checking current link capabilities
- Ac01PcieCoreGetEndpointInfo (RootComplex, PcieIndex, &EpMaxWidth, &EpMaxGen);
- LinkStatusCheck = Ac01PcieCoreLinkCheck (RootComplex, PcieIndex, EpMaxWidth, EpMaxGen);
- // Delay to allow the link to perform internal operation and generate
- // any error status update. This allows detection of any error observed
- // during initial link training. Possible evaluation time can be
- // between 100ms to 200ms.
- MicroSecondDelay (100000);
- // Check for error
- RasdesChecking = Ac01PFACommand (RootComplex, PcieIndex, PFA_MODE_READ);
- // Clear error counter
- Ac01PFACommand (RootComplex, PcieIndex, PFA_MODE_CLEAR);
- // If link check functions return passed, then breaking out
- // else go to soft reset
- if (LinkStatusCheck != LINK_CHECK_FAILED &&
- RasdesChecking != LINK_CHECK_FAILED &&
- PcieLinkUpCheck (&RootComplex->Pcie[PcieIndex]))
- {
- return LINK_CHECK_SUCCESS;
- }
- RootComplex->Pcie[PcieIndex].LinkUp = FALSE;
- }
- // Trigger controller soft reset
- DEBUG ((DEBUG_INFO, "PCIE%d.%d Start link re-initialization..\n", RootComplex->ID, PcieIndex));
- Ac01PcieCoreSetupRC (RootComplex, TRUE, PcieIndex);
- PollLinkUp (RootComplex, PcieIndex);
- NumberOfReset--;
- } while (NumberOfReset > 0);
- return LINK_CHECK_SUCCESS;
- }
- BOOLEAN
- Ac01PcieCoreCheckCardPresent (
- IN AC01_PCIE_CONTROLLER *PcieController
- )
- {
- EFI_PHYSICAL_ADDRESS TargetAddress;
- UINT32 ControlValue;
- ControlValue = 0;
- TargetAddress = PcieController->CsrBase;
- ControlValue = MmioRead32 (TargetAddress + AC01_PCIE_CORE_LINK_CTRL_REG);
- if (0 == LTSSMENB_GET (ControlValue)) {
- //
- // LTSSMENB is clear to 0x00 by Hardware -> link partner is connected.
- //
- return TRUE;
- }
- return FALSE;
- }
- VOID
- Ac01PcieCoreUpdateLink (
- IN AC01_ROOT_COMPLEX *RootComplex,
- OUT BOOLEAN *IsNextRoundNeeded,
- OUT INT8 *FailedPciePtr,
- OUT INT8 *FailedPcieCount
- )
- {
- AC01_PCIE_CONTROLLER *Pcie;
- PHYSICAL_ADDRESS CfgBase;
- UINT8 PcieIndex;
- UINT32 Index;
- UINT32 Val;
- *IsNextRoundNeeded = FALSE;
- *FailedPcieCount = 0;
- for (Index = 0; Index < MaxPcieControllerOfRootComplexB; Index++) {
- FailedPciePtr[Index] = -1;
- }
- if (!RootComplex->Active) {
- return;
- }
- // Loop for all controllers
- for (PcieIndex = 0; PcieIndex < RootComplex->MaxPcieController; PcieIndex++) {
- Pcie = &RootComplex->Pcie[PcieIndex];
- CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT);
- if (Pcie->Active && !Pcie->LinkUp) {
- if (PcieLinkUpCheck (Pcie)) {
- Pcie->LinkUp = TRUE;
- Val = MmioRead32 (CfgBase + PCIE_CAPABILITY_BASE + LINK_CONTROL_LINK_STATUS_REG);
- // Doing link checking and recovery if needed
- Ac01PcieCoreQoSLinkCheckRecovery (RootComplex, PcieIndex);
- // Un-mask Completion Timeout
- DisableCompletionTimeOut (RootComplex, PcieIndex, FALSE);
- } else {
- FailedPciePtr[*FailedPcieCount] = PcieIndex;
- *FailedPcieCount += 1;
- *IsNextRoundNeeded = !(*IsNextRoundNeeded) ? Ac01PcieCoreCheckCardPresent (Pcie) : TRUE;
- }
- }
- }
- }
- /**
- Verify the link status and retry to initialize the Root Complex if there's any issue.
- @param RootComplexList Pointer to the Root Complex list
- **/
- VOID
- Ac01PcieCorePostSetupRC (
- IN AC01_ROOT_COMPLEX *RootComplexList
- )
- {
- UINT8 RCIndex, Idx;
- BOOLEAN IsNextRoundNeeded, NextRoundNeeded;
- UINT64 PrevTick, CurrTick, ElapsedCycle;
- UINT64 TimerTicks64;
- UINT8 ReInit;
- INT8 FailedPciePtr[MaxPcieControllerOfRootComplexB];
- INT8 FailedPcieCount;
- ReInit = 0;
- _link_polling:
- NextRoundNeeded = FALSE;
- //
- // It is not guaranteed the timer service is ready prior to PCI Dxe.
- // Calculate system ticks for link training.
- //
- TimerTicks64 = ArmGenericTimerGetTimerFreq (); /* 1 Second */
- PrevTick = ArmGenericTimerGetSystemCount ();
- ElapsedCycle = 0;
- do {
- CurrTick = ArmGenericTimerGetSystemCount ();
- if (CurrTick < PrevTick) {
- ElapsedCycle += MAX_UINT64 - PrevTick;
- PrevTick = 0;
- }
- ElapsedCycle += (CurrTick - PrevTick);
- PrevTick = CurrTick;
- } while (ElapsedCycle < TimerTicks64);
- for (RCIndex = 0; RCIndex < AC01_PCIE_MAX_ROOT_COMPLEX; RCIndex++) {
- Ac01PcieCoreUpdateLink (&RootComplexList[RCIndex], &IsNextRoundNeeded, FailedPciePtr, &FailedPcieCount);
- if (IsNextRoundNeeded) {
- NextRoundNeeded = TRUE;
- }
- }
- if (NextRoundNeeded && ReInit < MAX_REINIT) {
- //
- // Timer is up. Give another chance to re-program controller
- //
- ReInit++;
- for (RCIndex = 0; RCIndex < AC01_PCIE_MAX_ROOT_COMPLEX; RCIndex++) {
- Ac01PcieCoreUpdateLink (&RootComplexList[RCIndex], &IsNextRoundNeeded, FailedPciePtr, &FailedPcieCount);
- if (IsNextRoundNeeded) {
- for (Idx = 0; Idx < FailedPcieCount; Idx++) {
- if (FailedPciePtr[Idx] == -1) {
- continue;
- }
- //
- // Some controller still observes link-down. Re-init controller
- //
- Ac01PcieCoreSetupRC (&RootComplexList[RCIndex], TRUE, FailedPciePtr[Idx]);
- }
- }
- }
- goto _link_polling;
- }
- }
|