aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChenhui Sun <sunchenhui@huawei.com>2017-03-18 09:04:00 +0800
committerLeif Lindholm <leif.lindholm@linaro.org>2017-04-10 14:57:18 +0100
commit25d6112ca7d1e943c286dde587ab6d50986e45a1 (patch)
tree44a5b5116f57d37138b71f78cc930fde2cee9b05
parentb85b9ea08d9607d113e41bfe97f9d8e86b636afd (diff)
Hisilicon: Add reconfig lane number feature
In some cases, the PCIe device may close part of lanes in config state of LTSSM, the hip06 RC should reconfig lane number and try to linkup again. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Chenhui Sun <sunchenhui@huawei.com> Signed-off-by: Heyi Guo <heyi.guo@linaro.org> Signed-off-by: Yi Li <phoenix.liyi@huawei.com> Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
-rw-r--r--Chips/Hisilicon/Hi1610/Drivers/PcieInit1610/PcieInitLib.c136
-rw-r--r--Chips/Hisilicon/Include/Regs/HisiPcieV1RegOffset.h5
2 files changed, 139 insertions, 2 deletions
diff --git a/Chips/Hisilicon/Hi1610/Drivers/PcieInit1610/PcieInitLib.c b/Chips/Hisilicon/Hi1610/Drivers/PcieInit1610/PcieInitLib.c
index 1df7a90..8ab7fa3 100644
--- a/Chips/Hisilicon/Hi1610/Drivers/PcieInit1610/PcieInitLib.c
+++ b/Chips/Hisilicon/Hi1610/Drivers/PcieInit1610/PcieInitLib.c
@@ -39,6 +39,14 @@ extern PCIE_DRIVER_CFG gastr_pcie_driver_cfg;
extern PCIE_IATU gastr_pcie_iatu_cfg;
extern PCIE_IATU_VA mPcieIatuTable;
+EFI_STATUS
+EFIAPI
+PciePortInit (
+ IN UINT32 soctype,
+ IN UINT32 HostBridgeNum,
+ IN PCIE_DRIVER_CFG *PcieCfg
+ );
+
VOID PcieRegWrite(UINT32 Port, UINTN Offset, UINT32 Value)
{
RegWrite((UINT64)mPcieIntCfg.RegResource[Port] + Offset, Value);
@@ -149,8 +157,131 @@ VOID PcieRxValidCtrl(UINT32 soctype, UINT32 HostBridgeNum, UINT32 Port, BOOLEAN
}
}
}
+/*
+ * The ltssm register is assigned in an asynchronous way, the value
+ * of register may not right in metastable state.
+ * Read the register twice to get stable value.
+ */
+VOID PcieGetLtssmValue (
+ IN UINT32 HostBridgeNum,
+ IN UINT32 Port,
+ IN UINT32 *Value
+ )
+{
+ UINT32 ValueA;
+ UINT32 ValueB = 0;
+ UINT32 Count;
+
+ RegRead (PCIE_APB_SLAVE_BASE_1610[HostBridgeNum][Port] + PCIE_SYS_REG_OFFSET + PCIE_SYS_STATE4_REG, ValueA);
+ ValueA = ValueA & PCIE_LTSSM_STATE_MASK;
+
+ Count = 0;
+ while (Count < 2) {
+
+ RegRead (PCIE_APB_SLAVE_BASE_1610[HostBridgeNum][Port] + PCIE_SYS_REG_OFFSET + PCIE_SYS_STATE4_REG, ValueB);
+ ValueB = ValueB & PCIE_LTSSM_STATE_MASK;
+
+ /* Get the same state in continuous two times*/
+ if (ValueA == ValueB) {
+ break;
+ }
+
+ //If the second value not equal to the first, we return the second one as the stable
+ ValueA = ValueB;
+ Count++;
+ }
+
+ *Value = ValueB;
+
+ return;
+
+}
+
+/*
+ * In some cases, the PCIe device may close part of lanes in
+ * config state of LTSSM, the hip06 RC should reconfig lane num
+ * and try to linkup again.
+ */
+VOID PcieReconfigLaneNum (
+ IN UINT32 soctype,
+ IN UINT32 HostBridgeNum,
+ IN UINT32 Port,
+ IN PCIE_DRIVER_CFG *PcieCfg
+ )
+{
+ EFI_STATUS Status;
+ UINT32 LtssmStatus;
+ UINT32 RegVal;
+ UINT32 LoopCnt = 0;
+ UINT32 LaneNumCnt = 0;
+ PCIE_PORT_WIDTH PortWidth = PcieCfg->PortInfo.PortWidth;
+
+ // 500 * 200us = 100ms, so it takes 100 ms must to reconfig lane numbers
+ while (LoopCnt < 500) {
+
+ /*
+ * The minimum lanenum is 1, no need to try any more.
+ */
+ if (PortWidth <= 1) {
+ DEBUG ((DEBUG_ERROR, "PcieReconfigLanenum PortWidth <= 1 !\n"));
+ return;
+ }
+
+ /*
+ * Check the lane num config state is normal or not.
+ */
+ PcieGetLtssmValue (HostBridgeNum, Port, &LtssmStatus);
+ if ((LtssmStatus == PCIE_LTSSM_CFG_LANENUM_ACPT) || (LtssmStatus == PCIE_LTSSM_CFG_COMPLETE)) {
+ LaneNumCnt++;
+ } else if (LtssmStatus == PCIE_LTSSM_LINKUP_STATE) {
+ PcieGetLtssmValue (HostBridgeNum, Port, &LtssmStatus);
+ if (LtssmStatus == PCIE_LTSSM_LINKUP_STATE) {
+ break;
+ }
+ } else {
+ LaneNumCnt = 0;
+ }
+
+ /*
+ * The lane num config state is abnormal, need to reconfig
+ * the lane num and try to establish link again.
+ */
+ if (LaneNumCnt > MAX_TRY_LINK_NUM) {
+ /* Disable LTSSM */
+ RegRead (PCIE_APB_SLAVE_BASE_1610[HostBridgeNum][Port] + PCIE_CTRL_7_REG, RegVal);
+ RegVal &= ~(LTSSM_ENABLE);
+ RegWrite (PCIE_APB_SLAVE_BASE_1610[HostBridgeNum][Port] + PCIE_CTRL_7_REG, RegVal);
+ /*
+ * Decrease the PortWidth and try to link again,
+ * the value of PortWidth 0xf (X8), 0x7(x4), 0x3(X2), 0x1(X1)
+ */
+ PcieCfg->PortInfo.PortWidth = (PCIE_PORT_WIDTH)((UINT8)PcieCfg->PortInfo.PortWidth >> 1);
+
+ Status = PciePortInit (soctype, HostBridgeNum, PcieCfg);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "PcieReconfigLanenum HostBridge %d, Pcie Port %d Init Failed! \n", HostBridgeNum, Port));
+ }
+ return;
+ }
+
+ LoopCnt++;
+ /* Pcie 3.0 Spec,part 4.2.6.3.4.1: the Upstream Lanes are permitted
+ * delay up to 1 ms before transitioning to Configuration.Lanenum.Accept.
+ * So the delay time 200 us * 5(LanNumCnt) = 1ms, not beyond the reasonable range.
+ */
+ MicroSecondDelay (200);
+ }
+
+ return ;
+}
-EFI_STATUS PcieEnableItssm(UINT32 soctype, UINT32 HostBridgeNum, UINT32 Port)
+EFI_STATUS
+PcieEnableItssm (
+ IN UINT32 soctype,
+ IN UINT32 HostBridgeNum,
+ IN UINT32 Port,
+ IN PCIE_DRIVER_CFG *PcieCfg
+ )
{
PCIE_CTRL_7_U pcie_ctrl7;
UINT32 Value = 0;
@@ -165,6 +296,7 @@ EFI_STATUS PcieEnableItssm(UINT32 soctype, UINT32 HostBridgeNum, UINT32 Port)
Value |= BIT11|BIT30|BIT31;
RegWrite(PCIE_APB_SLAVE_BASE_1610[HostBridgeNum][Port] + 0x1114, Value);
(VOID)PcieRxValidCtrl(soctype, HostBridgeNum, Port, 1);
+ PcieReconfigLaneNum (soctype, HostBridgeNum, Port, PcieCfg);
return EFI_SUCCESS;
}
else
@@ -1008,7 +1140,7 @@ PciePortInit (
/* Disable RC Option Rom */
DisableRcOptionRom (soctype, HostBridgeNum, PortIndex, PcieCfg->PortInfo.PortType);
/* assert LTSSM enable */
- (VOID)PcieEnableItssm(soctype, HostBridgeNum, PortIndex);
+ (VOID)PcieEnableItssm (soctype, HostBridgeNum, PortIndex, PcieCfg);
if (FeaturePcdGet(PcdIsPciPerfTuningEnable)) {
//PCIe will still work even if performance tuning fails,
//and there is warning message inside the function to print
diff --git a/Chips/Hisilicon/Include/Regs/HisiPcieV1RegOffset.h b/Chips/Hisilicon/Include/Regs/HisiPcieV1RegOffset.h
index 539d567..bf57652 100644
--- a/Chips/Hisilicon/Include/Regs/HisiPcieV1RegOffset.h
+++ b/Chips/Hisilicon/Include/Regs/HisiPcieV1RegOffset.h
@@ -8982,6 +8982,7 @@ typedef union tagIepMsiCtrlIntStatus
#define PCIE_SYS_CTRL28_REG (PCI_SYS_BASE + 0x1c4)
#define PCIE_SYS_CTRL29_REG (PCI_SYS_BASE + 0x1c8)
#define PCIE_SYS_CTRL54_REG (PCI_SYS_BASE + 0x274)
+#define PCIE_SYS_STATE4_REG (PCI_SYS_BASE + 0x31C)
#define PCIE_SYS_STATE5_REG (PCI_SYS_BASE + 0x30)
#define PCIE_SYS_STATE6_REG (PCI_SYS_BASE + 0x34)
#define PCIE_SYS_STATE7_REG (PCI_SYS_BASE + 0x38)
@@ -12694,7 +12695,11 @@ typedef union tagPortlogic93
#define PCIE_SUBCTRL_SC_PCIE0_SYS_STATE3_REG (PCIE_SUBCTRL_BASE + 0x6814)
#define PCIE_SUBCTRL_SC_PCIE0_SYS_STATE4_REG (PCIE_SUBCTRL_BASE + 0x6818)
#define PCIE_LTSSM_STATE_MASK (0x3f)
+#define PCIE_LTSSM_CFG_LANENUM_ACPT 0x0a
+#define PCIE_LTSSM_CFG_COMPLETE 0x0b
#define PCIE_LTSSM_LINKUP_STATE (0x11)
+#define LTSSM_ENABLE BIT11
+#define MAX_TRY_LINK_NUM 5
#define PCIE_SUBCTRL_SC_PCIE0_AXI_MSTR_OOO_WR_STS0_REG (PCIE_SUBCTRL_BASE + 0x6880)
#define PCIE_SUBCTRL_SC_PCIE0_AXI_MSTR_OOO_WR_STS1_REG (PCIE_SUBCTRL_BASE + 0x6884)
#define PCIE_SUBCTRL_SC_PCIE0_AXI_MSTR_OOO_RD_STS0_REG (PCIE_SUBCTRL_BASE + 0x6890)