]> Git Repo - linux.git/blob - drivers/pci/controller/dwc/pcie-designware-plat.c
Merge tag 'drm-fixes-2018-06-22' of git://anongit.freedesktop.org/drm/drm
[linux.git] / drivers / pci / controller / dwc / pcie-designware-plat.c
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 <[email protected]>
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/of_gpio.h>
17 #include <linux/pci.h>
18 #include <linux/platform_device.h>
19 #include <linux/resource.h>
20 #include <linux/signal.h>
21 #include <linux/types.h>
22 #include <linux/regmap.h>
23
24 #include "pcie-designware.h"
25
26 struct dw_plat_pcie {
27         struct dw_pcie                  *pci;
28         struct regmap                   *regmap;
29         enum dw_pcie_device_mode        mode;
30 };
31
32 struct dw_plat_pcie_of_data {
33         enum dw_pcie_device_mode        mode;
34 };
35
36 static const struct of_device_id dw_plat_pcie_of_match[];
37
38 static int dw_plat_pcie_host_init(struct pcie_port *pp)
39 {
40         struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
41
42         dw_pcie_setup_rc(pp);
43         dw_pcie_wait_for_link(pci);
44
45         if (IS_ENABLED(CONFIG_PCI_MSI))
46                 dw_pcie_msi_init(pp);
47
48         return 0;
49 }
50
51 static void dw_plat_set_num_vectors(struct pcie_port *pp)
52 {
53         pp->num_vectors = MAX_MSI_IRQS;
54 }
55
56 static const struct dw_pcie_host_ops dw_plat_pcie_host_ops = {
57         .host_init = dw_plat_pcie_host_init,
58         .set_num_vectors = dw_plat_set_num_vectors,
59 };
60
61 static int dw_plat_pcie_establish_link(struct dw_pcie *pci)
62 {
63         return 0;
64 }
65
66 static const struct dw_pcie_ops dw_pcie_ops = {
67         .start_link = dw_plat_pcie_establish_link,
68 };
69
70 static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep)
71 {
72         struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
73         enum pci_barno bar;
74
75         for (bar = BAR_0; bar <= BAR_5; bar++)
76                 dw_pcie_ep_reset_bar(pci, bar);
77 }
78
79 static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
80                                      enum pci_epc_irq_type type,
81                                      u8 interrupt_num)
82 {
83         struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
84
85         switch (type) {
86         case PCI_EPC_IRQ_LEGACY:
87                 dev_err(pci->dev, "EP cannot trigger legacy IRQs\n");
88                 return -EINVAL;
89         case PCI_EPC_IRQ_MSI:
90                 return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
91         default:
92                 dev_err(pci->dev, "UNKNOWN IRQ type\n");
93         }
94
95         return 0;
96 }
97
98 static struct dw_pcie_ep_ops pcie_ep_ops = {
99         .ep_init = dw_plat_pcie_ep_init,
100         .raise_irq = dw_plat_pcie_ep_raise_irq,
101 };
102
103 static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie,
104                                  struct platform_device *pdev)
105 {
106         struct dw_pcie *pci = dw_plat_pcie->pci;
107         struct pcie_port *pp = &pci->pp;
108         struct device *dev = &pdev->dev;
109         int ret;
110
111         pp->irq = platform_get_irq(pdev, 1);
112         if (pp->irq < 0)
113                 return pp->irq;
114
115         if (IS_ENABLED(CONFIG_PCI_MSI)) {
116                 pp->msi_irq = platform_get_irq(pdev, 0);
117                 if (pp->msi_irq < 0)
118                         return pp->msi_irq;
119         }
120
121         pp->root_bus_nr = -1;
122         pp->ops = &dw_plat_pcie_host_ops;
123
124         ret = dw_pcie_host_init(pp);
125         if (ret) {
126                 dev_err(dev, "Failed to initialize host\n");
127                 return ret;
128         }
129
130         return 0;
131 }
132
133 static int dw_plat_add_pcie_ep(struct dw_plat_pcie *dw_plat_pcie,
134                                struct platform_device *pdev)
135 {
136         int ret;
137         struct dw_pcie_ep *ep;
138         struct resource *res;
139         struct device *dev = &pdev->dev;
140         struct dw_pcie *pci = dw_plat_pcie->pci;
141
142         ep = &pci->ep;
143         ep->ops = &pcie_ep_ops;
144
145         res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi2");
146         pci->dbi_base2 = devm_ioremap_resource(dev, res);
147         if (IS_ERR(pci->dbi_base2))
148                 return PTR_ERR(pci->dbi_base2);
149
150         res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
151         if (!res)
152                 return -EINVAL;
153
154         ep->phys_base = res->start;
155         ep->addr_size = resource_size(res);
156
157         ret = dw_pcie_ep_init(ep);
158         if (ret) {
159                 dev_err(dev, "Failed to initialize endpoint\n");
160                 return ret;
161         }
162         return 0;
163 }
164
165 static int dw_plat_pcie_probe(struct platform_device *pdev)
166 {
167         struct device *dev = &pdev->dev;
168         struct dw_plat_pcie *dw_plat_pcie;
169         struct dw_pcie *pci;
170         struct resource *res;  /* Resource from DT */
171         int ret;
172         const struct of_device_id *match;
173         const struct dw_plat_pcie_of_data *data;
174         enum dw_pcie_device_mode mode;
175
176         match = of_match_device(dw_plat_pcie_of_match, dev);
177         if (!match)
178                 return -EINVAL;
179
180         data = (struct dw_plat_pcie_of_data *)match->data;
181         mode = (enum dw_pcie_device_mode)data->mode;
182
183         dw_plat_pcie = devm_kzalloc(dev, sizeof(*dw_plat_pcie), GFP_KERNEL);
184         if (!dw_plat_pcie)
185                 return -ENOMEM;
186
187         pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
188         if (!pci)
189                 return -ENOMEM;
190
191         pci->dev = dev;
192         pci->ops = &dw_pcie_ops;
193
194         dw_plat_pcie->pci = pci;
195         dw_plat_pcie->mode = mode;
196
197         res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
198         if (!res)
199                 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
200
201         pci->dbi_base = devm_ioremap_resource(dev, res);
202         if (IS_ERR(pci->dbi_base))
203                 return PTR_ERR(pci->dbi_base);
204
205         platform_set_drvdata(pdev, dw_plat_pcie);
206
207         switch (dw_plat_pcie->mode) {
208         case DW_PCIE_RC_TYPE:
209                 if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_HOST))
210                         return -ENODEV;
211
212                 ret = dw_plat_add_pcie_port(dw_plat_pcie, pdev);
213                 if (ret < 0)
214                         return ret;
215                 break;
216         case DW_PCIE_EP_TYPE:
217                 if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_EP))
218                         return -ENODEV;
219
220                 ret = dw_plat_add_pcie_ep(dw_plat_pcie, pdev);
221                 if (ret < 0)
222                         return ret;
223                 break;
224         default:
225                 dev_err(dev, "INVALID device type %d\n", dw_plat_pcie->mode);
226         }
227
228         return 0;
229 }
230
231 static const struct dw_plat_pcie_of_data dw_plat_pcie_rc_of_data = {
232         .mode = DW_PCIE_RC_TYPE,
233 };
234
235 static const struct dw_plat_pcie_of_data dw_plat_pcie_ep_of_data = {
236         .mode = DW_PCIE_EP_TYPE,
237 };
238
239 static const struct of_device_id dw_plat_pcie_of_match[] = {
240         {
241                 .compatible = "snps,dw-pcie",
242                 .data = &dw_plat_pcie_rc_of_data,
243         },
244         {
245                 .compatible = "snps,dw-pcie-ep",
246                 .data = &dw_plat_pcie_ep_of_data,
247         },
248         {},
249 };
250
251 static struct platform_driver dw_plat_pcie_driver = {
252         .driver = {
253                 .name   = "dw-pcie",
254                 .of_match_table = dw_plat_pcie_of_match,
255                 .suppress_bind_attrs = true,
256         },
257         .probe = dw_plat_pcie_probe,
258 };
259 builtin_platform_driver(dw_plat_pcie_driver);
This page took 0.047451 seconds and 4 git commands to generate.