linux/drivers/pci/controller/dwc/pci-layerscape.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * PCIe host controller driver for Freescale Layerscape SoCs
   4 *
   5 * Copyright (C) 2014 Freescale Semiconductor.
   6 *
   7 * Author: Minghuan Lian <Minghuan.Lian@freescale.com>
   8 */
   9
  10#include <linux/kernel.h>
  11#include <linux/interrupt.h>
  12#include <linux/init.h>
  13#include <linux/of_pci.h>
  14#include <linux/of_platform.h>
  15#include <linux/of_irq.h>
  16#include <linux/of_address.h>
  17#include <linux/pci.h>
  18#include <linux/platform_device.h>
  19#include <linux/resource.h>
  20#include <linux/mfd/syscon.h>
  21#include <linux/regmap.h>
  22
  23#include "pcie-designware.h"
  24
  25/* PEX1/2 Misc Ports Status Register */
  26#define SCFG_PEXMSCPORTSR(pex_idx)      (0x94 + (pex_idx) * 4)
  27#define LTSSM_STATE_SHIFT       20
  28#define LTSSM_STATE_MASK        0x3f
  29#define LTSSM_PCIE_L0           0x11 /* L0 state */
  30
  31/* PEX Internal Configuration Registers */
  32#define PCIE_STRFMR1            0x71c /* Symbol Timer & Filter Mask Register1 */
  33#define PCIE_ABSERR             0x8d0 /* Bridge Slave Error Response Register */
  34#define PCIE_ABSERR_SETTING     0x9401 /* Forward error of non-posted request */
  35
  36#define PCIE_IATU_NUM           6
  37
  38struct ls_pcie_drvdata {
  39        u32 lut_offset;
  40        u32 ltssm_shift;
  41        u32 lut_dbg;
  42        const struct dw_pcie_host_ops *ops;
  43        const struct dw_pcie_ops *dw_pcie_ops;
  44};
  45
  46struct ls_pcie {
  47        struct dw_pcie *pci;
  48        void __iomem *lut;
  49        struct regmap *scfg;
  50        const struct ls_pcie_drvdata *drvdata;
  51        int index;
  52};
  53
  54#define to_ls_pcie(x)   dev_get_drvdata((x)->dev)
  55
  56static bool ls_pcie_is_bridge(struct ls_pcie *pcie)
  57{
  58        struct dw_pcie *pci = pcie->pci;
  59        u32 header_type;
  60
  61        header_type = ioread8(pci->dbi_base + PCI_HEADER_TYPE);
  62        header_type &= 0x7f;
  63
  64        return header_type == PCI_HEADER_TYPE_BRIDGE;
  65}
  66
  67/* Clear multi-function bit */
  68static void ls_pcie_clear_multifunction(struct ls_pcie *pcie)
  69{
  70        struct dw_pcie *pci = pcie->pci;
  71
  72        iowrite8(PCI_HEADER_TYPE_BRIDGE, pci->dbi_base + PCI_HEADER_TYPE);
  73}
  74
  75/* Drop MSG TLP except for Vendor MSG */
  76static void ls_pcie_drop_msg_tlp(struct ls_pcie *pcie)
  77{
  78        u32 val;
  79        struct dw_pcie *pci = pcie->pci;
  80
  81        val = ioread32(pci->dbi_base + PCIE_STRFMR1);
  82        val &= 0xDFFFFFFF;
  83        iowrite32(val, pci->dbi_base + PCIE_STRFMR1);
  84}
  85
  86static int ls1021_pcie_link_up(struct dw_pcie *pci)
  87{
  88        u32 state;
  89        struct ls_pcie *pcie = to_ls_pcie(pci);
  90
  91        if (!pcie->scfg)
  92                return 0;
  93
  94        regmap_read(pcie->scfg, SCFG_PEXMSCPORTSR(pcie->index), &state);
  95        state = (state >> LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK;
  96
  97        if (state < LTSSM_PCIE_L0)
  98                return 0;
  99
 100        return 1;
 101}
 102
 103static int ls_pcie_link_up(struct dw_pcie *pci)
 104{
 105        struct ls_pcie *pcie = to_ls_pcie(pci);
 106        u32 state;
 107
 108        state = (ioread32(pcie->lut + pcie->drvdata->lut_dbg) >>
 109                 pcie->drvdata->ltssm_shift) &
 110                 LTSSM_STATE_MASK;
 111
 112        if (state < LTSSM_PCIE_L0)
 113                return 0;
 114
 115        return 1;
 116}
 117
 118/* Forward error response of outbound non-posted requests */
 119static void ls_pcie_fix_error_response(struct ls_pcie *pcie)
 120{
 121        struct dw_pcie *pci = pcie->pci;
 122
 123        iowrite32(PCIE_ABSERR_SETTING, pci->dbi_base + PCIE_ABSERR);
 124}
 125
 126static int ls_pcie_host_init(struct pcie_port *pp)
 127{
 128        struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 129        struct ls_pcie *pcie = to_ls_pcie(pci);
 130
 131        ls_pcie_fix_error_response(pcie);
 132
 133        dw_pcie_dbi_ro_wr_en(pci);
 134        ls_pcie_clear_multifunction(pcie);
 135        dw_pcie_dbi_ro_wr_dis(pci);
 136
 137        ls_pcie_drop_msg_tlp(pcie);
 138
 139        return 0;
 140}
 141
 142static int ls1021_pcie_host_init(struct pcie_port *pp)
 143{
 144        struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 145        struct ls_pcie *pcie = to_ls_pcie(pci);
 146        struct device *dev = pci->dev;
 147        u32 index[2];
 148        int ret;
 149
 150        pcie->scfg = syscon_regmap_lookup_by_phandle(dev->of_node,
 151                                                     "fsl,pcie-scfg");
 152        if (IS_ERR(pcie->scfg)) {
 153                ret = PTR_ERR(pcie->scfg);
 154                dev_err(dev, "No syscfg phandle specified\n");
 155                pcie->scfg = NULL;
 156                return ret;
 157        }
 158
 159        if (of_property_read_u32_array(dev->of_node,
 160                                       "fsl,pcie-scfg", index, 2)) {
 161                pcie->scfg = NULL;
 162                return -EINVAL;
 163        }
 164        pcie->index = index[1];
 165
 166        return ls_pcie_host_init(pp);
 167}
 168
 169static const struct dw_pcie_host_ops ls1021_pcie_host_ops = {
 170        .host_init = ls1021_pcie_host_init,
 171};
 172
 173static const struct dw_pcie_host_ops ls_pcie_host_ops = {
 174        .host_init = ls_pcie_host_init,
 175};
 176
 177static const struct dw_pcie_ops dw_ls1021_pcie_ops = {
 178        .link_up = ls1021_pcie_link_up,
 179};
 180
 181static const struct dw_pcie_ops dw_ls_pcie_ops = {
 182        .link_up = ls_pcie_link_up,
 183};
 184
 185static const struct ls_pcie_drvdata ls1021_drvdata = {
 186        .ops = &ls1021_pcie_host_ops,
 187        .dw_pcie_ops = &dw_ls1021_pcie_ops,
 188};
 189
 190static const struct ls_pcie_drvdata ls1043_drvdata = {
 191        .lut_offset = 0x10000,
 192        .ltssm_shift = 24,
 193        .lut_dbg = 0x7fc,
 194        .ops = &ls_pcie_host_ops,
 195        .dw_pcie_ops = &dw_ls_pcie_ops,
 196};
 197
 198static const struct ls_pcie_drvdata ls1046_drvdata = {
 199        .lut_offset = 0x80000,
 200        .ltssm_shift = 24,
 201        .lut_dbg = 0x407fc,
 202        .ops = &ls_pcie_host_ops,
 203        .dw_pcie_ops = &dw_ls_pcie_ops,
 204};
 205
 206static const struct ls_pcie_drvdata ls2080_drvdata = {
 207        .lut_offset = 0x80000,
 208        .ltssm_shift = 0,
 209        .lut_dbg = 0x7fc,
 210        .ops = &ls_pcie_host_ops,
 211        .dw_pcie_ops = &dw_ls_pcie_ops,
 212};
 213
 214static const struct ls_pcie_drvdata ls2088_drvdata = {
 215        .lut_offset = 0x80000,
 216        .ltssm_shift = 0,
 217        .lut_dbg = 0x407fc,
 218        .ops = &ls_pcie_host_ops,
 219        .dw_pcie_ops = &dw_ls_pcie_ops,
 220};
 221
 222static const struct of_device_id ls_pcie_of_match[] = {
 223        { .compatible = "fsl,ls1012a-pcie", .data = &ls1046_drvdata },
 224        { .compatible = "fsl,ls1021a-pcie", .data = &ls1021_drvdata },
 225        { .compatible = "fsl,ls1028a-pcie", .data = &ls2088_drvdata },
 226        { .compatible = "fsl,ls1043a-pcie", .data = &ls1043_drvdata },
 227        { .compatible = "fsl,ls1046a-pcie", .data = &ls1046_drvdata },
 228        { .compatible = "fsl,ls2080a-pcie", .data = &ls2080_drvdata },
 229        { .compatible = "fsl,ls2085a-pcie", .data = &ls2080_drvdata },
 230        { .compatible = "fsl,ls2088a-pcie", .data = &ls2088_drvdata },
 231        { .compatible = "fsl,ls1088a-pcie", .data = &ls2088_drvdata },
 232        { },
 233};
 234
 235static int ls_pcie_probe(struct platform_device *pdev)
 236{
 237        struct device *dev = &pdev->dev;
 238        struct dw_pcie *pci;
 239        struct ls_pcie *pcie;
 240        struct resource *dbi_base;
 241
 242        pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
 243        if (!pcie)
 244                return -ENOMEM;
 245
 246        pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
 247        if (!pci)
 248                return -ENOMEM;
 249
 250        pcie->drvdata = of_device_get_match_data(dev);
 251
 252        pci->dev = dev;
 253        pci->ops = pcie->drvdata->dw_pcie_ops;
 254        pci->pp.ops = pcie->drvdata->ops;
 255
 256        pcie->pci = pci;
 257
 258        dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
 259        pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base);
 260        if (IS_ERR(pci->dbi_base))
 261                return PTR_ERR(pci->dbi_base);
 262
 263        pcie->lut = pci->dbi_base + pcie->drvdata->lut_offset;
 264
 265        if (!ls_pcie_is_bridge(pcie))
 266                return -ENODEV;
 267
 268        platform_set_drvdata(pdev, pcie);
 269
 270        return dw_pcie_host_init(&pci->pp);
 271}
 272
 273static struct platform_driver ls_pcie_driver = {
 274        .probe = ls_pcie_probe,
 275        .driver = {
 276                .name = "layerscape-pcie",
 277                .of_match_table = ls_pcie_of_match,
 278                .suppress_bind_attrs = true,
 279        },
 280};
 281builtin_platform_driver(ls_pcie_driver);
 282