Commit 886a9c13 authored by Rob Herring's avatar Rob Herring Committed by Lorenzo Pieralisi
Browse files

PCI: dwc: Move link handling into common code

All the DWC drivers do link setup and checks at roughly the same time.
Let's use the existing .start_link() hook (currently only used in EP
mode) and move the link handling to the core code.

The behavior for a link down was inconsistent as some drivers would fail
probe in that case while others succeed. Let's standardize this to
succeed as there are usecases where devices (and the link) appear later
even without hotplug. For example, a reconfigured FPGA device.

Link: https://lore.kernel.org/r/20201105211159.1814485-11-robh@kernel.org


Tested-by: default avatarMarek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: default avatarRob Herring <robh@kernel.org>
Signed-off-by: default avatarLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Acked-by: default avatarJingoo Han <jingoohan1@gmail.com>
Cc: Kishon Vijay Abraham I <kishon@ti.com>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Kukjin Kim <kgene@kernel.org>
Cc: Krzysztof Kozlowski <krzk@kernel.org>
Cc: Richard Zhu <hongxing.zhu@nxp.com>
Cc: Lucas Stach <l.stach@pengutronix.de>
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Pengutronix Kernel Team <kernel@pengutronix.de>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: NXP Linux Team <linux-imx@nxp.com>
Cc: Murali Karicheri <m-karicheri2@ti.com>
Cc: Yue Wang <yue.wang@Amlogic.com>
Cc: Kevin Hilman <khilman@baylibre.com>
Cc: Neil Armstrong <narmstrong@baylibre.com>
Cc: Jerome Brunet <jbrunet@baylibre.com>
Cc: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Cc: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
Cc: Jesper Nilsson <jesper.nilsson@axis.com>
Cc: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
Cc: Xiaowei Song <songxiaowei@hisilicon.com>
Cc: Binghui Wang <wangbinghui@hisilicon.com>
Cc: Andy Gross <agross@kernel.org>
Cc: Bjorn Andersson <bjorn.andersson@linaro.org>
Cc: Stanimir Varbanov <svarbanov@mm-sol.com>
Cc: Pratyush Anand <pratyush.anand@gmail.com>
Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Jonathan Hunter <jonathanh@nvidia.com>
Cc: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
Cc: linux-omap@vger.kernel.org
Cc: linux-samsung-soc@vger.kernel.org
Cc: linux-amlogic@lists.infradead.org
Cc: linux-arm-kernel@axis.com
Cc: linux-arm-msm@vger.kernel.org
Cc: linux-tegra@vger.kernel.org
parent f78f0263
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -183,8 +183,6 @@ static int dra7xx_pcie_host_init(struct pcie_port *pp)

	dw_pcie_setup_rc(pp);

	dra7xx_pcie_establish_link(pci);
	dw_pcie_wait_for_link(pci);
	dw_pcie_msi_init(pp);
	dra7xx_pcie_enable_interrupts(dra7xx);

+17 −24
Original line number Diff line number Diff line
@@ -229,30 +229,9 @@ static void exynos_pcie_assert_reset(struct exynos_pcie *ep)
				GPIOF_OUT_INIT_HIGH, "RESET");
}

static int exynos_pcie_establish_link(struct exynos_pcie *ep)
static int exynos_pcie_start_link(struct dw_pcie *pci)
{
	struct dw_pcie *pci = ep->pci;
	struct pcie_port *pp = &pci->pp;
	struct device *dev = pci->dev;

	if (dw_pcie_link_up(pci)) {
		dev_err(dev, "Link already up\n");
		return 0;
	}

	exynos_pcie_assert_core_reset(ep);

	phy_reset(ep->phy);

	exynos_pcie_writel(ep->mem_res->elbi_base, 1,
			PCIE_PWR_RESET);

	phy_power_on(ep->phy);
	phy_init(ep->phy);

	exynos_pcie_deassert_core_reset(ep);
	dw_pcie_setup_rc(pp);
	exynos_pcie_assert_reset(ep);
	struct exynos_pcie *ep = to_exynos_pcie(pci);

	/* assert LTSSM enable */
	exynos_pcie_writel(ep->mem_res->elbi_base, PCIE_ELBI_LTSSM_ENABLE,
@@ -386,7 +365,20 @@ static int exynos_pcie_host_init(struct pcie_port *pp)

	pp->bridge->ops = &exynos_pci_ops;

	exynos_pcie_establish_link(ep);
	exynos_pcie_assert_core_reset(ep);

	phy_reset(ep->phy);

	exynos_pcie_writel(ep->mem_res->elbi_base, 1,
			PCIE_PWR_RESET);

	phy_power_on(ep->phy);
	phy_init(ep->phy);

	exynos_pcie_deassert_core_reset(ep);
	dw_pcie_setup_rc(pp);
	exynos_pcie_assert_reset(ep);

	exynos_pcie_enable_interrupts(ep);

	return 0;
@@ -430,6 +422,7 @@ static const struct dw_pcie_ops dw_pcie_ops = {
	.read_dbi = exynos_pcie_read_dbi,
	.write_dbi = exynos_pcie_write_dbi,
	.link_up = exynos_pcie_link_up,
	.start_link = exynos_pcie_start_link,
};

static int __init exynos_pcie_probe(struct platform_device *pdev)
+4 −5
Original line number Diff line number Diff line
@@ -745,9 +745,9 @@ static void imx6_pcie_ltssm_enable(struct device *dev)
	}
}

