xref: /openbmc/linux/drivers/pci/controller/dwc/pcie-designware-plat.c (revision 5ed132db5ad4f58156ae9d28219396b6f764a9cb)
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