PCI: rockchip: dw: Add retrain link support

Speed change is set via dw_pcie_setup_rc(), so if both of links
support gen2 or gen3, auto speed change will happen. However, if
it's not, provide a manual speed change for EP function driver.

Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
Change-Id: Ib0dc765452aef0723968c5d48b5b44de24ca141e
This commit is contained in:
Shawn Lin
2024-09-03 11:26:09 +08:00
committed by Tao Huang
parent b28ccdbd6d
commit 4ca55c87f9
2 changed files with 32 additions and 0 deletions

View File

@@ -304,6 +304,34 @@ static int rk_pcie_disable_power(struct rk_pcie *rk_pcie)
return ret;
}
static void rk_pcie_retrain(struct dw_pcie *pci)
{
u32 pcie_cap_off;
u16 lnk_stat, lnk_ctl;
int ret;
/*
* Set retrain bit if current speed is 2.5 GB/s,
* but the PCIe root port support is > 2.5 GB/s.
*/
if (pci->link_gen < 2)
return;
dev_info(pci->dev, "Retrain link..\n");
pcie_cap_off = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
lnk_stat = dw_pcie_readw_dbi(pci, pcie_cap_off + PCI_EXP_LNKSTA);
if ((lnk_stat & PCI_EXP_LNKSTA_CLS) == PCI_EXP_LNKSTA_CLS_2_5GB) {
lnk_ctl = dw_pcie_readw_dbi(pci, pcie_cap_off + PCI_EXP_LNKCTL);
lnk_ctl |= PCI_EXP_LNKCTL_RL;
dw_pcie_writew_dbi(pci, pcie_cap_off + PCI_EXP_LNKCTL, lnk_ctl);
ret = readw_poll_timeout(pci->dbi_base + pcie_cap_off + PCI_EXP_LNKSTA,
lnk_stat, ((lnk_stat & PCI_EXP_LNKSTA_LT) == 0), 1000, HZ);
if (ret)
dev_err(pci->dev, "Retrain link timeout\n");
}
}
static int rk_pcie_establish_link(struct dw_pcie *pci)
{
int retries, power;
@@ -1684,6 +1712,9 @@ int rockchip_dw_pcie_pm_ctrl_for_user(struct pci_dev *dev, enum rockchip_pcie_pm
rockchip_dw_pcie_suspend(rk_pcie->pci->dev);
rockchip_dw_pcie_resume(rk_pcie->pci->dev);
break;
case ROCKCHIP_PCIE_PM_RETRAIN_LINK:
rk_pcie_retrain(pci);
break;
default:
dev_err(rk_pcie->pci->dev, "%s flag=%d invalid\n", __func__, flag);
return -EINVAL;

View File

@@ -17,6 +17,7 @@ static inline bool pcie_aspm_ext_is_in_l1sub_state(struct pci_dev *pdev) { retur
enum rockchip_pcie_pm_ctrl_flag {
ROCKCHIP_PCIE_PM_CTRL_RESET = 1,
ROCKCHIP_PCIE_PM_RETRAIN_LINK = 2,
};
int rockchip_dw_pcie_pm_ctrl_for_user(struct pci_dev *dev, enum rockchip_pcie_pm_ctrl_flag flag);