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:
@@ -304,6 +304,34 @@ static int rk_pcie_disable_power(struct rk_pcie *rk_pcie)
|
|||||||
return ret;
|
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)
|
static int rk_pcie_establish_link(struct dw_pcie *pci)
|
||||||
{
|
{
|
||||||
int retries, power;
|
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_suspend(rk_pcie->pci->dev);
|
||||||
rockchip_dw_pcie_resume(rk_pcie->pci->dev);
|
rockchip_dw_pcie_resume(rk_pcie->pci->dev);
|
||||||
break;
|
break;
|
||||||
|
case ROCKCHIP_PCIE_PM_RETRAIN_LINK:
|
||||||
|
rk_pcie_retrain(pci);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(rk_pcie->pci->dev, "%s flag=%d invalid\n", __func__, flag);
|
dev_err(rk_pcie->pci->dev, "%s flag=%d invalid\n", __func__, flag);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|||||||
@@ -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 {
|
enum rockchip_pcie_pm_ctrl_flag {
|
||||||
ROCKCHIP_PCIE_PM_CTRL_RESET = 1,
|
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);
|
int rockchip_dw_pcie_pm_ctrl_for_user(struct pci_dev *dev, enum rockchip_pcie_pm_ctrl_flag flag);
|
||||||
|
|||||||
Reference in New Issue
Block a user