root/drivers/pci/controller/dwc/pcie-hisi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hisi_pcie_rd_conf
  2. hisi_pcie_wr_conf
  3. hisi_pcie_map_bus
  4. hisi_pcie_init
  5. hisi_pcie_cfg_read
  6. hisi_pcie_cfg_write
  7. hisi_pcie_link_up_hip05
  8. hisi_pcie_link_up_hip06
  9. hisi_pcie_link_up
  10. hisi_add_pcie_port
  11. hisi_pcie_probe
  12. hisi_pcie_almost_ecam_probe
  13. hisi_pcie_platform_init

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

/* [<][>][^][v][top][bottom][index][help] */