diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index 1f87e2607564..a08fab7c9790 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -930,14 +930,21 @@ static const struct dw_pcie_ops dw_pcie_ops = { .link_up = rk_pcie_link_up, }; -static void rk_pcie_fast_link_setup(struct rk_pcie *rk_pcie) +static void rk_pcie_fast_link_setup(struct rk_pcie *rk_pcie, bool enable_dly2_en) { u32 val; /* LTSSM EN ctrl mode */ val = rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_HOT_RESET_CTRL); - val |= (PCIE_LTSSM_ENABLE_ENHANCE | PCIE_LTSSM_APP_DLY2_EN) - | ((PCIE_LTSSM_APP_DLY2_EN | PCIE_LTSSM_ENABLE_ENHANCE) << 16); + val |= PCIE_LTSSM_ENABLE_ENHANCE | (PCIE_LTSSM_ENABLE_ENHANCE << 16); + + if (enable_dly2_en) { + val |= PCIE_LTSSM_APP_DLY2_EN | (PCIE_LTSSM_APP_DLY2_EN << 16); + } else { + val &= ~PCIE_LTSSM_APP_DLY2_EN; + val |= PCIE_LTSSM_APP_DLY2_EN << 16; + } + rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_HOT_RESET_CTRL, val); } @@ -1339,7 +1346,7 @@ static int rk_pcie_slot_enable(struct gpio_hotplug_slot *slot) dev_info(rk_pcie->pci->dev, "%s\n", __func__); rk_pcie->hp_no_link = true; rk_pcie_enable_power(rk_pcie); - rk_pcie_fast_link_setup(rk_pcie); + rk_pcie_fast_link_setup(rk_pcie, true); ret = rk_pcie_establish_link(rk_pcie->pci); if (ret) dev_err(rk_pcie->pci->dev, "fail to enable slot\n"); @@ -1494,6 +1501,7 @@ static int rk_pcie_hardware_io_config(struct rk_pcie *rk_pcie) phy_power_on(rk_pcie->phy); + /* Release resets after PHY is working */ reset_control_deassert(rk_pcie->rsts); ret = phy_calibrate(rk_pcie->phy); @@ -1585,7 +1593,14 @@ static int rk_pcie_host_config(struct rk_pcie *rk_pcie) dw_pcie_writel_dbi(rk_pcie->pci, rk_pcie->linkcap_off, val); } - rk_pcie_fast_link_setup(rk_pcie); + /* + * S2R is in noirq phase which couldn't ack hot reset or link down event. + * But we need to deal with dly2_en enable case, otherwise the ltssm will + * be stuck waiting for dlye_done. We could set dly2_done in advance, + * however, it's slef-clear. So the only option here is to disable dly2_en + * when resuming. + */ + rk_pcie_fast_link_setup(rk_pcie, !rk_pcie->in_suspend); rk_pcie_set_power_limit(rk_pcie); @@ -2034,6 +2049,7 @@ static int __maybe_unused rockchip_dw_pcie_resume(struct device *dev) dw_pcie_dbi_ro_wr_dis(pci); rk_pcie->in_suspend = false; + rk_pcie_fast_link_setup(rk_pcie, true); return 0;