linux/drivers/pci/controller/dwc/pcie-keembay.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * PCIe controller driver for Intel Keem Bay
   4 * Copyright (C) 2020 Intel Corporation
   5 */
   6
   7#include <linux/bitfield.h>
   8#include <linux/bits.h>
   9#include <linux/clk.h>
  10#include <linux/delay.h>
  11#include <linux/err.h>
  12#include <linux/gpio/consumer.h>
  13#include <linux/init.h>
  14#include <linux/iopoll.h>
  15#include <linux/irqchip/chained_irq.h>
  16#include <linux/kernel.h>
  17#include <linux/mod_devicetable.h>
  18#include <linux/pci.h>
  19#include <linux/platform_device.h>
  20#include <linux/property.h>
  21
  22#include "pcie-designware.h"
  23
  24/* PCIE_REGS_APB_SLV Registers */
  25#define PCIE_REGS_PCIE_CFG              0x0004
  26#define  PCIE_DEVICE_TYPE               BIT(8)
  27#define  PCIE_RSTN                      BIT(0)
  28#define PCIE_REGS_PCIE_APP_CNTRL        0x0008
  29#define  APP_LTSSM_ENABLE               BIT(0)
  30#define PCIE_REGS_INTERRUPT_ENABLE      0x0028
  31#define  MSI_CTRL_INT_EN                BIT(8)
  32#define  EDMA_INT_EN                    GENMASK(7, 0)
  33#define PCIE_REGS_INTERRUPT_STATUS      0x002c
  34#define  MSI_CTRL_INT                   BIT(8)
  35#define PCIE_REGS_PCIE_SII_PM_STATE     0x00b0
  36#define  SMLH_LINK_UP                   BIT(19)
  37#define  RDLH_LINK_UP                   BIT(8)
  38#define  PCIE_REGS_PCIE_SII_LINK_UP     (SMLH_LINK_UP | RDLH_LINK_UP)
  39#define PCIE_REGS_PCIE_PHY_CNTL         0x0164
  40#define  PHY0_SRAM_BYPASS               BIT(8)
  41#define PCIE_REGS_PCIE_PHY_STAT         0x0168
  42#define  PHY0_MPLLA_STATE               BIT(1)
  43#define PCIE_REGS_LJPLL_STA             0x016c
  44#define  LJPLL_LOCK                     BIT(0)
  45#define PCIE_REGS_LJPLL_CNTRL_0         0x0170
  46#define  LJPLL_EN                       BIT(29)
  47#define  LJPLL_FOUT_EN                  GENMASK(24, 21)
  48#define PCIE_REGS_LJPLL_CNTRL_2         0x0178
  49#define  LJPLL_REF_DIV                  GENMASK(17, 12)
  50#define  LJPLL_FB_DIV                   GENMASK(11, 0)
  51#define PCIE_REGS_LJPLL_CNTRL_3         0x017c
  52#define  LJPLL_POST_DIV3A               GENMASK(24, 22)
  53#define  LJPLL_POST_DIV2A               GENMASK(18, 16)
  54
  55#define PERST_DELAY_US          1000
  56#define AUX_CLK_RATE_HZ         24000000
  57
  58struct keembay_pcie {
  59        struct dw_pcie          pci;
  60        void __iomem            *apb_base;
  61        enum dw_pcie_device_mode mode;
  62
  63        struct clk              *clk_master;
  64        struct clk              *clk_aux;
  65        struct gpio_desc        *reset;
  66};
  67
  68struct keembay_pcie_of_data {
  69        enum dw_pcie_device_mode mode;
  70};
  71
  72static void keembay_ep_reset_assert(struct keembay_pcie *pcie)
  73{
  74        gpiod_set_value_cansleep(pcie->reset, 1);
  75        usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
  76}
  77
  78static void keembay_ep_reset_deassert(struct keembay_pcie *pcie)
  79{
  80        /*
  81         * Ensure that PERST# is asserted for a minimum of 100ms.
  82         *
  83         * For more details, refer to PCI Express Card Electromechanical
  84         * Specification Revision 1.1, Table-2.4.
  85         */
  86        msleep(100);
  87
  88        gpiod_set_value_cansleep(pcie->reset, 0);
  89        usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
  90}
  91
  92static void keembay_pcie_ltssm_set(struct keembay_pcie *pcie, bool enable)
  93{
  94        u32 val;
  95
  96        val = readl(pcie->apb_base + PCIE_REGS_PCIE_APP_CNTRL);
  97        if (enable)
  98                val |= APP_LTSSM_ENABLE;
  99        else
 100                val &= ~APP_LTSSM_ENABLE;
 101        writel(val, pcie->apb_base + PCIE_REGS_PCIE_APP_CNTRL);
 102}
 103
 104static int keembay_pcie_link_up(struct dw_pcie *pci)
 105{
 106        struct keembay_pcie *pcie = dev_get_drvdata(pci->dev);
 107        u32 val;
 108
 109        val = readl(pcie->apb_base + PCIE_REGS_PCIE_SII_PM_STATE);
 110
 111        return (val & PCIE_REGS_PCIE_SII_LINK_UP) == PCIE_REGS_PCIE_SII_LINK_UP;
 112}
 113
 114static int keembay_pcie_start_link(struct dw_pcie *pci)
 115{
 116        struct keembay_pcie *pcie = dev_get_drvdata(pci->dev);
 117        u32 val;
 118        int ret;
 119
 120        if (pcie->mode == DW_PCIE_EP_TYPE)
 121                return 0;
 122
 123        keembay_pcie_ltssm_set(pcie, false);
 124
 125        ret = readl_poll_timeout(pcie->apb_base + PCIE_REGS_PCIE_PHY_STAT,
 126                                 val, val & PHY0_MPLLA_STATE, 20,
 127                                 500 * USEC_PER_MSEC);
 128        if (ret) {
 129                dev_err(pci->dev, "MPLLA is not locked\n");
 130                return ret;
 131        }
 132
 133        keembay_pcie_ltssm_set(pcie, true);
 134
 135        return 0;
 136}
 137
 138static void keembay_pcie_stop_link(struct dw_pcie *pci)
 139{
 140        struct keembay_pcie *pcie = dev_get_drvdata(pci->dev);
 141
 142        keembay_pcie_ltssm_set(pcie, false);
 143}
 144
 145static const struct dw_pcie_ops keembay_pcie_ops = {
 146        .link_up        = keembay_pcie_link_up,
 147        .start_link     = keembay_pcie_start_link,
 148        .stop_link      = keembay_pcie_stop_link,
 149};
 150
 151static inline struct clk *keembay_pcie_probe_clock(struct device *dev,
 152                                                   const char *id, u64 rate)
 153{
 154        struct clk *clk;
 155        int ret;
 156
 157        clk = devm_clk_get(dev, id);
 158        if (IS_ERR(clk))
 159                return clk;
 160
 161        if (rate) {
 162                ret = clk_set_rate(clk, rate);
 163                if (ret)
 164                        return ERR_PTR(ret);
 165        }
 166
 167        ret = clk_prepare_enable(clk);
 168        if (ret)
 169                return ERR_PTR(ret);
 170
 171        ret = devm_add_action_or_reset(dev,
 172                                       (void(*)(void *))clk_disable_unprepare,
 173                                       clk);
 174        if (ret)
 175                return ERR_PTR(ret);
 176
 177        return clk;
 178}
 179
 180static int keembay_pcie_probe_clocks(struct keembay_pcie *pcie)
 181{
 182        struct dw_pcie *pci = &pcie->pci;
 183        struct device *dev = pci->dev;
 184
 185        pcie->clk_master = keembay_pcie_probe_clock(dev, "master", 0);
 186        if (IS_ERR(pcie->clk_master))
 187                return dev_err_probe(dev, PTR_ERR(pcie->clk_master),
 188                                     "Failed to enable master clock");
 189
 190        pcie->clk_aux = keembay_pcie_probe_clock(dev, "aux", AUX_CLK_RATE_HZ);
 191        if (IS_ERR(pcie->clk_aux))
 192                return dev_err_probe(dev, PTR_ERR(pcie->clk_aux),
 193                                     "Failed to enable auxiliary clock");
 194
 195        return 0;
 196}
 197
 198/*
 199 * Initialize the internal PCIe PLL in Host mode.
 200 * See the following sections in Keem Bay data book,
 201 * (1) 6.4.6.1 PCIe Subsystem Example Initialization,
 202 * (2) 6.8 PCIe Low Jitter PLL for Ref Clk Generation.
 203 */
 204static int keembay_pcie_pll_init(struct keembay_pcie *pcie)
 205{
 206        struct dw_pcie *pci = &pcie->pci;
 207        u32 val;
 208        int ret;
 209
 210        val = FIELD_PREP(LJPLL_REF_DIV, 0) | FIELD_PREP(LJPLL_FB_DIV, 0x32);
 211        writel(val, pcie->apb_base + PCIE_REGS_LJPLL_CNTRL_2);
 212
 213        val = FIELD_PREP(LJPLL_POST_DIV3A, 0x2) |
 214                FIELD_PREP(LJPLL_POST_DIV2A, 0x2);
 215        writel(val, pcie->apb_base + PCIE_REGS_LJPLL_CNTRL_3);
 216
 217        val = FIELD_PREP(LJPLL_EN, 0x1) | FIELD_PREP(LJPLL_FOUT_EN, 0xc);
 218        writel(val, pcie->apb_base + PCIE_REGS_LJPLL_CNTRL_0);
 219
 220        ret = readl_poll_timeout(pcie->apb_base + PCIE_REGS_LJPLL_STA,
 221                                 val, val & LJPLL_LOCK, 20,
 222                                 500 * USEC_PER_MSEC);
 223        if (ret)
 224                dev_err(pci->dev, "Low jitter PLL is not locked\n");
 225
 226        return ret;
 227}
 228
 229static void keembay_pcie_msi_irq_handler(struct irq_desc *desc)
 230{
 231        struct keembay_pcie *pcie = irq_desc_get_handler_data(desc);
 232        struct irq_chip *chip = irq_desc_get_chip(desc);
 233        u32 val, mask, status;
 234        struct pcie_port *pp;
 235
 236        /*
 237         * Keem Bay PCIe Controller provides an additional IP logic on top of
 238         * standard DWC IP to clear MSI IRQ by writing '1' to the respective
 239         * bit of the status register.
 240         *
 241         * So, a chained irq handler is defined to handle this additional
 242         * IP logic.
 243         */
 244
 245        chained_irq_enter(chip, desc);
 246
 247        pp = &pcie->pci.pp;
 248        val = readl(pcie->apb_base + PCIE_REGS_INTERRUPT_STATUS);
 249        mask = readl(pcie->apb_base + PCIE_REGS_INTERRUPT_ENABLE);
 250
 251        status = val & mask;
 252
 253        if (status & MSI_CTRL_INT) {
 254                dw_handle_msi_irq(pp);
 255                writel(status, pcie->apb_base + PCIE_REGS_INTERRUPT_STATUS);
 256        }
 257
 258        chained_irq_exit(chip, desc);
 259}
 260
 261static int keembay_pcie_setup_msi_irq(struct keembay_pcie *pcie)
 262{
 263        struct dw_pcie *pci = &pcie->pci;
 264        struct device *dev = pci->dev;
 265        struct platform_device *pdev = to_platform_device(dev);
 266        int irq;
 267
 268        irq = platform_get_irq_byname(pdev, "pcie");
 269        if (irq < 0)
 270                return irq;
 271
 272        irq_set_chained_handler_and_data(irq, keembay_pcie_msi_irq_handler,
 273                                         pcie);
 274
 275        return 0;
 276}
 277
 278static void keembay_pcie_ep_init(struct dw_pcie_ep *ep)
 279{
 280        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
 281        struct keembay_pcie *pcie = dev_get_drvdata(pci->dev);
 282
 283        writel(EDMA_INT_EN, pcie->apb_base + PCIE_REGS_INTERRUPT_ENABLE);
 284}
 285
 286static int keembay_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
 287                                     enum pci_epc_irq_type type,
 288                                     u16 interrupt_num)
 289{
 290        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
 291
 292        switch (type) {
 293        case PCI_EPC_IRQ_LEGACY:
 294                /* Legacy interrupts are not supported in Keem Bay */
 295                dev_err(pci->dev, "Legacy IRQ is not supported\n");
 296                return -EINVAL;
 297        case PCI_EPC_IRQ_MSI:
 298                return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
 299        case PCI_EPC_IRQ_MSIX:
 300                return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num);
 301        default:
 302                dev_err(pci->dev, "Unknown IRQ type %d\n", type);
 303                return -EINVAL;
 304        }
 305}
 306
 307static const struct pci_epc_features keembay_pcie_epc_features = {
 308        .linkup_notifier        = false,
 309        .msi_capable            = true,
 310        .msix_capable           = true,
 311        .reserved_bar           = BIT(BAR_1) | BIT(BAR_3) | BIT(BAR_5),
 312        .bar_fixed_64bit        = BIT(BAR_0) | BIT(BAR_2) | BIT(BAR_4),
 313        .align                  = SZ_16K,
 314};
 315
 316static const struct pci_epc_features *
 317keembay_pcie_get_features(struct dw_pcie_ep *ep)
 318{
 319        return &keembay_pcie_epc_features;
 320}
 321
 322static const struct dw_pcie_ep_ops keembay_pcie_ep_ops = {
 323        .ep_init        = keembay_pcie_ep_init,
 324        .raise_irq      = keembay_pcie_ep_raise_irq,
 325        .get_features   = keembay_pcie_get_features,
 326};
 327
 328static const struct dw_pcie_host_ops keembay_pcie_host_ops = {
 329};
 330
 331static int keembay_pcie_add_pcie_port(struct keembay_pcie *pcie,
 332                                      struct platform_device *pdev)
 333{
 334        struct dw_pcie *pci = &pcie->pci;
 335        struct pcie_port *pp = &pci->pp;
 336        struct device *dev = &pdev->dev;
 337        u32 val;
 338        int ret;
 339
 340        pp->ops = &keembay_pcie_host_ops;
 341        pp->msi_irq = -ENODEV;
 342
 343        ret = keembay_pcie_setup_msi_irq(pcie);
 344        if (ret)
 345                return ret;
 346
 347        pcie->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
 348        if (IS_ERR(pcie->reset))
 349                return PTR_ERR(pcie->reset);
 350
 351        ret = keembay_pcie_probe_clocks(pcie);
 352        if (ret)
 353                return ret;
 354
 355        val = readl(pcie->apb_base + PCIE_REGS_PCIE_PHY_CNTL);
 356        val |= PHY0_SRAM_BYPASS;
 357        writel(val, pcie->apb_base + PCIE_REGS_PCIE_PHY_CNTL);
 358
 359        writel(PCIE_DEVICE_TYPE, pcie->apb_base + PCIE_REGS_PCIE_CFG);
 360
 361        ret = keembay_pcie_pll_init(pcie);
 362        if (ret)
 363                return ret;
 364
 365        val = readl(pcie->apb_base + PCIE_REGS_PCIE_CFG);
 366        writel(val | PCIE_RSTN, pcie->apb_base + PCIE_REGS_PCIE_CFG);
 367        keembay_ep_reset_deassert(pcie);
 368
 369        ret = dw_pcie_host_init(pp);
 370        if (ret) {
 371                keembay_ep_reset_assert(pcie);
 372                dev_err(dev, "Failed to initialize host: %d\n", ret);
 373                return ret;
 374        }
 375
 376        val = readl(pcie->apb_base + PCIE_REGS_INTERRUPT_ENABLE);
 377        if (IS_ENABLED(CONFIG_PCI_MSI))
 378                val |= MSI_CTRL_INT_EN;
 379        writel(val, pcie->apb_base + PCIE_REGS_INTERRUPT_ENABLE);
 380
 381        return 0;
 382}
 383
 384static int keembay_pcie_probe(struct platform_device *pdev)
 385{
 386        const struct keembay_pcie_of_data *data;
 387        struct device *dev = &pdev->dev;
 388        struct keembay_pcie *pcie;
 389        struct dw_pcie *pci;
 390        enum dw_pcie_device_mode mode;
 391
 392        data = device_get_match_data(dev);
 393        if (!data)
 394                return -ENODEV;
 395
 396        mode = (enum dw_pcie_device_mode)data->mode;
 397
 398        pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
 399        if (!pcie)
 400                return -ENOMEM;
 401
 402        pci = &pcie->pci;
 403        pci->dev = dev;
 404        pci->ops = &keembay_pcie_ops;
 405
 406        pcie->mode = mode;
 407
 408        pcie->apb_base = devm_platform_ioremap_resource_byname(pdev, "apb");
 409        if (IS_ERR(pcie->apb_base))
 410                return PTR_ERR(pcie->apb_base);
 411
 412        platform_set_drvdata(pdev, pcie);
 413
 414        switch (pcie->mode) {
 415        case DW_PCIE_RC_TYPE:
 416                if (!IS_ENABLED(CONFIG_PCIE_KEEMBAY_HOST))
 417                        return -ENODEV;
 418
 419                return keembay_pcie_add_pcie_port(pcie, pdev);
 420        case DW_PCIE_EP_TYPE:
 421                if (!IS_ENABLED(CONFIG_PCIE_KEEMBAY_EP))
 422                        return -ENODEV;
 423
 424                pci->ep.ops = &keembay_pcie_ep_ops;
 425                return dw_pcie_ep_init(&pci->ep);
 426        default:
 427                dev_err(dev, "Invalid device type %d\n", pcie->mode);
 428                return -ENODEV;
 429        }
 430}
 431
 432static const struct keembay_pcie_of_data keembay_pcie_rc_of_data = {
 433        .mode = DW_PCIE_RC_TYPE,
 434};
 435
 436static const struct keembay_pcie_of_data keembay_pcie_ep_of_data = {
 437        .mode = DW_PCIE_EP_TYPE,
 438};
 439
 440static const struct of_device_id keembay_pcie_of_match[] = {
 441        {
 442                .compatible = "intel,keembay-pcie",
 443                .data = &keembay_pcie_rc_of_data,
 444        },
 445        {
 446                .compatible = "intel,keembay-pcie-ep",
 447                .data = &keembay_pcie_ep_of_data,
 448        },
 449        {}
 450};
 451
 452static struct platform_driver keembay_pcie_driver = {
 453        .driver = {
 454                .name = "keembay-pcie",
 455                .of_match_table = keembay_pcie_of_match,
 456                .suppress_bind_attrs = true,
 457        },
 458        .probe  = keembay_pcie_probe,
 459};
 460builtin_platform_driver(keembay_pcie_driver);
 461