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