static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
static int imx6_pcie_start_link(struct dw_pcie *pci)
{
	struct dw_pcie *pci = imx6_pcie->pci;
	struct imx6_pcie *imx6_pcie = to_imx6_pcie(pci);
	struct device *dev = pci->dev;
	u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
	u32 tmp;
@@ -835,7 +835,6 @@ static int imx6_pcie_host_init(struct pcie_port *pp)
	imx6_pcie_deassert_core_reset(imx6_pcie);
	imx6_setup_phy_mpll(imx6_pcie);
	dw_pcie_setup_rc(pp);
	imx6_pcie_establish_link(imx6_pcie);
	dw_pcie_msi_init(pp);

	return 0;
@@ -865,7 +864,7 @@ static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
}

static const struct dw_pcie_ops dw_pcie_ops = {
	/* No special ops needed, but pcie-designware still expects this struct */
	.start_link = imx6_pcie_start_link,
};

#ifdef CONFIG_PM_SLEEP
@@ -974,7 +973,7 @@ static int imx6_pcie_resume_noirq(struct device *dev)
	imx6_pcie_deassert_core_reset(imx6_pcie);
	dw_pcie_setup_rc(pp);

	ret = imx6_pcie_establish_link(imx6_pcie);
	ret = imx6_pcie_start_link(imx6_pcie->pci);
	if (ret < 0)
		dev_info(dev, "pcie link is down after resume.\n");

+0 −9
Original line number Diff line number Diff line
@@ -511,14 +511,8 @@ static void ks_pcie_stop_link(struct dw_pcie *pci)
static int ks_pcie_start_link(struct dw_pcie *pci)
{
	struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
	struct device *dev = pci->dev;
	u32 val;

	if (dw_pcie_link_up(pci)) {
		dev_dbg(dev, "link is already up\n");
		return 0;
	}

	/* Initiate Link Training */
	val = ks_pcie_app_readl(ks_pcie, CMD_STATUS);
	ks_pcie_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val);
@@ -833,9 +827,6 @@ static int __init ks_pcie_host_init(struct pcie_port *pp)
			"Asynchronous external abort");
#endif

	ks_pcie_start_link(pci);
	dw_pcie_wait_for_link(pci);

	return 0;
}

+9 −15
Original line number Diff line number Diff line
@@ -231,7 +231,7 @@ static void meson_pcie_assert_reset(struct meson_pcie *mp)
	gpiod_set_value_cansleep(mp->reset_gpio, 0);
}

static void meson_pcie_init_dw(struct meson_pcie *mp)
static void meson_pcie_ltssm_enable(struct meson_pcie *mp)
{
	u32 val;

@@ -289,20 +289,14 @@ static void meson_set_max_rd_req_size(struct meson_pcie *mp, int size)
	dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
}

static int meson_pcie_establish_link(struct meson_pcie *mp)
static int meson_pcie_start_link(struct dw_pcie *pci)
{
	struct dw_pcie *pci = &mp->pci;
	struct pcie_port *pp = &pci->pp;

	meson_pcie_init_dw(mp);
	meson_set_max_payload(mp, MAX_PAYLOAD_SIZE);
	meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE);

	dw_pcie_setup_rc(pp);
	struct meson_pcie *mp = to_meson_pcie(pci);

	meson_pcie_ltssm_enable(mp);
	meson_pcie_assert_reset(mp);

	return dw_pcie_wait_for_link(pci);
	return 0;
}

static int meson_pcie_rd_own_conf(struct pci_bus *bus, u32 devfn,
@@ -380,14 +374,13 @@ static int meson_pcie_host_init(struct pcie_port *pp)
{
	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
	struct meson_pcie *mp = to_meson_pcie(pci);
	int ret;

	pp->bridge->ops = &meson_pci_ops;

	ret = meson_pcie_establish_link(mp);
	if (ret)
		return ret;
	meson_set_max_payload(mp, MAX_PAYLOAD_SIZE);
	meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE);

	dw_pcie_setup_rc(pp);
	dw_pcie_msi_init(pp);

	return 0;
@@ -418,6 +411,7 @@ static int meson_add_pcie_port(struct meson_pcie *mp,

static const struct dw_pcie_ops dw_pcie_ops = {
	.link_up = meson_pcie_link_up,
	.start_link = meson_pcie_start_link,
};

static int meson_pcie_probe(struct platform_device *pdev)
Loading