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