linux/drivers/pci/dwc/pcie-hisi.c
<<
>>
Prefs
   1/*
   2 * PCIe host controller driver for HiSilicon SoCs
   3 *
   4 * Copyright (C) 2015 HiSilicon Co., Ltd. http://www.hisilicon.com
   5 *
   6 * Authors: Zhou Wang <wangzhou1@hisilicon.com>
   7 *          Dacai Zhu <zhudacai@hisilicon.com>
   8 *          Gabriele Paoloni <gabriele.paoloni@huawei.com>
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License version 2 as
  12 * published by the Free Software Foundation.
  13 */
  14#include <linux/interrupt.h>
  15#include <linux/init.h>
  16#include <linux/mfd/syscon.h>
  17#include <linux/of_address.h>
  18#include <linux/of_pci.h>
  19#include <linux/platform_device.h>
  20#include <linux/of_device.h>
  21#include <linux/pci.h>
  22#include <linux/pci-acpi.h>
  23#include <linux/pci-ecam.h>
  24#include <linux/regmap.h>
  25#include "../pci.h"
  26
  27#if defined(CONFIG_PCI_HISI) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS))
  28
  29static int hisi_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
  30                             int size, u32 *val)
  31{
  32        struct pci_config_window *cfg = bus->sysdata;
  33        int dev = PCI_SLOT(devfn);
  34
  35        if (bus->number == cfg->busr.start) {
  36                /* access only one slot on each root port */
  37                if (dev > 0)
  38                        return PCIBIOS_DEVICE_NOT_FOUND;
  39                else
  40                        return pci_generic_config_read32(bus, devfn, where,
  41                                                         size, val);
  42        }
  43
  44        return pci_generic_config_read(bus, devfn, where, size, val);
  45}
  46
  47static int hisi_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
  48                             int where, int size, u32 val)
  49{
  50        struct pci_config_window *cfg = bus->sysdata;
  51        int dev = PCI_SLOT(devfn);
  52
  53        if (bus->number == cfg->busr.start) {
  54                /* access only one slot on each root port */
  55                if (dev > 0)
  56                        return PCIBIOS_DEVICE_NOT_FOUND;
  57                else
  58                        return pci_generic_config_write32(bus, devfn, where,
  59                                                          size, val);
  60        }
  61
  62        return pci_generic_config_write(bus, devfn, where, size, val);
  63}
  64
  65static void __iomem *hisi_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
  66                                       int where)
  67{
  68        struct pci_config_window *cfg = bus->sysdata;
  69        void __iomem *reg_base = cfg->priv;
  70
  71        if (bus->number == cfg->busr.start)
  72                return reg_base + where;
  73        else
  74                return pci_ecam_map_bus(bus, devfn, where);
  75}
  76
  77#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
  78
  79static int hisi_pcie_init(struct pci_config_window *cfg)
  80{
  81        struct device *dev = cfg->parent;
  82        struct acpi_device *adev = to_acpi_device(dev);
  83        struct acpi_pci_root *root = acpi_driver_data(adev);
  84        struct resource *res;
  85        void __iomem *reg_base;
  86        int ret;
  87
  88        /*
  89         * Retrieve RC base and size from a HISI0081 device with _UID
  90         * matching our segment.
  91         */
  92        res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
  93        if (!res)
  94                return -ENOMEM;
  95
  96        ret = acpi_get_rc_resources(dev, "HISI0081", root->segment, res);
  97        if (ret) {
  98                dev_err(dev, "can't get rc base address\n");
  99                return -ENOMEM;
 100        }
 101
 102        reg_base = devm_pci_remap_cfgspace(dev, res->start, resource_size(res));
 103        if (!reg_base)
 104                return -ENOMEM;
 105
 106        cfg->priv = reg_base;
 107        return 0;
 108}
 109
 110struct pci_ecam_ops hisi_pcie_ops = {
 111        .bus_shift    = 20,
 112        .init         =  hisi_pcie_init,
 113        .pci_ops      = {
 114                .map_bus    = hisi_pcie_map_bus,
 115                .read       = hisi_pcie_rd_conf,
 116                .write      = hisi_pcie_wr_conf,
 117        }
 118};
 119
 120#endif
 121
 122#ifdef CONFIG_PCI_HISI
 123
 124#include "pcie-designware.h"
 125
 126#define PCIE_SUBCTRL_SYS_STATE4_REG             0x6818
 127#define PCIE_HIP06_CTRL_OFF                     0x1000
 128#define PCIE_SYS_STATE4                         (PCIE_HIP06_CTRL_OFF + 0x31c)
 129#define PCIE_LTSSM_LINKUP_STATE                 0x11
 130#define PCIE_LTSSM_STATE_MASK                   0x3F
 131
 132#define to_hisi_pcie(x) dev_get_drvdata((x)->dev)
 133
 134struct hisi_pcie;
 135
 136struct pcie_soc_ops {
 137        int (*hisi_pcie_link_up)(struct hisi_pcie *hisi_pcie);
 138};
 139
 140struct hisi_pcie {
 141        struct dw_pcie *pci;
 142        struct regmap *subctrl;
 143        u32 port_id;
 144        const struct pcie_soc_ops *soc_ops;
 145};
 146
 147/* HipXX PCIe host only supports 32-bit config access */
 148static int hisi_pcie_cfg_read(struct pcie_port *pp, int where, int size,
 149                              u32 *val)
 150{
 151        u32 reg;
 152        u32 reg_val;
 153        void *walker = &reg_val;
 154        struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 155
 156        walker += (where & 0x3);
 157        reg = where & ~0x3;
 158        reg_val = dw_pcie_readl_dbi(pci, reg);
 159
 160        if (size == 1)
 161                *val = *(u8 __force *) walker;
 162        else if (size == 2)
 163                *val = *(u16 __force *) walker;
 164        else if (size == 4)
 165                *val = reg_val;
 166        else
 167                return PCIBIOS_BAD_REGISTER_NUMBER;
 168
 169        return PCIBIOS_SUCCESSFUL;
 170}
 171
 172/* HipXX PCIe host only supports 32-bit config access */
 173static int hisi_pcie_cfg_write(struct pcie_port *pp, int where, int  size,
 174                                u32 val)
 175{
 176        u32 reg_val;
 177        u32 reg;
 178        void *walker = &reg_val;
 179        struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 180
 181        walker += (where & 0x3);
 182        reg = where & ~0x3;
 183        if (size == 4)
 184                dw_pcie_writel_dbi(pci, reg, val);
 185        else if (size == 2) {
 186                reg_val = dw_pcie_readl_dbi(pci, reg);
 187                *(u16 __force *) walker = val;
 188                dw_pcie_writel_dbi(pci, reg, reg_val);
 189        } else if (size == 1) {
 190                reg_val = dw_pcie_readl_dbi(pci, reg);
 191                *(u8 __force *) walker = val;
 192                dw_pcie_writel_dbi(pci, reg, reg_val);
 193        } else
 194                return PCIBIOS_BAD_REGISTER_NUMBER;
 195
 196        return PCIBIOS_SUCCESSFUL;
 197}
 198
 199static int hisi_pcie_link_up_hip05(struct hisi_pcie *hisi_pcie)
 200{
 201        u32 val;
 202
 203        regmap_read(hisi_pcie->subctrl, PCIE_SUBCTRL_SYS_STATE4_REG +
 204                    0x100 * hisi_pcie->port_id, &val);
 205
 206        return ((val & PCIE_LTSSM_STATE_MASK) == PCIE_LTSSM_LINKUP_STATE);
 207}
 208
 209static int hisi_pcie_link_up_hip06(struct hisi_pcie *hisi_pcie)
 210{
 211        struct dw_pcie *pci = hisi_pcie->pci;
 212        u32 val;
 213
 214        val = dw_pcie_readl_dbi(pci, PCIE_SYS_STATE4);
 215
 216        return ((val & PCIE_LTSSM_STATE_MASK) == PCIE_LTSSM_LINKUP_STATE);
 217}
 218
 219static int hisi_pcie_link_up(struct dw_pcie *pci)
 220{
 221        struct hisi_pcie *hisi_pcie = to_hisi_pcie(pci);
 222
 223        return hisi_pcie->soc_ops->hisi_pcie_link_up(hisi_pcie);
 224}
 225
 226static struct dw_pcie_host_ops hisi_pcie_host_ops = {
 227        .rd_own_conf = hisi_pcie_cfg_read,
 228        .wr_own_conf = hisi_pcie_cfg_write,
 229};
 230
 231static int hisi_add_pcie_port(struct hisi_pcie *hisi_pcie,
 232                              struct platform_device *pdev)
 233{
 234        struct dw_pcie *pci = hisi_pcie->pci;
 235        struct pcie_port *pp = &pci->pp;
 236        struct device *dev = &pdev->dev;
 237        int ret;
 238        u32 port_id;
 239
 240        if (of_property_read_u32(dev->of_node, "port-id", &port_id)) {
 241                dev_err(dev, "failed to read port-id\n");
 242                return -EINVAL;
 243        }
 244        if (port_id > 3) {
 245                dev_err(dev, "Invalid port-id: %d\n", port_id);
 246                return -EINVAL;
 247        }
 248        hisi_pcie->port_id = port_id;
 249
 250        pp->ops = &hisi_pcie_host_ops;
 251
 252        ret = dw_pcie_host_init(pp);
 253        if (ret) {
 254                dev_err(dev, "failed to initialize host\n");
 255                return ret;
 256        }
 257
 258        return 0;
 259}
 260
 261static const struct dw_pcie_ops dw_pcie_ops = {
 262        .link_up = hisi_pcie_link_up,
 263};
 264
 265static int hisi_pcie_probe(struct platform_device *pdev)
 266{
 267        struct device *dev = &pdev->dev;
 268        struct dw_pcie *pci;
 269        struct hisi_pcie *hisi_pcie;
 270        struct resource *reg;
 271        struct device_driver *driver;
 272        int ret;
 273
 274        hisi_pcie = devm_kzalloc(dev, sizeof(*hisi_pcie), GFP_KERNEL);
 275        if (!hisi_pcie)
 276                return -ENOMEM;
 277
 278        pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
 279        if (!pci)
 280                return -ENOMEM;
 281
 282        pci->dev = dev;
 283        pci->ops = &dw_pcie_ops;
 284
 285        driver = dev->driver;
 286
 287        hisi_pcie->pci = pci;
 288
 289        hisi_pcie->soc_ops = of_device_get_match_data(dev);
 290
 291        hisi_pcie->subctrl =
 292            syscon_regmap_lookup_by_compatible("hisilicon,pcie-sas-subctrl");
 293        if (IS_ERR(hisi_pcie->subctrl)) {
 294                dev_err(dev, "cannot get subctrl base\n");
 295                return PTR_ERR(hisi_pcie->subctrl);
 296        }
 297
 298        reg = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rc_dbi");
 299        pci->dbi_base = devm_pci_remap_cfg_resource(dev, reg);
 300        if (IS_ERR(pci->dbi_base))
 301                return PTR_ERR(pci->dbi_base);
 302        platform_set_drvdata(pdev, hisi_pcie);
 303
 304        ret = hisi_add_pcie_port(hisi_pcie, pdev);
 305        if (ret)
 306                return ret;
 307
 308        return 0;
 309}
 310
 311static struct pcie_soc_ops hip05_ops = {
 312                &hisi_pcie_link_up_hip05
 313};
 314
 315static struct pcie_soc_ops hip06_ops = {
 316                &hisi_pcie_link_up_hip06
 317};
 318
 319static const struct of_device_id hisi_pcie_of_match[] = {
 320        {
 321                        .compatible = "hisilicon,hip05-pcie",
 322                        .data       = (void *) &hip05_ops,
 323        },
 324        {
 325                        .compatible = "hisilicon,hip06-pcie",
 326                        .data       = (void *) &hip06_ops,
 327        },
 328        {},
 329};
 330
 331static struct platform_driver hisi_pcie_driver = {
 332        .probe  = hisi_pcie_probe,
 333        .driver = {
 334                   .name = "hisi-pcie",
 335                   .of_match_table = hisi_pcie_of_match,
 336                   .suppress_bind_attrs = true,
 337        },
 338};
 339builtin_platform_driver(hisi_pcie_driver);
 340
 341static int hisi_pcie_almost_ecam_probe(struct platform_device *pdev)
 342{
 343        struct device *dev = &pdev->dev;
 344        struct pci_ecam_ops *ops;
 345
 346        ops = (struct pci_ecam_ops *)of_device_get_match_data(dev);
 347        return pci_host_common_probe(pdev, ops);
 348}
 349
 350static int hisi_pcie_platform_init(struct pci_config_window *cfg)
 351{
 352        struct device *dev = cfg->parent;
 353        struct platform_device *pdev = to_platform_device(dev);
 354        struct resource *res;
 355        void __iomem *reg_base;
 356
 357        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 358        if (!res) {
 359                dev_err(dev, "missing \"reg[1]\"property\n");
 360                return -EINVAL;
 361        }
 362
 363        reg_base = devm_pci_remap_cfgspace(dev, res->start, resource_size(res));
 364        if (!reg_base)
 365                return -ENOMEM;
 366
 367        cfg->priv = reg_base;
 368        return 0;
 369}
 370
 371struct pci_ecam_ops hisi_pcie_platform_ops = {
 372        .bus_shift    = 20,
 373        .init         =  hisi_pcie_platform_init,
 374        .pci_ops      = {
 375                .map_bus    = hisi_pcie_map_bus,
 376                .read       = hisi_pcie_rd_conf,
 377                .write      = hisi_pcie_wr_conf,
 378        }
 379};
 380
 381static const struct of_device_id hisi_pcie_almost_ecam_of_match[] = {
 382        {
 383                .compatible =  "hisilicon,hip06-pcie-ecam",
 384                .data       = (void *) &hisi_pcie_platform_ops,
 385        },
 386        {
 387                .compatible =  "hisilicon,hip07-pcie-ecam",
 388                .data       = (void *) &hisi_pcie_platform_ops,
 389        },
 390        {},
 391};
 392
 393static struct platform_driver hisi_pcie_almost_ecam_driver = {
 394        .probe  = hisi_pcie_almost_ecam_probe,
 395        .driver = {
 396                   .name = "hisi-pcie-almost-ecam",
 397                   .of_match_table = hisi_pcie_almost_ecam_of_match,
 398                   .suppress_bind_attrs = true,
 399        },
 400};
 401builtin_platform_driver(hisi_pcie_almost_ecam_driver);
 402
 403#endif
 404#endif
 405