Tool/software: TI-RTOS
Today I learned something about PCIe Subsystem Reset that might be helpful to others so I thought I'd pass it along.
We were having issues with PCIe getting to Gen2 reliably. We tried to do a recovery where if it fails to get into
Gen2 we restarted the PCIe configuration including the PCIe Reset function from the AM5728 sample code, specifically
pcie_sample_board.c function PlatformPCIESS1Reset().
void PlatformPCIESS1Reset(void)
{
/*Reset PCIeSS1*/
HW_WR_FIELD32(SOC_L3INIT_PRM_BASE + RM_PCIESS_RSTCTRL,
RM_PCIESS_RSTCTRL_RST_LOCAL_PCIE1,
RM_PCIESS_RSTCTRL_RST_LOCAL_PCIE1_CLEAR);
/* Wait till PCIeSS1 is out of reset */
while (((HW_RD_REG32(SOC_L3INIT_PRM_BASE + RM_PCIESS_RSTST) &
RM_PCIESS_RSTST_RST_LOCAL_PCIE1_MASK) <<
RM_PCIESS_RSTST_RST_LOCAL_PCIE1_SHIFT) !=
RM_PCIESS_RSTST_RST_LOCAL_PCIE1_RESET_YES)
{
;
}
}
The TRM says the following about the Reset Register RM_PCIESS_RSTCTRL.
0x0: Reset is cleared for the PCIE1
0x1: Reset is asserted for the PCIE1
I don't believe that is accurate. What needs to happen to cause a reset is to toggle the RST_LOCAL_PCIE bit from
1 to 0. The sample code shown above attempts to do this by counter intuitively clearing the reset bit, via the usage
of RM_PCIESS_RSTCTRL_RST_LOCAL_PCIE1_CLEAR. This however, assumes that the bit is currently a 1, which it is after a
power up of the PCIESS, but not after any subsequent usage. Important to also note that the status bits discussed
below, do not become a 1 until the reset is driven low.
The status bits are also confusing to use. The TRM says,
0x0: No SW reset occurred
0x1: PCIE1 has been reset upon SW reset
What the TRM doesn't say is that in order to clear the status bit you need to write a 1 to that bit. If you don't do
that, then next time you call this function, the status bit is already set from the last status and the function completes
successfully even though a reset never occurred.
On top of this, the low level programming model contradicts the code above this by saying,
2.Assert a local SW main reset to the PCIe_SS1,2 PRCM.RM_PCIESS_RSTCTRL[0] 0b1
controllers RST_LOCAL_PCIE1
PRCM.RM_PCIESS_RSTCTRL[1]
RST_LOCAL_PCIE2
3.Poll main reset completion status for the PRCM.RM_PCIESS_RSTST[0] =0b1
PCIe_SS1,2 controllers RST_LOCAL_PCIE1
PRCM.RM_PCIESS_RSTST[1]
RST_LOCAL_PCIE2
What I have found to work well now is the following:
1) Clear the status register, RM_PCIESS_RSTST, by writing a 1 to the desired status bit.
2) Write a 1 to the desired bit in RM_PCIESS_RSTCTRL.
3) Verify the RSTCTRL bit did indeed go to a 1, loop and retry if not.
4) Write a 0 to the desired bit in RM_PCIESS_RSTCTRL. (This is what actually causes the reset and the status to be updated.)
5) Wait for the desired status bit in RM_PCIESS_RSTST to go to a 1.
Using this new code model, things have improved greatly for us. We had an issue where the PCIE state would sometimes
get locked into PRE_DETECT_QUIET on startup. That seems to be better if not fixed. Then when trying to up-train to GEN2,
we would end up in DETECT_QUIET state. We can get into L0 now, but completely starting the PCIe code over again including
the new improved Reset code outlined above.