pcie-designware-plat.c (4507B)
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 24struct dw_plat_pcie { 25 struct dw_pcie *pci; 26 struct regmap *regmap; 27 enum dw_pcie_device_mode mode; 28}; 29 30struct dw_plat_pcie_of_data { 31 enum dw_pcie_device_mode mode; 32}; 33 34static const struct of_device_id dw_plat_pcie_of_match[]; 35 36static const struct dw_pcie_host_ops dw_plat_pcie_host_ops = { 37}; 38 39static int dw_plat_pcie_establish_link(struct dw_pcie *pci) 40{ 41 return 0; 42} 43 44static const struct dw_pcie_ops dw_pcie_ops = { 45 .start_link = dw_plat_pcie_establish_link, 46}; 47 48static 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 57static 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 77static const struct pci_epc_features dw_plat_pcie_epc_features = { 78 .linkup_notifier = false, 79 .msi_capable = true, 80 .msix_capable = true, 81}; 82 83static const struct pci_epc_features* 84dw_plat_pcie_get_features(struct dw_pcie_ep *ep) 85{ 86 return &dw_plat_pcie_epc_features; 87} 88 89static 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 95static 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 119static 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 dw_plat_pcie_of_data *data; 126 enum dw_pcie_device_mode mode; 127 128 data = of_device_get_match_data(dev); 129 if (!data) 130 return -EINVAL; 131 132 mode = (enum dw_pcie_device_mode)data->mode; 133 134 dw_plat_pcie = devm_kzalloc(dev, sizeof(*dw_plat_pcie), GFP_KERNEL); 135 if (!dw_plat_pcie) 136 return -ENOMEM; 137 138 pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL); 139 if (!pci) 140 return -ENOMEM; 141 142 pci->dev = dev; 143 pci->ops = &dw_pcie_ops; 144 145 dw_plat_pcie->pci = pci; 146 dw_plat_pcie->mode = mode; 147 148 platform_set_drvdata(pdev, dw_plat_pcie); 149 150 switch (dw_plat_pcie->mode) { 151 case DW_PCIE_RC_TYPE: 152 if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_HOST)) 153 return -ENODEV; 154 155 ret = dw_plat_add_pcie_port(dw_plat_pcie, pdev); 156 if (ret < 0) 157 return ret; 158 break; 159 case DW_PCIE_EP_TYPE: 160 if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_EP)) 161 return -ENODEV; 162 163 pci->ep.ops = &pcie_ep_ops; 164 return dw_pcie_ep_init(&pci->ep); 165 default: 166 dev_err(dev, "INVALID device type %d\n", dw_plat_pcie->mode); 167 } 168 169 return 0; 170} 171 172static const struct dw_plat_pcie_of_data dw_plat_pcie_rc_of_data = { 173 .mode = DW_PCIE_RC_TYPE, 174}; 175 176static const struct dw_plat_pcie_of_data dw_plat_pcie_ep_of_data = { 177 .mode = DW_PCIE_EP_TYPE, 178}; 179 180static const struct of_device_id dw_plat_pcie_of_match[] = { 181 { 182 .compatible = "snps,dw-pcie", 183 .data = &dw_plat_pcie_rc_of_data, 184 }, 185 { 186 .compatible = "snps,dw-pcie-ep", 187 .data = &dw_plat_pcie_ep_of_data, 188 }, 189 {}, 190}; 191 192static struct platform_driver dw_plat_pcie_driver = { 193 .driver = { 194 .name = "dw-pcie", 195 .of_match_table = dw_plat_pcie_of_match, 196 .suppress_bind_attrs = true, 197 }, 198 .probe = dw_plat_pcie_probe, 199}; 200builtin_platform_driver(dw_plat_pcie_driver);