18d7e33d6SKunihiko Hayashi // SPDX-License-Identifier: GPL-2.0
28d7e33d6SKunihiko Hayashi /*
38d7e33d6SKunihiko Hayashi  * PCIe endpoint controller driver for UniPhier SoCs
48d7e33d6SKunihiko Hayashi  * Copyright 2018 Socionext Inc.
58d7e33d6SKunihiko Hayashi  * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
68d7e33d6SKunihiko Hayashi  */
78d7e33d6SKunihiko Hayashi 
88d7e33d6SKunihiko Hayashi #include <linux/bitops.h>
98d7e33d6SKunihiko Hayashi #include <linux/bitfield.h>
108d7e33d6SKunihiko Hayashi #include <linux/clk.h>
118d7e33d6SKunihiko Hayashi #include <linux/delay.h>
128d7e33d6SKunihiko Hayashi #include <linux/init.h>
13892fdf15SKunihiko Hayashi #include <linux/iopoll.h>
14*c925cfafSRob Herring #include <linux/of.h>
158d7e33d6SKunihiko Hayashi #include <linux/pci.h>
168d7e33d6SKunihiko Hayashi #include <linux/phy/phy.h>
178d7e33d6SKunihiko Hayashi #include <linux/platform_device.h>
188d7e33d6SKunihiko Hayashi #include <linux/reset.h>
198d7e33d6SKunihiko Hayashi 
208d7e33d6SKunihiko Hayashi #include "pcie-designware.h"
218d7e33d6SKunihiko Hayashi 
228d7e33d6SKunihiko Hayashi /* Link Glue registers */
238d7e33d6SKunihiko Hayashi #define PCL_RSTCTRL0			0x0010
248d7e33d6SKunihiko Hayashi #define PCL_RSTCTRL_AXI_REG		BIT(3)
258d7e33d6SKunihiko Hayashi #define PCL_RSTCTRL_AXI_SLAVE		BIT(2)
268d7e33d6SKunihiko Hayashi #define PCL_RSTCTRL_AXI_MASTER		BIT(1)
278d7e33d6SKunihiko Hayashi #define PCL_RSTCTRL_PIPE3		BIT(0)
288d7e33d6SKunihiko Hayashi 
298d7e33d6SKunihiko Hayashi #define PCL_RSTCTRL1			0x0020
308d7e33d6SKunihiko Hayashi #define PCL_RSTCTRL_PERST		BIT(0)
318d7e33d6SKunihiko Hayashi 
328d7e33d6SKunihiko Hayashi #define PCL_RSTCTRL2			0x0024
338d7e33d6SKunihiko Hayashi #define PCL_RSTCTRL_PHY_RESET		BIT(0)
348d7e33d6SKunihiko Hayashi 
35892fdf15SKunihiko Hayashi #define PCL_PINCTRL0			0x002c
36892fdf15SKunihiko Hayashi #define PCL_PERST_PLDN_REGEN		BIT(12)
37892fdf15SKunihiko Hayashi #define PCL_PERST_NOE_REGEN		BIT(11)
38892fdf15SKunihiko Hayashi #define PCL_PERST_OUT_REGEN		BIT(8)
39892fdf15SKunihiko Hayashi #define PCL_PERST_PLDN_REGVAL		BIT(4)
40892fdf15SKunihiko Hayashi #define PCL_PERST_NOE_REGVAL		BIT(3)
41892fdf15SKunihiko Hayashi #define PCL_PERST_OUT_REGVAL		BIT(0)
42892fdf15SKunihiko Hayashi 
43892fdf15SKunihiko Hayashi #define PCL_PIPEMON			0x0044
44892fdf15SKunihiko Hayashi #define PCL_PCLK_ALIVE			BIT(15)
45892fdf15SKunihiko Hayashi 
468d7e33d6SKunihiko Hayashi #define PCL_MODE			0x8000
478d7e33d6SKunihiko Hayashi #define PCL_MODE_REGEN			BIT(8)
488d7e33d6SKunihiko Hayashi #define PCL_MODE_REGVAL			BIT(0)
498d7e33d6SKunihiko Hayashi 
508d7e33d6SKunihiko Hayashi #define PCL_APP_CLK_CTRL		0x8004
518d7e33d6SKunihiko Hayashi #define PCL_APP_CLK_REQ			BIT(0)
528d7e33d6SKunihiko Hayashi 
538d7e33d6SKunihiko Hayashi #define PCL_APP_READY_CTRL		0x8008
548d7e33d6SKunihiko Hayashi #define PCL_APP_LTSSM_ENABLE		BIT(0)
558d7e33d6SKunihiko Hayashi 
568d7e33d6SKunihiko Hayashi #define PCL_APP_MSI0			0x8040
578d7e33d6SKunihiko Hayashi #define PCL_APP_VEN_MSI_TC_MASK		GENMASK(10, 8)
588d7e33d6SKunihiko Hayashi #define PCL_APP_VEN_MSI_VECTOR_MASK	GENMASK(4, 0)
598d7e33d6SKunihiko Hayashi 
608d7e33d6SKunihiko Hayashi #define PCL_APP_MSI1			0x8044
618d7e33d6SKunihiko Hayashi #define PCL_APP_MSI_REQ			BIT(0)
628d7e33d6SKunihiko Hayashi 
638d7e33d6SKunihiko Hayashi #define PCL_APP_INTX			0x8074
648d7e33d6SKunihiko Hayashi #define PCL_APP_INTX_SYS_INT		BIT(0)
658d7e33d6SKunihiko Hayashi 
66892fdf15SKunihiko Hayashi #define PCL_APP_PM0			0x8078
67892fdf15SKunihiko Hayashi #define PCL_SYS_AUX_PWR_DET		BIT(8)
68892fdf15SKunihiko Hayashi 
698d7e33d6SKunihiko Hayashi /* assertion time of INTx in usec */
708d7e33d6SKunihiko Hayashi #define PCL_INTX_WIDTH_USEC		30
718d7e33d6SKunihiko Hayashi 
728d7e33d6SKunihiko Hayashi struct uniphier_pcie_ep_priv {
738d7e33d6SKunihiko Hayashi 	void __iomem *base;
748d7e33d6SKunihiko Hayashi 	struct dw_pcie pci;
758d7e33d6SKunihiko Hayashi 	struct clk *clk, *clk_gio;
768d7e33d6SKunihiko Hayashi 	struct reset_control *rst, *rst_gio;
778d7e33d6SKunihiko Hayashi 	struct phy *phy;
78d41584aeSKunihiko Hayashi 	const struct uniphier_pcie_ep_soc_data *data;
79d41584aeSKunihiko Hayashi };
80d41584aeSKunihiko Hayashi 
81d41584aeSKunihiko Hayashi struct uniphier_pcie_ep_soc_data {
82d41584aeSKunihiko Hayashi 	bool has_gio;
83d41584aeSKunihiko Hayashi 	void (*init)(struct uniphier_pcie_ep_priv *priv);
84d41584aeSKunihiko Hayashi 	int (*wait)(struct uniphier_pcie_ep_priv *priv);
85d41584aeSKunihiko Hayashi 	const struct pci_epc_features features;
868d7e33d6SKunihiko Hayashi };
878d7e33d6SKunihiko Hayashi 
888d7e33d6SKunihiko Hayashi #define to_uniphier_pcie(x)	dev_get_drvdata((x)->dev)
898d7e33d6SKunihiko Hayashi 
uniphier_pcie_ltssm_enable(struct uniphier_pcie_ep_priv * priv,bool enable)908d7e33d6SKunihiko Hayashi static void uniphier_pcie_ltssm_enable(struct uniphier_pcie_ep_priv *priv,
918d7e33d6SKunihiko Hayashi 				       bool enable)
928d7e33d6SKunihiko Hayashi {
938d7e33d6SKunihiko Hayashi 	u32 val;
948d7e33d6SKunihiko Hayashi 
958d7e33d6SKunihiko Hayashi 	val = readl(priv->base + PCL_APP_READY_CTRL);
968d7e33d6SKunihiko Hayashi 	if (enable)
978d7e33d6SKunihiko Hayashi 		val |= PCL_APP_LTSSM_ENABLE;
988d7e33d6SKunihiko Hayashi 	else
998d7e33d6SKunihiko Hayashi 		val &= ~PCL_APP_LTSSM_ENABLE;
1008d7e33d6SKunihiko Hayashi 	writel(val, priv->base + PCL_APP_READY_CTRL);
1018d7e33d6SKunihiko Hayashi }
1028d7e33d6SKunihiko Hayashi 
uniphier_pcie_phy_reset(struct uniphier_pcie_ep_priv * priv,bool assert)1038d7e33d6SKunihiko Hayashi static void uniphier_pcie_phy_reset(struct uniphier_pcie_ep_priv *priv,
1048d7e33d6SKunihiko Hayashi 				    bool assert)
1058d7e33d6SKunihiko Hayashi {
1068d7e33d6SKunihiko Hayashi 	u32 val;
1078d7e33d6SKunihiko Hayashi 
1088d7e33d6SKunihiko Hayashi 	val = readl(priv->base + PCL_RSTCTRL2);
1098d7e33d6SKunihiko Hayashi 	if (assert)
1108d7e33d6SKunihiko Hayashi 		val |= PCL_RSTCTRL_PHY_RESET;
1118d7e33d6SKunihiko Hayashi 	else
1128d7e33d6SKunihiko Hayashi 		val &= ~PCL_RSTCTRL_PHY_RESET;
1138d7e33d6SKunihiko Hayashi 	writel(val, priv->base + PCL_RSTCTRL2);
1148d7e33d6SKunihiko Hayashi }
1158d7e33d6SKunihiko Hayashi 
uniphier_pcie_pro5_init_ep(struct uniphier_pcie_ep_priv * priv)116d41584aeSKunihiko Hayashi static void uniphier_pcie_pro5_init_ep(struct uniphier_pcie_ep_priv *priv)
1178d7e33d6SKunihiko Hayashi {
1188d7e33d6SKunihiko Hayashi 	u32 val;
1198d7e33d6SKunihiko Hayashi 
1208d7e33d6SKunihiko Hayashi 	/* set EP mode */
1218d7e33d6SKunihiko Hayashi 	val = readl(priv->base + PCL_MODE);
1228d7e33d6SKunihiko Hayashi 	val |= PCL_MODE_REGEN | PCL_MODE_REGVAL;
1238d7e33d6SKunihiko Hayashi 	writel(val, priv->base + PCL_MODE);
1248d7e33d6SKunihiko Hayashi 
1258d7e33d6SKunihiko Hayashi 	/* clock request */
1268d7e33d6SKunihiko Hayashi 	val = readl(priv->base + PCL_APP_CLK_CTRL);
1278d7e33d6SKunihiko Hayashi 	val &= ~PCL_APP_CLK_REQ;
1288d7e33d6SKunihiko Hayashi 	writel(val, priv->base + PCL_APP_CLK_CTRL);
1298d7e33d6SKunihiko Hayashi 
1308d7e33d6SKunihiko Hayashi 	/* deassert PIPE3 and AXI reset */
1318d7e33d6SKunihiko Hayashi 	val = readl(priv->base + PCL_RSTCTRL0);
1328d7e33d6SKunihiko Hayashi 	val |= PCL_RSTCTRL_AXI_REG | PCL_RSTCTRL_AXI_SLAVE
1338d7e33d6SKunihiko Hayashi 		| PCL_RSTCTRL_AXI_MASTER | PCL_RSTCTRL_PIPE3;
1348d7e33d6SKunihiko Hayashi 	writel(val, priv->base + PCL_RSTCTRL0);
1358d7e33d6SKunihiko Hayashi 
1368d7e33d6SKunihiko Hayashi 	uniphier_pcie_ltssm_enable(priv, false);
1378d7e33d6SKunihiko Hayashi 
1388d7e33d6SKunihiko Hayashi 	msleep(100);
1398d7e33d6SKunihiko Hayashi }
1408d7e33d6SKunihiko Hayashi 
uniphier_pcie_nx1_init_ep(struct uniphier_pcie_ep_priv * priv)141892fdf15SKunihiko Hayashi static void uniphier_pcie_nx1_init_ep(struct uniphier_pcie_ep_priv *priv)
142892fdf15SKunihiko Hayashi {
143892fdf15SKunihiko Hayashi 	u32 val;
144892fdf15SKunihiko Hayashi 
145892fdf15SKunihiko Hayashi 	/* set EP mode */
146892fdf15SKunihiko Hayashi 	val = readl(priv->base + PCL_MODE);
147892fdf15SKunihiko Hayashi 	val |= PCL_MODE_REGEN | PCL_MODE_REGVAL;
148892fdf15SKunihiko Hayashi 	writel(val, priv->base + PCL_MODE);
149892fdf15SKunihiko Hayashi 
150892fdf15SKunihiko Hayashi 	/* use auxiliary power detection */
151892fdf15SKunihiko Hayashi 	val = readl(priv->base + PCL_APP_PM0);
152892fdf15SKunihiko Hayashi 	val |= PCL_SYS_AUX_PWR_DET;
153892fdf15SKunihiko Hayashi 	writel(val, priv->base + PCL_APP_PM0);
154892fdf15SKunihiko Hayashi 
155892fdf15SKunihiko Hayashi 	/* assert PERST# */
156892fdf15SKunihiko Hayashi 	val = readl(priv->base + PCL_PINCTRL0);
157892fdf15SKunihiko Hayashi 	val &= ~(PCL_PERST_NOE_REGVAL | PCL_PERST_OUT_REGVAL
158892fdf15SKunihiko Hayashi 		 | PCL_PERST_PLDN_REGVAL);
159892fdf15SKunihiko Hayashi 	val |= PCL_PERST_NOE_REGEN | PCL_PERST_OUT_REGEN
160892fdf15SKunihiko Hayashi 		| PCL_PERST_PLDN_REGEN;
161892fdf15SKunihiko Hayashi 	writel(val, priv->base + PCL_PINCTRL0);
162892fdf15SKunihiko Hayashi 
163892fdf15SKunihiko Hayashi 	uniphier_pcie_ltssm_enable(priv, false);
164892fdf15SKunihiko Hayashi 
165892fdf15SKunihiko Hayashi 	usleep_range(100000, 200000);
166892fdf15SKunihiko Hayashi 
167892fdf15SKunihiko Hayashi 	/* deassert PERST# */
168892fdf15SKunihiko Hayashi 	val = readl(priv->base + PCL_PINCTRL0);
169892fdf15SKunihiko Hayashi 	val |= PCL_PERST_OUT_REGVAL | PCL_PERST_OUT_REGEN;
170892fdf15SKunihiko Hayashi 	writel(val, priv->base + PCL_PINCTRL0);
171892fdf15SKunihiko Hayashi }
172892fdf15SKunihiko Hayashi 
uniphier_pcie_nx1_wait_ep(struct uniphier_pcie_ep_priv * priv)173892fdf15SKunihiko Hayashi static int uniphier_pcie_nx1_wait_ep(struct uniphier_pcie_ep_priv *priv)
174892fdf15SKunihiko Hayashi {
175892fdf15SKunihiko Hayashi 	u32 status;
176892fdf15SKunihiko Hayashi 	int ret;
177892fdf15SKunihiko Hayashi 
178892fdf15SKunihiko Hayashi 	/* wait PIPE clock */
179892fdf15SKunihiko Hayashi 	ret = readl_poll_timeout(priv->base + PCL_PIPEMON, status,
180892fdf15SKunihiko Hayashi 				 status & PCL_PCLK_ALIVE, 100000, 1000000);
181892fdf15SKunihiko Hayashi 	if (ret) {
182892fdf15SKunihiko Hayashi 		dev_err(priv->pci.dev,
183892fdf15SKunihiko Hayashi 			"Failed to initialize controller in EP mode\n");
184892fdf15SKunihiko Hayashi 		return ret;
185892fdf15SKunihiko Hayashi 	}
186892fdf15SKunihiko Hayashi 
187892fdf15SKunihiko Hayashi 	return 0;
188892fdf15SKunihiko Hayashi }
189892fdf15SKunihiko Hayashi 
uniphier_pcie_start_link(struct dw_pcie * pci)1908d7e33d6SKunihiko Hayashi static int uniphier_pcie_start_link(struct dw_pcie *pci)
1918d7e33d6SKunihiko Hayashi {
1928d7e33d6SKunihiko Hayashi 	struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci);
1938d7e33d6SKunihiko Hayashi 
1948d7e33d6SKunihiko Hayashi 	uniphier_pcie_ltssm_enable(priv, true);
1958d7e33d6SKunihiko Hayashi 
1968d7e33d6SKunihiko Hayashi 	return 0;
1978d7e33d6SKunihiko Hayashi }
1988d7e33d6SKunihiko Hayashi 
uniphier_pcie_stop_link(struct dw_pcie * pci)1998d7e33d6SKunihiko Hayashi static void uniphier_pcie_stop_link(struct dw_pcie *pci)
2008d7e33d6SKunihiko Hayashi {
2018d7e33d6SKunihiko Hayashi 	struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci);
2028d7e33d6SKunihiko Hayashi 
2038d7e33d6SKunihiko Hayashi 	uniphier_pcie_ltssm_enable(priv, false);
2048d7e33d6SKunihiko Hayashi }
2058d7e33d6SKunihiko Hayashi 
uniphier_pcie_ep_init(struct dw_pcie_ep * ep)2068d7e33d6SKunihiko Hayashi static void uniphier_pcie_ep_init(struct dw_pcie_ep *ep)
2078d7e33d6SKunihiko Hayashi {
2088d7e33d6SKunihiko Hayashi 	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
2098d7e33d6SKunihiko Hayashi 	enum pci_barno bar;
2108d7e33d6SKunihiko Hayashi 
2118d7e33d6SKunihiko Hayashi 	for (bar = BAR_0; bar <= BAR_5; bar++)
2128d7e33d6SKunihiko Hayashi 		dw_pcie_ep_reset_bar(pci, bar);
2138d7e33d6SKunihiko Hayashi }
2148d7e33d6SKunihiko Hayashi 
uniphier_pcie_ep_raise_legacy_irq(struct dw_pcie_ep * ep)2158d7e33d6SKunihiko Hayashi static int uniphier_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep)
2168d7e33d6SKunihiko Hayashi {
2178d7e33d6SKunihiko Hayashi 	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
2188d7e33d6SKunihiko Hayashi 	struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci);
2198d7e33d6SKunihiko Hayashi 	u32 val;
2208d7e33d6SKunihiko Hayashi 
2218d7e33d6SKunihiko Hayashi 	/*
2228d7e33d6SKunihiko Hayashi 	 * This makes pulse signal to send INTx to the RC, so this should
2238d7e33d6SKunihiko Hayashi 	 * be cleared as soon as possible. This sequence is covered with
2248d7e33d6SKunihiko Hayashi 	 * mutex in pci_epc_raise_irq().
2258d7e33d6SKunihiko Hayashi 	 */
2268d7e33d6SKunihiko Hayashi 	/* assert INTx */
2278d7e33d6SKunihiko Hayashi 	val = readl(priv->base + PCL_APP_INTX);
2288d7e33d6SKunihiko Hayashi 	val |= PCL_APP_INTX_SYS_INT;
2298d7e33d6SKunihiko Hayashi 	writel(val, priv->base + PCL_APP_INTX);
2308d7e33d6SKunihiko Hayashi 
2318d7e33d6SKunihiko Hayashi 	udelay(PCL_INTX_WIDTH_USEC);
2328d7e33d6SKunihiko Hayashi 
2338d7e33d6SKunihiko Hayashi 	/* deassert INTx */
2348d7e33d6SKunihiko Hayashi 	val &= ~PCL_APP_INTX_SYS_INT;
2358d7e33d6SKunihiko Hayashi 	writel(val, priv->base + PCL_APP_INTX);
2368d7e33d6SKunihiko Hayashi 
2378d7e33d6SKunihiko Hayashi 	return 0;
2388d7e33d6SKunihiko Hayashi }
2398d7e33d6SKunihiko Hayashi 
uniphier_pcie_ep_raise_msi_irq(struct dw_pcie_ep * ep,u8 func_no,u16 interrupt_num)2408d7e33d6SKunihiko Hayashi static int uniphier_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep,
2418d7e33d6SKunihiko Hayashi 					  u8 func_no, u16 interrupt_num)
2428d7e33d6SKunihiko Hayashi {
2438d7e33d6SKunihiko Hayashi 	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
2448d7e33d6SKunihiko Hayashi 	struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci);
2458d7e33d6SKunihiko Hayashi 	u32 val;
2468d7e33d6SKunihiko Hayashi 
2478d7e33d6SKunihiko Hayashi 	val = FIELD_PREP(PCL_APP_VEN_MSI_TC_MASK, func_no)
2488d7e33d6SKunihiko Hayashi 		| FIELD_PREP(PCL_APP_VEN_MSI_VECTOR_MASK, interrupt_num - 1);
2498d7e33d6SKunihiko Hayashi 	writel(val, priv->base + PCL_APP_MSI0);
2508d7e33d6SKunihiko Hayashi 
2518d7e33d6SKunihiko Hayashi 	val = readl(priv->base + PCL_APP_MSI1);
2528d7e33d6SKunihiko Hayashi 	val |= PCL_APP_MSI_REQ;
2538d7e33d6SKunihiko Hayashi 	writel(val, priv->base + PCL_APP_MSI1);
2548d7e33d6SKunihiko Hayashi 
2558d7e33d6SKunihiko Hayashi 	return 0;
2568d7e33d6SKunihiko Hayashi }
2578d7e33d6SKunihiko Hayashi 
uniphier_pcie_ep_raise_irq(struct dw_pcie_ep * ep,u8 func_no,enum pci_epc_irq_type type,u16 interrupt_num)2588d7e33d6SKunihiko Hayashi static int uniphier_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
2598d7e33d6SKunihiko Hayashi 				      enum pci_epc_irq_type type,
2608d7e33d6SKunihiko Hayashi 				      u16 interrupt_num)
2618d7e33d6SKunihiko Hayashi {
2628d7e33d6SKunihiko Hayashi 	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
2638d7e33d6SKunihiko Hayashi 
2648d7e33d6SKunihiko Hayashi 	switch (type) {
2658d7e33d6SKunihiko Hayashi 	case PCI_EPC_IRQ_LEGACY:
2668d7e33d6SKunihiko Hayashi 		return uniphier_pcie_ep_raise_legacy_irq(ep);
2678d7e33d6SKunihiko Hayashi 	case PCI_EPC_IRQ_MSI:
2688d7e33d6SKunihiko Hayashi 		return uniphier_pcie_ep_raise_msi_irq(ep, func_no,
2698d7e33d6SKunihiko Hayashi 						      interrupt_num);
2708d7e33d6SKunihiko Hayashi 	default:
2718d7e33d6SKunihiko Hayashi 		dev_err(pci->dev, "UNKNOWN IRQ type (%d)\n", type);
2728d7e33d6SKunihiko Hayashi 	}
2738d7e33d6SKunihiko Hayashi 
2748d7e33d6SKunihiko Hayashi 	return 0;
2758d7e33d6SKunihiko Hayashi }
2768d7e33d6SKunihiko Hayashi 
2778d7e33d6SKunihiko Hayashi static const struct pci_epc_features*
uniphier_pcie_get_features(struct dw_pcie_ep * ep)2788d7e33d6SKunihiko Hayashi uniphier_pcie_get_features(struct dw_pcie_ep *ep)
2798d7e33d6SKunihiko Hayashi {
2808d7e33d6SKunihiko Hayashi 	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
2818d7e33d6SKunihiko Hayashi 	struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci);
2828d7e33d6SKunihiko Hayashi 
283d41584aeSKunihiko Hayashi 	return &priv->data->features;
2848d7e33d6SKunihiko Hayashi }
2858d7e33d6SKunihiko Hayashi 
2868d7e33d6SKunihiko Hayashi static const struct dw_pcie_ep_ops uniphier_pcie_ep_ops = {
2878d7e33d6SKunihiko Hayashi 	.ep_init = uniphier_pcie_ep_init,
2888d7e33d6SKunihiko Hayashi 	.raise_irq = uniphier_pcie_ep_raise_irq,
2898d7e33d6SKunihiko Hayashi 	.get_features = uniphier_pcie_get_features,
2908d7e33d6SKunihiko Hayashi };
2918d7e33d6SKunihiko Hayashi 
uniphier_pcie_ep_enable(struct uniphier_pcie_ep_priv * priv)2928d7e33d6SKunihiko Hayashi static int uniphier_pcie_ep_enable(struct uniphier_pcie_ep_priv *priv)
2938d7e33d6SKunihiko Hayashi {
2948d7e33d6SKunihiko Hayashi 	int ret;
2958d7e33d6SKunihiko Hayashi 
2968d7e33d6SKunihiko Hayashi 	ret = clk_prepare_enable(priv->clk);
2978d7e33d6SKunihiko Hayashi 	if (ret)
2988d7e33d6SKunihiko Hayashi 		return ret;
2998d7e33d6SKunihiko Hayashi 
3008d7e33d6SKunihiko Hayashi 	ret = clk_prepare_enable(priv->clk_gio);
3018d7e33d6SKunihiko Hayashi 	if (ret)
3028d7e33d6SKunihiko Hayashi 		goto out_clk_disable;
3038d7e33d6SKunihiko Hayashi 
3048d7e33d6SKunihiko Hayashi 	ret = reset_control_deassert(priv->rst);
3058d7e33d6SKunihiko Hayashi 	if (ret)
3068d7e33d6SKunihiko Hayashi 		goto out_clk_gio_disable;
3078d7e33d6SKunihiko Hayashi 
3088d7e33d6SKunihiko Hayashi 	ret = reset_control_deassert(priv->rst_gio);
3098d7e33d6SKunihiko Hayashi 	if (ret)
3108d7e33d6SKunihiko Hayashi 		goto out_rst_assert;
3118d7e33d6SKunihiko Hayashi 
312d41584aeSKunihiko Hayashi 	if (priv->data->init)
313d41584aeSKunihiko Hayashi 		priv->data->init(priv);
3148d7e33d6SKunihiko Hayashi 
3158d7e33d6SKunihiko Hayashi 	uniphier_pcie_phy_reset(priv, true);
3168d7e33d6SKunihiko Hayashi 
3178d7e33d6SKunihiko Hayashi 	ret = phy_init(priv->phy);
3188d7e33d6SKunihiko Hayashi 	if (ret)
3198d7e33d6SKunihiko Hayashi 		goto out_rst_gio_assert;
3208d7e33d6SKunihiko Hayashi 
3218d7e33d6SKunihiko Hayashi 	uniphier_pcie_phy_reset(priv, false);
3228d7e33d6SKunihiko Hayashi 
323d41584aeSKunihiko Hayashi 	if (priv->data->wait) {
324d41584aeSKunihiko Hayashi 		ret = priv->data->wait(priv);
325d41584aeSKunihiko Hayashi 		if (ret)
326d41584aeSKunihiko Hayashi 			goto out_phy_exit;
327d41584aeSKunihiko Hayashi 	}
328d41584aeSKunihiko Hayashi 
3298d7e33d6SKunihiko Hayashi 	return 0;
3308d7e33d6SKunihiko Hayashi 
331d41584aeSKunihiko Hayashi out_phy_exit:
332d41584aeSKunihiko Hayashi 	phy_exit(priv->phy);
3338d7e33d6SKunihiko Hayashi out_rst_gio_assert:
3348d7e33d6SKunihiko Hayashi 	reset_control_assert(priv->rst_gio);
3358d7e33d6SKunihiko Hayashi out_rst_assert:
3368d7e33d6SKunihiko Hayashi 	reset_control_assert(priv->rst);
3378d7e33d6SKunihiko Hayashi out_clk_gio_disable:
3388d7e33d6SKunihiko Hayashi 	clk_disable_unprepare(priv->clk_gio);
3398d7e33d6SKunihiko Hayashi out_clk_disable:
3408d7e33d6SKunihiko Hayashi 	clk_disable_unprepare(priv->clk);
3418d7e33d6SKunihiko Hayashi 
3428d7e33d6SKunihiko Hayashi 	return ret;
3438d7e33d6SKunihiko Hayashi }
3448d7e33d6SKunihiko Hayashi 
3458d7e33d6SKunihiko Hayashi static const struct dw_pcie_ops dw_pcie_ops = {
3468d7e33d6SKunihiko Hayashi 	.start_link = uniphier_pcie_start_link,
3478d7e33d6SKunihiko Hayashi 	.stop_link = uniphier_pcie_stop_link,
3488d7e33d6SKunihiko Hayashi };
3498d7e33d6SKunihiko Hayashi 
uniphier_pcie_ep_probe(struct platform_device * pdev)3508d7e33d6SKunihiko Hayashi static int uniphier_pcie_ep_probe(struct platform_device *pdev)
3518d7e33d6SKunihiko Hayashi {
3528d7e33d6SKunihiko Hayashi 	struct device *dev = &pdev->dev;
3538d7e33d6SKunihiko Hayashi 	struct uniphier_pcie_ep_priv *priv;
3548d7e33d6SKunihiko Hayashi 	int ret;
3558d7e33d6SKunihiko Hayashi 
3568d7e33d6SKunihiko Hayashi 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
3578d7e33d6SKunihiko Hayashi 	if (!priv)
3588d7e33d6SKunihiko Hayashi 		return -ENOMEM;
3598d7e33d6SKunihiko Hayashi 
360d41584aeSKunihiko Hayashi 	priv->data = of_device_get_match_data(dev);
361d41584aeSKunihiko Hayashi 	if (WARN_ON(!priv->data))
3628d7e33d6SKunihiko Hayashi 		return -EINVAL;
3638d7e33d6SKunihiko Hayashi 
3648d7e33d6SKunihiko Hayashi 	priv->pci.dev = dev;
3658d7e33d6SKunihiko Hayashi 	priv->pci.ops = &dw_pcie_ops;
3668d7e33d6SKunihiko Hayashi 
3678d7e33d6SKunihiko Hayashi 	priv->base = devm_platform_ioremap_resource_byname(pdev, "link");
3688d7e33d6SKunihiko Hayashi 	if (IS_ERR(priv->base))
3698d7e33d6SKunihiko Hayashi 		return PTR_ERR(priv->base);
3708d7e33d6SKunihiko Hayashi 
371d41584aeSKunihiko Hayashi 	if (priv->data->has_gio) {
3728d7e33d6SKunihiko Hayashi 		priv->clk_gio = devm_clk_get(dev, "gio");
3738d7e33d6SKunihiko Hayashi 		if (IS_ERR(priv->clk_gio))
3748d7e33d6SKunihiko Hayashi 			return PTR_ERR(priv->clk_gio);
3758d7e33d6SKunihiko Hayashi 
3768d7e33d6SKunihiko Hayashi 		priv->rst_gio = devm_reset_control_get_shared(dev, "gio");
3778d7e33d6SKunihiko Hayashi 		if (IS_ERR(priv->rst_gio))
3788d7e33d6SKunihiko Hayashi 			return PTR_ERR(priv->rst_gio);
379d41584aeSKunihiko Hayashi 	}
3808d7e33d6SKunihiko Hayashi 
3818d7e33d6SKunihiko Hayashi 	priv->clk = devm_clk_get(dev, "link");
3828d7e33d6SKunihiko Hayashi 	if (IS_ERR(priv->clk))
3838d7e33d6SKunihiko Hayashi 		return PTR_ERR(priv->clk);
3848d7e33d6SKunihiko Hayashi 
3858d7e33d6SKunihiko Hayashi 	priv->rst = devm_reset_control_get_shared(dev, "link");
3868d7e33d6SKunihiko Hayashi 	if (IS_ERR(priv->rst))
3878d7e33d6SKunihiko Hayashi 		return PTR_ERR(priv->rst);
3888d7e33d6SKunihiko Hayashi 
3898d7e33d6SKunihiko Hayashi 	priv->phy = devm_phy_optional_get(dev, "pcie-phy");
3908d7e33d6SKunihiko Hayashi 	if (IS_ERR(priv->phy)) {
3918d7e33d6SKunihiko Hayashi 		ret = PTR_ERR(priv->phy);
3928d7e33d6SKunihiko Hayashi 		dev_err(dev, "Failed to get phy (%d)\n", ret);
3938d7e33d6SKunihiko Hayashi 		return ret;
3948d7e33d6SKunihiko Hayashi 	}
3958d7e33d6SKunihiko Hayashi 
3968d7e33d6SKunihiko Hayashi 	platform_set_drvdata(pdev, priv);
3978d7e33d6SKunihiko Hayashi 
3988d7e33d6SKunihiko Hayashi 	ret = uniphier_pcie_ep_enable(priv);
3998d7e33d6SKunihiko Hayashi 	if (ret)
4008d7e33d6SKunihiko Hayashi 		return ret;
4018d7e33d6SKunihiko Hayashi 
402a0fd361dSRob Herring 	priv->pci.ep.ops = &uniphier_pcie_ep_ops;
403a0fd361dSRob Herring 	return dw_pcie_ep_init(&priv->pci.ep);
4048d7e33d6SKunihiko Hayashi }
4058d7e33d6SKunihiko Hayashi 
406d41584aeSKunihiko Hayashi static const struct uniphier_pcie_ep_soc_data uniphier_pro5_data = {
407d41584aeSKunihiko Hayashi 	.has_gio = true,
408d41584aeSKunihiko Hayashi 	.init = uniphier_pcie_pro5_init_ep,
409d41584aeSKunihiko Hayashi 	.wait = NULL,
410d41584aeSKunihiko Hayashi 	.features = {
4118d7e33d6SKunihiko Hayashi 		.linkup_notifier = false,
4128d7e33d6SKunihiko Hayashi 		.msi_capable = true,
4138d7e33d6SKunihiko Hayashi 		.msix_capable = false,
4148d7e33d6SKunihiko Hayashi 		.align = 1 << 16,
4158d7e33d6SKunihiko Hayashi 		.bar_fixed_64bit = BIT(BAR_0) | BIT(BAR_2) | BIT(BAR_4),
4168d7e33d6SKunihiko Hayashi 		.reserved_bar =  BIT(BAR_4),
417d41584aeSKunihiko Hayashi 	},
4188d7e33d6SKunihiko Hayashi };
4198d7e33d6SKunihiko Hayashi 
420892fdf15SKunihiko Hayashi static const struct uniphier_pcie_ep_soc_data uniphier_nx1_data = {
421892fdf15SKunihiko Hayashi 	.has_gio = false,
422892fdf15SKunihiko Hayashi 	.init = uniphier_pcie_nx1_init_ep,
423892fdf15SKunihiko Hayashi 	.wait = uniphier_pcie_nx1_wait_ep,
424892fdf15SKunihiko Hayashi 	.features = {
425892fdf15SKunihiko Hayashi 		.linkup_notifier = false,
426892fdf15SKunihiko Hayashi 		.msi_capable = true,
427892fdf15SKunihiko Hayashi 		.msix_capable = false,
428892fdf15SKunihiko Hayashi 		.align = 1 << 12,
429892fdf15SKunihiko Hayashi 		.bar_fixed_64bit = BIT(BAR_0) | BIT(BAR_2) | BIT(BAR_4),
430892fdf15SKunihiko Hayashi 	},
431892fdf15SKunihiko Hayashi };
432892fdf15SKunihiko Hayashi 
4338d7e33d6SKunihiko Hayashi static const struct of_device_id uniphier_pcie_ep_match[] = {
4348d7e33d6SKunihiko Hayashi 	{
4358d7e33d6SKunihiko Hayashi 		.compatible = "socionext,uniphier-pro5-pcie-ep",
4368d7e33d6SKunihiko Hayashi 		.data = &uniphier_pro5_data,
4378d7e33d6SKunihiko Hayashi 	},
438892fdf15SKunihiko Hayashi 	{
439892fdf15SKunihiko Hayashi 		.compatible = "socionext,uniphier-nx1-pcie-ep",
440892fdf15SKunihiko Hayashi 		.data = &uniphier_nx1_data,
441892fdf15SKunihiko Hayashi 	},
4428d7e33d6SKunihiko Hayashi 	{ /* sentinel */ },
4438d7e33d6SKunihiko Hayashi };
4448d7e33d6SKunihiko Hayashi 
4458d7e33d6SKunihiko Hayashi static struct platform_driver uniphier_pcie_ep_driver = {
4468d7e33d6SKunihiko Hayashi 	.probe  = uniphier_pcie_ep_probe,
4478d7e33d6SKunihiko Hayashi 	.driver = {
4488d7e33d6SKunihiko Hayashi 		.name = "uniphier-pcie-ep",
4498d7e33d6SKunihiko Hayashi 		.of_match_table = uniphier_pcie_ep_match,
4508d7e33d6SKunihiko Hayashi 		.suppress_bind_attrs = true,
4518d7e33d6SKunihiko Hayashi 	},
4528d7e33d6SKunihiko Hayashi };
4538d7e33d6SKunihiko Hayashi builtin_platform_driver(uniphier_pcie_ep_driver);
454