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 const struct dw_pcie_host_ops dw_plat_pcie_host_ops = { 37 }; 38 39 static int dw_plat_pcie_establish_link(struct dw_pcie *pci) 40 { 41 return 0; 42 } 43 44 static const struct dw_pcie_ops dw_pcie_ops = { 45 .start_link = dw_plat_pcie_establish_link, 46 }; 47 48 static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep) 49 { 50 struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 51 enum pci_barno bar; 52 53 for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) 54 dw_pcie_ep_reset_bar(pci, bar); 55 } 56 57 static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, 58 enum pci_epc_irq_type type, 59 u16 interrupt_num) 60 { 61 struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 62 63 switch (type) { 64 case PCI_EPC_IRQ_LEGACY: 65 return dw_pcie_ep_raise_legacy_irq(ep, func_no); 66 case PCI_EPC_IRQ_MSI: 67 return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num); 68 case PCI_EPC_IRQ_MSIX: 69 return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num); 70 default: 71 dev_err(pci->dev, "UNKNOWN IRQ type\n"); 72 } 73 74 return 0; 75 } 76 77 static const struct pci_epc_features dw_plat_pcie_epc_features = { 78 .linkup_notifier = false, 79 .msi_capable = true, 80 .msix_capable = true, 81 }; 82 83 static const struct pci_epc_features* 84 dw_plat_pcie_get_features(struct dw_pcie_ep *ep) 85 { 86 return &dw_plat_pcie_epc_features; 87 } 88 89 static const struct dw_pcie_ep_ops pcie_ep_ops = { 90 .ep_init = dw_plat_pcie_ep_init, 91 .raise_irq = dw_plat_pcie_ep_raise_irq, 92 .get_features = dw_plat_pcie_get_features, 93 }; 94 95 static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie, 96 struct platform_device *pdev) 97 { 98 struct dw_pcie *pci = dw_plat_pcie->pci; 99 struct pcie_port *pp = &pci->pp; 100 struct device *dev = &pdev->dev; 101 int ret; 102 103 pp->irq = platform_get_irq(pdev, 1); 104 if (pp->irq < 0) 105 return pp->irq; 106 107 pp->num_vectors = MAX_MSI_IRQS; 108 pp->ops = &dw_plat_pcie_host_ops; 109 110 ret = dw_pcie_host_init(pp); 111 if (ret) { 112 dev_err(dev, "Failed to initialize host\n"); 113 return ret; 114 } 115 116 return 0; 117 } 118 119 static int dw_plat_pcie_probe(struct platform_device *pdev) 120 { 121 struct device *dev = &pdev->dev; 122 struct dw_plat_pcie *dw_plat_pcie; 123 struct dw_pcie *pci; 124 int ret; 125 const struct of_device_id *match; 126 const struct dw_plat_pcie_of_data *data; 127 enum dw_pcie_device_mode mode; 128 129 match = of_match_device(dw_plat_pcie_of_match, dev); 130 if (!match) 131 return -EINVAL; 132 133 data = (struct dw_plat_pcie_of_data *)match->data; 134 mode = (enum dw_pcie_device_mode)data->mode; 135 136 dw_plat_pcie = devm_kzalloc(dev, sizeof(*dw_plat_pcie), GFP_KERNEL); 137 if (!dw_plat_pcie) 138 return -ENOMEM; 139 140 pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL); 141 if (!pci) 142 return -ENOMEM; 143 144 pci->dev = dev; 145 pci->ops = &dw_pcie_ops; 146 147 dw_plat_pcie->pci = pci; 148 dw_plat_pcie->mode = mode; 149 150 platform_set_drvdata(pdev, dw_plat_pcie); 151 152 switch (dw_plat_pcie->mode) { 153 case DW_PCIE_RC_TYPE: 154 if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_HOST)) 155 return -ENODEV; 156 157 ret = dw_plat_add_pcie_port(dw_plat_pcie, pdev); 158 if (ret < 0) 159 return ret; 160 break; 161 case DW_PCIE_EP_TYPE: 162 if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_EP)) 163 return -ENODEV; 164 165 pci->ep.ops = &pcie_ep_ops; 166 return dw_pcie_ep_init(&pci->ep); 167 break; 168 default: 169 dev_err(dev, "INVALID device type %d\n", dw_plat_pcie->mode); 170 } 171 172 return 0; 173 } 174 175 static const struct dw_plat_pcie_of_data dw_plat_pcie_rc_of_data = { 176 .mode = DW_PCIE_RC_TYPE, 177 }; 178 179 static const struct dw_plat_pcie_of_data dw_plat_pcie_ep_of_data = { 180 .mode = DW_PCIE_EP_TYPE, 181 }; 182 183 static const struct of_device_id dw_plat_pcie_of_match[] = { 184 { 185 .compatible = "snps,dw-pcie", 186 .data = &dw_plat_pcie_rc_of_data, 187 }, 188 { 189 .compatible = "snps,dw-pcie-ep", 190 .data = &dw_plat_pcie_ep_of_data, 191 }, 192 {}, 193 }; 194 195 static struct platform_driver dw_plat_pcie_driver = { 196 .driver = { 197 .name = "dw-pcie", 198 .of_match_table = dw_plat_pcie_of_match, 199 .suppress_bind_attrs = true, 200 }, 201 .probe = dw_plat_pcie_probe, 202 }; 203 builtin_platform_driver(dw_plat_pcie_driver); 204