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> 13*892fdf15SKunihiko Hayashi #include <linux/iopoll.h> 148d7e33d6SKunihiko Hayashi #include <linux/of_device.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 35*892fdf15SKunihiko Hayashi #define PCL_PINCTRL0 0x002c 36*892fdf15SKunihiko Hayashi #define PCL_PERST_PLDN_REGEN BIT(12) 37*892fdf15SKunihiko Hayashi #define PCL_PERST_NOE_REGEN BIT(11) 38*892fdf15SKunihiko Hayashi #define PCL_PERST_OUT_REGEN BIT(8) 39*892fdf15SKunihiko Hayashi #define PCL_PERST_PLDN_REGVAL BIT(4) 40*892fdf15SKunihiko Hayashi #define PCL_PERST_NOE_REGVAL BIT(3) 41*892fdf15SKunihiko Hayashi #define PCL_PERST_OUT_REGVAL BIT(0) 42*892fdf15SKunihiko Hayashi 43*892fdf15SKunihiko Hayashi #define PCL_PIPEMON 0x0044 44*892fdf15SKunihiko Hayashi #define PCL_PCLK_ALIVE BIT(15) 45*892fdf15SKunihiko 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 66*892fdf15SKunihiko Hayashi #define PCL_APP_PM0 0x8078 67*892fdf15SKunihiko Hayashi #define PCL_SYS_AUX_PWR_DET BIT(8) 68*892fdf15SKunihiko 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 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 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 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 141*892fdf15SKunihiko Hayashi static void uniphier_pcie_nx1_init_ep(struct uniphier_pcie_ep_priv *priv) 142*892fdf15SKunihiko Hayashi { 143*892fdf15SKunihiko Hayashi u32 val; 144*892fdf15SKunihiko Hayashi 145*892fdf15SKunihiko Hayashi /* set EP mode */ 146*892fdf15SKunihiko Hayashi val = readl(priv->base + PCL_MODE); 147*892fdf15SKunihiko Hayashi val |= PCL_MODE_REGEN | PCL_MODE_REGVAL; 148*892fdf15SKunihiko Hayashi writel(val, priv->base + PCL_MODE); 149*892fdf15SKunihiko Hayashi 150*892fdf15SKunihiko Hayashi /* use auxiliary power detection */ 151*892fdf15SKunihiko Hayashi val = readl(priv->base + PCL_APP_PM0); 152*892fdf15SKunihiko Hayashi val |= PCL_SYS_AUX_PWR_DET; 153*892fdf15SKunihiko Hayashi writel(val, priv->base + PCL_APP_PM0); 154*892fdf15SKunihiko Hayashi 155*892fdf15SKunihiko Hayashi /* assert PERST# */ 156*892fdf15SKunihiko Hayashi val = readl(priv->base + PCL_PINCTRL0); 157*892fdf15SKunihiko Hayashi val &= ~(PCL_PERST_NOE_REGVAL | PCL_PERST_OUT_REGVAL 158*892fdf15SKunihiko Hayashi | PCL_PERST_PLDN_REGVAL); 159*892fdf15SKunihiko Hayashi val |= PCL_PERST_NOE_REGEN | PCL_PERST_OUT_REGEN 160*892fdf15SKunihiko Hayashi | PCL_PERST_PLDN_REGEN; 161*892fdf15SKunihiko Hayashi writel(val, priv->base + PCL_PINCTRL0); 162*892fdf15SKunihiko Hayashi 163*892fdf15SKunihiko Hayashi uniphier_pcie_ltssm_enable(priv, false); 164*892fdf15SKunihiko Hayashi 165*892fdf15SKunihiko Hayashi usleep_range(100000, 200000); 166*892fdf15SKunihiko Hayashi 167*892fdf15SKunihiko Hayashi /* deassert PERST# */ 168*892fdf15SKunihiko Hayashi val = readl(priv->base + PCL_PINCTRL0); 169*892fdf15SKunihiko Hayashi val |= PCL_PERST_OUT_REGVAL | PCL_PERST_OUT_REGEN; 170*892fdf15SKunihiko Hayashi writel(val, priv->base + PCL_PINCTRL0); 171*892fdf15SKunihiko Hayashi } 172*892fdf15SKunihiko Hayashi 173*892fdf15SKunihiko Hayashi static int uniphier_pcie_nx1_wait_ep(struct uniphier_pcie_ep_priv *priv) 174*892fdf15SKunihiko Hayashi { 175*892fdf15SKunihiko Hayashi u32 status; 176*892fdf15SKunihiko Hayashi int ret; 177*892fdf15SKunihiko Hayashi 178*892fdf15SKunihiko Hayashi /* wait PIPE clock */ 179*892fdf15SKunihiko Hayashi ret = readl_poll_timeout(priv->base + PCL_PIPEMON, status, 180*892fdf15SKunihiko Hayashi status & PCL_PCLK_ALIVE, 100000, 1000000); 181*892fdf15SKunihiko Hayashi if (ret) { 182*892fdf15SKunihiko Hayashi dev_err(priv->pci.dev, 183*892fdf15SKunihiko Hayashi "Failed to initialize controller in EP mode\n"); 184*892fdf15SKunihiko Hayashi return ret; 185*892fdf15SKunihiko Hayashi } 186*892fdf15SKunihiko Hayashi 187*892fdf15SKunihiko Hayashi return 0; 188*892fdf15SKunihiko Hayashi } 189*892fdf15SKunihiko Hayashi 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 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 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 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 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 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* 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 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 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 420*892fdf15SKunihiko Hayashi static const struct uniphier_pcie_ep_soc_data uniphier_nx1_data = { 421*892fdf15SKunihiko Hayashi .has_gio = false, 422*892fdf15SKunihiko Hayashi .init = uniphier_pcie_nx1_init_ep, 423*892fdf15SKunihiko Hayashi .wait = uniphier_pcie_nx1_wait_ep, 424*892fdf15SKunihiko Hayashi .features = { 425*892fdf15SKunihiko Hayashi .linkup_notifier = false, 426*892fdf15SKunihiko Hayashi .msi_capable = true, 427*892fdf15SKunihiko Hayashi .msix_capable = false, 428*892fdf15SKunihiko Hayashi .align = 1 << 12, 429*892fdf15SKunihiko Hayashi .bar_fixed_64bit = BIT(BAR_0) | BIT(BAR_2) | BIT(BAR_4), 430*892fdf15SKunihiko Hayashi }, 431*892fdf15SKunihiko Hayashi }; 432*892fdf15SKunihiko 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 }, 438*892fdf15SKunihiko Hayashi { 439*892fdf15SKunihiko Hayashi .compatible = "socionext,uniphier-nx1-pcie-ep", 440*892fdf15SKunihiko Hayashi .data = &uniphier_nx1_data, 441*892fdf15SKunihiko 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