linux/drivers/pci/controller/dwc/pcie-uniphier-ep.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * PCIe endpoint controller driver for UniPhier SoCs
   4 * Copyright 2018 Socionext Inc.
   5 * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
   6 */
   7
   8#include <linux/bitops.h>
   9#include <linux/bitfield.h>
  10#include <linux/clk.h>
  11#include <linux/delay.h>
  12#include <linux/init.h>
  13#include <linux/of_device.h>
  14#include <linux/pci.h>
  15#include <linux/phy/phy.h>
  16#include <linux/platform_device.h>
  17#include <linux/reset.h>
  18
  19#include "pcie-designware.h"
  20
  21/* Link Glue registers */
  22#define PCL_RSTCTRL0                    0x0010
  23#define PCL_RSTCTRL_AXI_REG             BIT(3)
  24#define PCL_RSTCTRL_AXI_SLAVE           BIT(2)
  25#define PCL_RSTCTRL_AXI_MASTER          BIT(1)
  26#define PCL_RSTCTRL_PIPE3               BIT(0)
  27
  28#define PCL_RSTCTRL1                    0x0020
  29#define PCL_RSTCTRL_PERST               BIT(0)
  30
  31#define PCL_RSTCTRL2                    0x0024
  32#define PCL_RSTCTRL_PHY_RESET           BIT(0)
  33
  34#define PCL_MODE                        0x8000
  35#define PCL_MODE_REGEN                  BIT(8)
  36#define PCL_MODE_REGVAL                 BIT(0)
  37
  38#define PCL_APP_CLK_CTRL                0x8004
  39#define PCL_APP_CLK_REQ                 BIT(0)
  40
  41#define PCL_APP_READY_CTRL              0x8008
  42#define PCL_APP_LTSSM_ENABLE            BIT(0)
  43
  44#define PCL_APP_MSI0                    0x8040
  45#define PCL_APP_VEN_MSI_TC_MASK         GENMASK(10, 8)
  46#define PCL_APP_VEN_MSI_VECTOR_MASK     GENMASK(4, 0)
  47
  48#define PCL_APP_MSI1                    0x8044
  49#define PCL_APP_MSI_REQ                 BIT(0)
  50
  51#define PCL_APP_INTX                    0x8074
  52#define PCL_APP_INTX_SYS_INT            BIT(0)
  53
  54/* assertion time of INTx in usec */
  55#define PCL_INTX_WIDTH_USEC             30
  56
  57struct uniphier_pcie_ep_priv {
  58        void __iomem *base;
  59        struct dw_pcie pci;
  60        struct clk *clk, *clk_gio;
  61        struct reset_control *rst, *rst_gio;
  62        struct phy *phy;
  63        const struct pci_epc_features *features;
  64};
  65
  66#define to_uniphier_pcie(x)     dev_get_drvdata((x)->dev)
  67
  68static void uniphier_pcie_ltssm_enable(struct uniphier_pcie_ep_priv *priv,
  69                                       bool enable)
  70{
  71        u32 val;
  72
  73        val = readl(priv->base + PCL_APP_READY_CTRL);
  74        if (enable)
  75                val |= PCL_APP_LTSSM_ENABLE;
  76        else
  77                val &= ~PCL_APP_LTSSM_ENABLE;
  78        writel(val, priv->base + PCL_APP_READY_CTRL);
  79}
  80
  81static void uniphier_pcie_phy_reset(struct uniphier_pcie_ep_priv *priv,
  82                                    bool assert)
  83{
  84        u32 val;
  85
  86        val = readl(priv->base + PCL_RSTCTRL2);
  87        if (assert)
  88                val |= PCL_RSTCTRL_PHY_RESET;
  89        else
  90                val &= ~PCL_RSTCTRL_PHY_RESET;
  91        writel(val, priv->base + PCL_RSTCTRL2);
  92}
  93
  94static void uniphier_pcie_init_ep(struct uniphier_pcie_ep_priv *priv)
  95{
  96        u32 val;
  97
  98        /* set EP mode */
  99        val = readl(priv->base + PCL_MODE);
 100        val |= PCL_MODE_REGEN | PCL_MODE_REGVAL;
 101        writel(val, priv->base + PCL_MODE);
 102
 103        /* clock request */
 104        val = readl(priv->base + PCL_APP_CLK_CTRL);
 105        val &= ~PCL_APP_CLK_REQ;
 106        writel(val, priv->base + PCL_APP_CLK_CTRL);
 107
 108        /* deassert PIPE3 and AXI reset */
 109        val = readl(priv->base + PCL_RSTCTRL0);
 110        val |= PCL_RSTCTRL_AXI_REG | PCL_RSTCTRL_AXI_SLAVE
 111                | PCL_RSTCTRL_AXI_MASTER | PCL_RSTCTRL_PIPE3;
 112        writel(val, priv->base + PCL_RSTCTRL0);
 113
 114        uniphier_pcie_ltssm_enable(priv, false);
 115
 116        msleep(100);
 117}
 118
 119static int uniphier_pcie_start_link(struct dw_pcie *pci)
 120{
 121        struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci);
 122
 123        uniphier_pcie_ltssm_enable(priv, true);
 124
 125        return 0;
 126}
 127
 128static void uniphier_pcie_stop_link(struct dw_pcie *pci)
 129{
 130        struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci);
 131
 132        uniphier_pcie_ltssm_enable(priv, false);
 133}
 134
 135static void uniphier_pcie_ep_init(struct dw_pcie_ep *ep)
 136{
 137        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
 138        enum pci_barno bar;
 139
 140        for (bar = BAR_0; bar <= BAR_5; bar++)
 141                dw_pcie_ep_reset_bar(pci, bar);
 142}
 143
 144static int uniphier_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep)
 145{
 146        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
 147        struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci);
 148        u32 val;
 149
 150        /*
 151         * This makes pulse signal to send INTx to the RC, so this should
 152         * be cleared as soon as possible. This sequence is covered with
 153         * mutex in pci_epc_raise_irq().
 154         */
 155        /* assert INTx */
 156        val = readl(priv->base + PCL_APP_INTX);
 157        val |= PCL_APP_INTX_SYS_INT;
 158        writel(val, priv->base + PCL_APP_INTX);
 159
 160        udelay(PCL_INTX_WIDTH_USEC);
 161
 162        /* deassert INTx */
 163        val &= ~PCL_APP_INTX_SYS_INT;
 164        writel(val, priv->base + PCL_APP_INTX);
 165
 166        return 0;
 167}
 168
 169static int uniphier_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep,
 170                                          u8 func_no, u16 interrupt_num)
 171{
 172        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
 173        struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci);
 174        u32 val;
 175
 176        val = FIELD_PREP(PCL_APP_VEN_MSI_TC_MASK, func_no)
 177                | FIELD_PREP(PCL_APP_VEN_MSI_VECTOR_MASK, interrupt_num - 1);
 178        writel(val, priv->base + PCL_APP_MSI0);
 179
 180        val = readl(priv->base + PCL_APP_MSI1);
 181        val |= PCL_APP_MSI_REQ;
 182        writel(val, priv->base + PCL_APP_MSI1);
 183
 184        return 0;
 185}
 186
 187static int uniphier_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
 188                                      enum pci_epc_irq_type type,
 189                                      u16 interrupt_num)
 190{
 191        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
 192
 193        switch (type) {
 194        case PCI_EPC_IRQ_LEGACY:
 195                return uniphier_pcie_ep_raise_legacy_irq(ep);
 196        case PCI_EPC_IRQ_MSI:
 197                return uniphier_pcie_ep_raise_msi_irq(ep, func_no,
 198                                                      interrupt_num);
 199        default:
 200                dev_err(pci->dev, "UNKNOWN IRQ type (%d)\n", type);
 201        }
 202
 203        return 0;
 204}
 205
 206static const struct pci_epc_features*
 207uniphier_pcie_get_features(struct dw_pcie_ep *ep)
 208{
 209        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
 210        struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci);
 211
 212        return priv->features;
 213}
 214
 215static const struct dw_pcie_ep_ops uniphier_pcie_ep_ops = {
 216        .ep_init = uniphier_pcie_ep_init,
 217        .raise_irq = uniphier_pcie_ep_raise_irq,
 218        .get_features = uniphier_pcie_get_features,
 219};
 220
 221static int uniphier_pcie_ep_enable(struct uniphier_pcie_ep_priv *priv)
 222{
 223        int ret;
 224
 225        ret = clk_prepare_enable(priv->clk);
 226        if (ret)
 227                return ret;
 228
 229        ret = clk_prepare_enable(priv->clk_gio);
 230        if (ret)
 231                goto out_clk_disable;
 232
 233        ret = reset_control_deassert(priv->rst);
 234        if (ret)
 235                goto out_clk_gio_disable;
 236
 237        ret = reset_control_deassert(priv->rst_gio);
 238        if (ret)
 239                goto out_rst_assert;
 240
 241        uniphier_pcie_init_ep(priv);
 242
 243        uniphier_pcie_phy_reset(priv, true);
 244
 245        ret = phy_init(priv->phy);
 246        if (ret)
 247                goto out_rst_gio_assert;
 248
 249        uniphier_pcie_phy_reset(priv, false);
 250
 251        return 0;
 252
 253out_rst_gio_assert:
 254        reset_control_assert(priv->rst_gio);
 255out_rst_assert:
 256        reset_control_assert(priv->rst);
 257out_clk_gio_disable:
 258        clk_disable_unprepare(priv->clk_gio);
 259out_clk_disable:
 260        clk_disable_unprepare(priv->clk);
 261
 262        return ret;
 263}
 264
 265static const struct dw_pcie_ops dw_pcie_ops = {
 266        .start_link = uniphier_pcie_start_link,
 267        .stop_link = uniphier_pcie_stop_link,
 268};
 269
 270static int uniphier_pcie_ep_probe(struct platform_device *pdev)
 271{
 272        struct device *dev = &pdev->dev;
 273        struct uniphier_pcie_ep_priv *priv;
 274        int ret;
 275
 276        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 277        if (!priv)
 278                return -ENOMEM;
 279
 280        priv->features = of_device_get_match_data(dev);
 281        if (WARN_ON(!priv->features))
 282                return -EINVAL;
 283
 284        priv->pci.dev = dev;
 285        priv->pci.ops = &dw_pcie_ops;
 286
 287        priv->base = devm_platform_ioremap_resource_byname(pdev, "link");
 288        if (IS_ERR(priv->base))
 289                return PTR_ERR(priv->base);
 290
 291        priv->clk_gio = devm_clk_get(dev, "gio");
 292        if (IS_ERR(priv->clk_gio))
 293                return PTR_ERR(priv->clk_gio);
 294
 295        priv->rst_gio = devm_reset_control_get_shared(dev, "gio");
 296        if (IS_ERR(priv->rst_gio))
 297                return PTR_ERR(priv->rst_gio);
 298
 299        priv->clk = devm_clk_get(dev, "link");
 300        if (IS_ERR(priv->clk))
 301                return PTR_ERR(priv->clk);
 302
 303        priv->rst = devm_reset_control_get_shared(dev, "link");
 304        if (IS_ERR(priv->rst))
 305                return PTR_ERR(priv->rst);
 306
 307        priv->phy = devm_phy_optional_get(dev, "pcie-phy");
 308        if (IS_ERR(priv->phy)) {
 309                ret = PTR_ERR(priv->phy);
 310                dev_err(dev, "Failed to get phy (%d)\n", ret);
 311                return ret;
 312        }
 313
 314        platform_set_drvdata(pdev, priv);
 315
 316        ret = uniphier_pcie_ep_enable(priv);
 317        if (ret)
 318                return ret;
 319
 320        priv->pci.ep.ops = &uniphier_pcie_ep_ops;
 321        return dw_pcie_ep_init(&priv->pci.ep);
 322}
 323
 324static const struct pci_epc_features uniphier_pro5_data = {
 325        .linkup_notifier = false,
 326        .msi_capable = true,
 327        .msix_capable = false,
 328        .align = 1 << 16,
 329        .bar_fixed_64bit = BIT(BAR_0) | BIT(BAR_2) | BIT(BAR_4),
 330        .reserved_bar =  BIT(BAR_4),
 331};
 332
 333static const struct of_device_id uniphier_pcie_ep_match[] = {
 334        {
 335                .compatible = "socionext,uniphier-pro5-pcie-ep",
 336                .data = &uniphier_pro5_data,
 337        },
 338        { /* sentinel */ },
 339};
 340
 341static struct platform_driver uniphier_pcie_ep_driver = {
 342        .probe  = uniphier_pcie_ep_probe,
 343        .driver = {
 344                .name = "uniphier-pcie-ep",
 345                .of_match_table = uniphier_pcie_ep_match,
 346                .suppress_bind_attrs = true,
 347        },
 348};
 349builtin_platform_driver(uniphier_pcie_ep_driver);
 350