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