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 24 struct dw_plat_pcie { 25 struct dw_pcie *pci; 26 struct regmap *regmap; 27 enum dw_pcie_device_mode mode; 28 }; 29 30 struct dw_plat_pcie_of_data { 31 enum dw_pcie_device_mode mode; 32 }; 33 34 static const struct of_device_id dw_plat_pcie_of_match[]; 35 36 static 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 47 static void dw_plat_set_num_vectors(struct pcie_port *pp) 48 { 49 pp->num_vectors = MAX_MSI_IRQS; 50 } 51 52 static 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 57 static int dw_plat_pcie_establish_link(struct dw_pcie *pci) 58 { 59 return 0; 60 } 61 62 static const struct dw_pcie_ops dw_pcie_ops = { 63 .start_link = dw_plat_pcie_establish_link, 64 }; 65 66 static 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 75 static 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 95 static const struct pci_epc_features dw_plat_pcie_epc_features = { 96 .linkup_notifier = false, 97 .msi_capable = true, 98 .msix_capable = true, 99 }; 100 101 static const struct pci_epc_features* 102 dw_plat_pcie_get_features(struct dw_pcie_ep *ep) 103 { 104 return &dw_plat_pcie_epc_features; 105 } 106 107 static 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 113 static 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 142 static 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 173 static 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 239 static const struct dw_plat_pcie_of_data dw_plat_pcie_rc_of_data = { 240 .mode = DW_PCIE_RC_TYPE, 241 }; 242 243 static const struct dw_plat_pcie_of_data dw_plat_pcie_ep_of_data = { 244 .mode = DW_PCIE_EP_TYPE, 245 }; 246 247 static 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 259 static 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 }; 267 builtin_platform_driver(dw_plat_pcie_driver); 268