1// SPDX-License-Identifier: GPL-2.0 2/* 3 * PCIe RC driver for Synopsys DesignWare Core 4 * 5 * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) 6 * 7 * Authors: Joao Pinto <Joao.Pinto@synopsys.com> 8 */ 9#include <linux/clk.h> 10#include <linux/delay.h> 11#include <linux/gpio.h> 12#include <linux/interrupt.h> 13#include <linux/kernel.h> 14#include <linux/init.h> 15#include <linux/of_device.h> 16#include <linux/pci.h> 17#include <linux/platform_device.h> 18#include <linux/resource.h> 19#include <linux/types.h> 20#include <linux/regmap.h> 21 22#include "pcie-designware.h" 23 24struct dw_plat_pcie { 25 struct dw_pcie *pci; 26 struct regmap *regmap; 27 enum dw_pcie_device_mode mode; 28}; 29 30struct dw_plat_pcie_of_data { 31 enum dw_pcie_device_mode mode; 32}; 33 34static const struct of_device_id dw_plat_pcie_of_match[]; 35 36static int dw_plat_pcie_host_init(struct pcie_port *pp) 37{ 38 struct dw_pcie *pci = to_dw_pcie_from_pp(pp); 39 40 dw_pcie_setup_rc(pp); 41 dw_pcie_wait_for_link(pci); 42 dw_pcie_msi_init(pp); 43 44 return 0; 45} 46 47static void dw_plat_set_num_vectors(struct pcie_port *pp) 48{ 49 pp->num_vectors = MAX_MSI_IRQS; 50} 51 52static const struct dw_pcie_host_ops dw_plat_pcie_host_ops = { 53 .host_init = dw_plat_pcie_host_init, 54 .set_num_vectors = dw_plat_set_num_vectors, 55}; 56 57static int dw_plat_pcie_establish_link(struct dw_pcie *pci) 58{ 59 return 0; 60} 61 62static const struct dw_pcie_ops dw_pcie_ops = { 63 .start_link = dw_plat_pcie_establish_link, 64}; 65 66static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep) 67{ 68 struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 69 enum pci_barno bar; 70 71 for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) 72 dw_pcie_ep_reset_bar(pci, bar); 73} 74 75static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, 76 enum pci_epc_irq_type type, 77 u16 interrupt_num) 78{ 79 struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 80 81 switch (type) { 82 case PCI_EPC_IRQ_LEGACY: 83 return dw_pcie_ep_raise_legacy_irq(ep, func_no); 84 case PCI_EPC_IRQ_MSI: 85 return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num); 86 case PCI_EPC_IRQ_MSIX: 87 return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num); 88 default: 89 dev_err(pci->dev, "UNKNOWN IRQ type\n"); 90 } 91 92 return 0; 93} 94 95static const struct pci_epc_features dw_plat_pcie_epc_features = { 96 .linkup_notifier = false, 97 .msi_capable = true, 98 .msix_capable = true, 99}; 100 101static const struct pci_epc_features* 102dw_plat_pcie_get_features(struct dw_pcie_ep *ep) 103{ 104 return &dw_plat_pcie_epc_features; 105} 106 107static const struct dw_pcie_ep_ops pcie_ep_ops = { 108 .ep_init = dw_plat_pcie_ep_init, 109 .raise_irq = dw_plat_pcie_ep_raise_irq, 110 .get_features = dw_plat_pcie_get_features, 111}; 112 113static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie, 114 struct platform_device *pdev) 115{ 116 struct dw_pcie *pci = dw_plat_pcie->pci; 117 struct pcie_port *pp = &pci->pp; 118 struct device *dev = &pdev->dev; 119 int ret; 120 121 pp->irq = platform_get_irq(pdev, 1); 122 if (pp->irq < 0) 123 return pp->irq; 124 125 if (IS_ENABLED(CONFIG_PCI_MSI)) { 126 pp->msi_irq = platform_get_irq(pdev, 0); 127 if (pp->msi_irq < 0) 128 return pp->msi_irq; 129 } 130 131 pp->ops = &dw_plat_pcie_host_ops; 132 133 ret = dw_pcie_host_init(pp); 134 if (ret) { 135 dev_err(dev, "Failed to initialize host\n"); 136 return ret; 137 } 138 139 return 0; 140} 141 142static int dw_plat_add_pcie_ep(struct dw_plat_pcie *dw_plat_pcie, 143 struct platform_device *pdev) 144{ 145 int ret; 146 struct dw_pcie_ep *ep; 147 struct resource *res; 148 struct device *dev = &pdev->dev; 149 struct dw_pcie *pci = dw_plat_pcie->pci; 150 151 ep = &pci->ep; 152 ep->ops = &pcie_ep_ops; 153 154 pci->dbi_base2 = devm_platform_ioremap_resource_byname(pdev, "dbi2"); 155 if (IS_ERR(pci->dbi_base2)) 156 return PTR_ERR(pci->dbi_base2); 157 158 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); 159 if (!res) 160 return -EINVAL; 161 162 ep->phys_base = res->start; 163 ep->addr_size = resource_size(res); 164 165 ret = dw_pcie_ep_init(ep); 166 if (ret) { 167 dev_err(dev, "Failed to initialize endpoint\n"); 168 return ret; 169 } 170 return 0; 171} 172 173static int dw_plat_pcie_probe(struct platform_device *pdev) 174{ 175 struct device *dev = &pdev->dev; 176 struct dw_plat_pcie *dw_plat_pcie; 177 struct dw_pcie *pci; 178 struct resource *res; /* Resource from DT */ 179 int ret; 180 const struct of_device_id *match; 181 const struct dw_plat_pcie_of_data *data; 182 enum dw_pcie_device_mode mode; 183 184 match = of_match_device(dw_plat_pcie_of_match, dev); 185 if (!match) 186 return -EINVAL; 187 188 data = (struct dw_plat_pcie_of_data *)match->data; 189 mode = (enum dw_pcie_device_mode)data->mode; 190 191 dw_plat_pcie = devm_kzalloc(dev, sizeof(*dw_plat_pcie), GFP_KERNEL); 192 if (!dw_plat_pcie) 193 return -ENOMEM; 194 195 pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL); 196 if (!pci) 197 return -ENOMEM; 198 199 pci->dev = dev; 200 pci->ops = &dw_pcie_ops; 201 202 dw_plat_pcie->pci = pci; 203 dw_plat_pcie->mode = mode; 204 205 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); 206 if (!res) 207 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 208 209 pci->dbi_base = devm_ioremap_resource(dev, res); 210 if (IS_ERR(pci->dbi_base)) 211 return PTR_ERR(pci->dbi_base); 212 213 platform_set_drvdata(pdev, dw_plat_pcie); 214 215 switch (dw_plat_pcie->mode) { 216 case DW_PCIE_RC_TYPE: 217 if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_HOST)) 218 return -ENODEV; 219 220 ret = dw_plat_add_pcie_port(dw_plat_pcie, pdev); 221 if (ret < 0) 222 return ret; 223 break; 224 case DW_PCIE_EP_TYPE: 225 if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_EP)) 226 return -ENODEV; 227 228 ret = dw_plat_add_pcie_ep(dw_plat_pcie, pdev); 229 if (ret < 0) 230 return ret; 231 break; 232 default: 233 dev_err(dev, "INVALID device type %d\n", dw_plat_pcie->mode); 234 } 235 236 return 0; 237} 238 239static const struct dw_plat_pcie_of_data dw_plat_pcie_rc_of_data = { 240 .mode = DW_PCIE_RC_TYPE, 241}; 242 243static const struct dw_plat_pcie_of_data dw_plat_pcie_ep_of_data = { 244 .mode = DW_PCIE_EP_TYPE, 245}; 246 247static const struct of_device_id dw_plat_pcie_of_match[] = { 248 { 249 .compatible = "snps,dw-pcie", 250 .data = &dw_plat_pcie_rc_of_data, 251 }, 252 { 253 .compatible = "snps,dw-pcie-ep", 254 .data = &dw_plat_pcie_ep_of_data, 255 }, 256 {}, 257}; 258 259static struct platform_driver dw_plat_pcie_driver = { 260 .driver = { 261 .name = "dw-pcie", 262 .of_match_table = dw_plat_pcie_of_match, 263 .suppress_bind_attrs = true, 264 }, 265 .probe = dw_plat_pcie_probe, 266}; 267builtin_platform_driver(dw_plat_pcie_driver); 268