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 enum pci_barno bar; 74 75 for (bar = BAR_0; bar <= BAR_5; bar++) 76 dw_pcie_ep_reset_bar(pci, bar); 77 } 78 79 static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, 80 enum pci_epc_irq_type type, 81 u8 interrupt_num) 82 { 83 struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 84 85 switch (type) { 86 case PCI_EPC_IRQ_LEGACY: 87 dev_err(pci->dev, "EP cannot trigger legacy IRQs\n"); 88 return -EINVAL; 89 case PCI_EPC_IRQ_MSI: 90 return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num); 91 default: 92 dev_err(pci->dev, "UNKNOWN IRQ type\n"); 93 } 94 95 return 0; 96 } 97 98 static struct dw_pcie_ep_ops pcie_ep_ops = { 99 .ep_init = dw_plat_pcie_ep_init, 100 .raise_irq = dw_plat_pcie_ep_raise_irq, 101 }; 102 103 static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie, 104 struct platform_device *pdev) 105 { 106 struct dw_pcie *pci = dw_plat_pcie->pci; 107 struct pcie_port *pp = &pci->pp; 108 struct device *dev = &pdev->dev; 109 int ret; 110 111 pp->irq = platform_get_irq(pdev, 1); 112 if (pp->irq < 0) 113 return pp->irq; 114 115 if (IS_ENABLED(CONFIG_PCI_MSI)) { 116 pp->msi_irq = platform_get_irq(pdev, 0); 117 if (pp->msi_irq < 0) 118 return pp->msi_irq; 119 } 120 121 pp->root_bus_nr = -1; 122 pp->ops = &dw_plat_pcie_host_ops; 123 124 ret = dw_pcie_host_init(pp); 125 if (ret) { 126 dev_err(dev, "Failed to initialize host\n"); 127 return ret; 128 } 129 130 return 0; 131 } 132 133 static int dw_plat_add_pcie_ep(struct dw_plat_pcie *dw_plat_pcie, 134 struct platform_device *pdev) 135 { 136 int ret; 137 struct dw_pcie_ep *ep; 138 struct resource *res; 139 struct device *dev = &pdev->dev; 140 struct dw_pcie *pci = dw_plat_pcie->pci; 141 142 ep = &pci->ep; 143 ep->ops = &pcie_ep_ops; 144 145 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi2"); 146 pci->dbi_base2 = devm_ioremap_resource(dev, res); 147 if (IS_ERR(pci->dbi_base2)) 148 return PTR_ERR(pci->dbi_base2); 149 150 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); 151 if (!res) 152 return -EINVAL; 153 154 ep->phys_base = res->start; 155 ep->addr_size = resource_size(res); 156 157 ret = dw_pcie_ep_init(ep); 158 if (ret) { 159 dev_err(dev, "Failed to initialize endpoint\n"); 160 return ret; 161 } 162 return 0; 163 } 164 165 static int dw_plat_pcie_probe(struct platform_device *pdev) 166 { 167 struct device *dev = &pdev->dev; 168 struct dw_plat_pcie *dw_plat_pcie; 169 struct dw_pcie *pci; 170 struct resource *res; /* Resource from DT */ 171 int ret; 172 const struct of_device_id *match; 173 const struct dw_plat_pcie_of_data *data; 174 enum dw_pcie_device_mode mode; 175 176 match = of_match_device(dw_plat_pcie_of_match, dev); 177 if (!match) 178 return -EINVAL; 179 180 data = (struct dw_plat_pcie_of_data *)match->data; 181 mode = (enum dw_pcie_device_mode)data->mode; 182 183 dw_plat_pcie = devm_kzalloc(dev, sizeof(*dw_plat_pcie), GFP_KERNEL); 184 if (!dw_plat_pcie) 185 return -ENOMEM; 186 187 pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL); 188 if (!pci) 189 return -ENOMEM; 190 191 pci->dev = dev; 192 pci->ops = &dw_pcie_ops; 193 194 dw_plat_pcie->pci = pci; 195 dw_plat_pcie->mode = mode; 196 197 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); 198 if (!res) 199 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 200 201 pci->dbi_base = devm_ioremap_resource(dev, res); 202 if (IS_ERR(pci->dbi_base)) 203 return PTR_ERR(pci->dbi_base); 204 205 platform_set_drvdata(pdev, dw_plat_pcie); 206 207 switch (dw_plat_pcie->mode) { 208 case DW_PCIE_RC_TYPE: 209 if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_HOST)) 210 return -ENODEV; 211 212 ret = dw_plat_add_pcie_port(dw_plat_pcie, pdev); 213 if (ret < 0) 214 return ret; 215 break; 216 case DW_PCIE_EP_TYPE: 217 if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_EP)) 218 return -ENODEV; 219 220 ret = dw_plat_add_pcie_ep(dw_plat_pcie, pdev); 221 if (ret < 0) 222 return ret; 223 break; 224 default: 225 dev_err(dev, "INVALID device type %d\n", dw_plat_pcie->mode); 226 } 227 228 return 0; 229 } 230 231 static const struct dw_plat_pcie_of_data dw_plat_pcie_rc_of_data = { 232 .mode = DW_PCIE_RC_TYPE, 233 }; 234 235 static const struct dw_plat_pcie_of_data dw_plat_pcie_ep_of_data = { 236 .mode = DW_PCIE_EP_TYPE, 237 }; 238 239 static const struct of_device_id dw_plat_pcie_of_match[] = { 240 { 241 .compatible = "snps,dw-pcie", 242 .data = &dw_plat_pcie_rc_of_data, 243 }, 244 { 245 .compatible = "snps,dw-pcie-ep", 246 .data = &dw_plat_pcie_ep_of_data, 247 }, 248 {}, 249 }; 250 251 static struct platform_driver dw_plat_pcie_driver = { 252 .driver = { 253 .name = "dw-pcie", 254 .of_match_table = dw_plat_pcie_of_match, 255 .suppress_bind_attrs = true, 256 }, 257 .probe = dw_plat_pcie_probe, 258 }; 259 builtin_platform_driver(dw_plat_pcie_driver); 260