/** @file
Pcie board specific driver to handle asserting PERST signal to Endpoint
card. PERST asserting is via group of GPIO pins to CPLD as Platform Specification.
Copyright (c) 2020 - 2023, Ampere Computing LLC. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#define RCA_MAX_PERST_GROUPVAL 62
#define RCB_MAX_PERST_GROUPVAL 46
#define DEFAULT_SEGMENT_NUMBER 0x0F
#define PCIE_PERST_DELAY (100 * 1000) // 100ms
VOID
BoardPcieReleaseAllPerst (
IN UINT8 SocketId
)
{
UINT32 GpioIndex, GpioPin;
// Write 1 to all GPIO[16..21] to release all PERST
GpioPin = AC01_GPIO_PINS_PER_SOCKET * SocketId + 16;
for (GpioIndex = 0; GpioIndex < 6; GpioIndex++) {
GpioModeConfig (GpioPin + GpioIndex, GpioConfigOutHigh);
}
MicroSecondDelay (PCIE_PERST_DELAY);
}
EFI_STATUS
GetGpioGroup (
IN UINT8 RootComplexId,
IN UINT8 PcieIndex,
OUT UINT32 *GpioGroupVal
)
{
/* Ampere Altra Max RootComplex->ID: 4:7 */
if (PcieIndex < 2) {
switch (RootComplexId) {
case 4:
*GpioGroupVal = 34 - (PcieIndex * 2);
break;
case 5:
*GpioGroupVal = 38 - (PcieIndex * 2);
break;
case 6:
*GpioGroupVal = 30 - (PcieIndex * 2);
break;
case 7:
*GpioGroupVal = 26 - (PcieIndex * 2);
break;
default:
return EFI_INVALID_PARAMETER;
}
} else {
/* Ampere Altra Max RootComplex->ID: 4:7 */
switch (RootComplexId) {
case 4:
*GpioGroupVal = 46 - ((PcieIndex - 2) * 2);
break;
case 5:
*GpioGroupVal = 42 - ((PcieIndex - 2) * 2);
break;
case 6:
*GpioGroupVal = 18 - ((PcieIndex - 2) * 2);
break;
case 7:
*GpioGroupVal = 22 - ((PcieIndex - 2) * 2);
break;
default:
return EFI_INVALID_PARAMETER;
}
}
return EFI_SUCCESS;
}
/**
Assert PERST of PCIe controller
@param[in] RootComplex Root Complex instance.
@param[in] PcieIndex PCIe controller index of input Root Complex.
@param[in] IsPullToHigh Target status for the PERST.
@retval RETURN_SUCCESS The operation is successful.
@retval Others An error occurred.
**/
RETURN_STATUS
EFIAPI
BoardPcieAssertPerst (
IN AC01_ROOT_COMPLEX *RootComplex,
IN UINT8 PcieIndex,
IN BOOLEAN IsPullToHigh
)
{
UINT32 GpioGroupVal;
UINT32 Val;
UINT32 GpioIndex;
UINT32 GpioPin;
EFI_STATUS Status;
if (!IsPullToHigh) {
if (RootComplex->Type == RootComplexTypeA) {
if (RootComplex->ID < MaxPcieControllerOfRootComplexA) {
/* Ampere Altra: 4 */
//
// RootComplexTypeA: RootComplex->ID: 0->3 ; PcieIndex: 0->3
//
GpioGroupVal = RCA_MAX_PERST_GROUPVAL - PcieIndex
- RootComplex->ID * MaxPcieControllerOfRootComplexA;
} else {
Status = GetGpioGroup (RootComplex->ID, PcieIndex, &GpioGroupVal);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Invalid Root Complex ID %d\n", RootComplex->ID));
return Status;
}
}
} else {
//
// RootComplexTypeB: RootComplex->ID: 4->7 ; PcieIndex: 0->7
//
GpioGroupVal = RCB_MAX_PERST_GROUPVAL - PcieIndex
- (RootComplex->ID - MaxRootComplexA) * MaxPcieControllerOfRootComplexB;
}
// Update the value of GPIO[16..21]. Corresponding PERST line will be decoded by CPLD.
GpioPin = AC01_GPIO_PINS_PER_SOCKET * RootComplex->Socket + 16;
for (GpioIndex = 0; GpioIndex < 6; GpioIndex++) {
Val = (GpioGroupVal & 0x3F) & (1 << GpioIndex);
if (Val == 0) {
GpioModeConfig (GpioPin + GpioIndex, GpioConfigOutLow);
} else {
GpioModeConfig (GpioPin + GpioIndex, GpioConfigOutHigh);
}
}
// Keep reset as low as 100 ms as specification
MicroSecondDelay (PCIE_PERST_DELAY);
} else {
BoardPcieReleaseAllPerst (RootComplex->Socket);
}
return RETURN_SUCCESS;
}
/**
Override the segment number for a root complex with a board specific number.
@param[in] RootComplex Root Complex instance with properties.
@retval Segment number corresponding to the input root complex.
Default segment number is 0x0F.
**/
UINT16
BoardPcieGetSegmentNumber (
IN AC01_ROOT_COMPLEX *RootComplex
)
{
UINT8 Ac01BoardSegment[PLATFORM_CPU_MAX_SOCKET][AC01_PCIE_MAX_ROOT_COMPLEX] =
{
{ 0x0C, 0x0D, 0x01, 0x00, 0x02, 0x03, 0x04, 0x05 },
{ 0x10, 0x11, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B }
};
if (RootComplex->Socket < PLATFORM_CPU_MAX_SOCKET
&& RootComplex->ID < AC01_PCIE_MAX_ROOT_COMPLEX) {
return Ac01BoardSegment[RootComplex->Socket][RootComplex->ID];
}
return (RootComplex->ID - 2);
}