Merge branch 'acpi-ec'
[linux-drm-fsl-dcu.git] / drivers / pci / host / pci-host-generic.c
1 /*
2  * Simple, generic PCI host controller driver targetting firmware-initialised
3  * systems and virtual machines (e.g. the PCI emulation provided by kvmtool).
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  * Copyright (C) 2014 ARM Limited
18  *
19  * Author: Will Deacon <will.deacon@arm.com>
20  */
21
22 #include <linux/kernel.h>
23 #include <linux/module.h>
24 #include <linux/of_address.h>
25 #include <linux/of_pci.h>
26 #include <linux/platform_device.h>
27
28 struct gen_pci_cfg_bus_ops {
29         u32 bus_shift;
30         void __iomem *(*map_bus)(struct pci_bus *, unsigned int, int);
31 };
32
33 struct gen_pci_cfg_windows {
34         struct resource                         res;
35         struct resource                         *bus_range;
36         void __iomem                            **win;
37
38         const struct gen_pci_cfg_bus_ops        *ops;
39 };
40
41 struct gen_pci {
42         struct pci_host_bridge                  host;
43         struct gen_pci_cfg_windows              cfg;
44         struct list_head                        resources;
45 };
46
47 static void __iomem *gen_pci_map_cfg_bus_cam(struct pci_bus *bus,
48                                              unsigned int devfn,
49                                              int where)
50 {
51         struct pci_sys_data *sys = bus->sysdata;
52         struct gen_pci *pci = sys->private_data;
53         resource_size_t idx = bus->number - pci->cfg.bus_range->start;
54
55         return pci->cfg.win[idx] + ((devfn << 8) | where);
56 }
57
58 static struct gen_pci_cfg_bus_ops gen_pci_cfg_cam_bus_ops = {
59         .bus_shift      = 16,
60         .map_bus        = gen_pci_map_cfg_bus_cam,
61 };
62
63 static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus,
64                                               unsigned int devfn,
65                                               int where)
66 {
67         struct pci_sys_data *sys = bus->sysdata;
68         struct gen_pci *pci = sys->private_data;
69         resource_size_t idx = bus->number - pci->cfg.bus_range->start;
70
71         return pci->cfg.win[idx] + ((devfn << 12) | where);
72 }
73
74 static struct gen_pci_cfg_bus_ops gen_pci_cfg_ecam_bus_ops = {
75         .bus_shift      = 20,
76         .map_bus        = gen_pci_map_cfg_bus_ecam,
77 };
78
79 static struct pci_ops gen_pci_ops = {
80         .read   = pci_generic_config_read,
81         .write  = pci_generic_config_write,
82 };
83
84 static const struct of_device_id gen_pci_of_match[] = {
85         { .compatible = "pci-host-cam-generic",
86           .data = &gen_pci_cfg_cam_bus_ops },
87
88         { .compatible = "pci-host-ecam-generic",
89           .data = &gen_pci_cfg_ecam_bus_ops },
90
91         { },
92 };
93 MODULE_DEVICE_TABLE(of, gen_pci_of_match);
94
95 static void gen_pci_release_of_pci_ranges(struct gen_pci *pci)
96 {
97         pci_free_resource_list(&pci->resources);
98 }
99
100 static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci)
101 {
102         int err, res_valid = 0;
103         struct device *dev = pci->host.dev.parent;
104         struct device_node *np = dev->of_node;
105         resource_size_t iobase;
106         struct resource_entry *win;
107
108         err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources,
109                                                &iobase);
110         if (err)
111                 return err;
112
113         resource_list_for_each_entry(win, &pci->resources) {
114                 struct resource *parent, *res = win->res;
115
116                 switch (resource_type(res)) {
117                 case IORESOURCE_IO:
118                         parent = &ioport_resource;
119                         err = pci_remap_iospace(res, iobase);
120                         if (err) {
121                                 dev_warn(dev, "error %d: failed to map resource %pR\n",
122                                          err, res);
123                                 continue;
124                         }
125                         break;
126                 case IORESOURCE_MEM:
127                         parent = &iomem_resource;
128                         res_valid |= !(res->flags & IORESOURCE_PREFETCH);
129                         break;
130                 case IORESOURCE_BUS:
131                         pci->cfg.bus_range = res;
132                 default:
133                         continue;
134                 }
135
136                 err = devm_request_resource(dev, parent, res);
137                 if (err)
138                         goto out_release_res;
139         }
140
141         if (!res_valid) {
142                 dev_err(dev, "non-prefetchable memory resource required\n");
143                 err = -EINVAL;
144                 goto out_release_res;
145         }
146
147         return 0;
148
149 out_release_res:
150         gen_pci_release_of_pci_ranges(pci);
151         return err;
152 }
153
154 static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
155 {
156         int err;
157         u8 bus_max;
158         resource_size_t busn;
159         struct resource *bus_range;
160         struct device *dev = pci->host.dev.parent;
161         struct device_node *np = dev->of_node;
162
163         err = of_address_to_resource(np, 0, &pci->cfg.res);
164         if (err) {
165                 dev_err(dev, "missing \"reg\" property\n");
166                 return err;
167         }
168
169         /* Limit the bus-range to fit within reg */
170         bus_max = pci->cfg.bus_range->start +
171                   (resource_size(&pci->cfg.res) >> pci->cfg.ops->bus_shift) - 1;
172         pci->cfg.bus_range->end = min_t(resource_size_t,
173                                         pci->cfg.bus_range->end, bus_max);
174
175         pci->cfg.win = devm_kcalloc(dev, resource_size(pci->cfg.bus_range),
176                                     sizeof(*pci->cfg.win), GFP_KERNEL);
177         if (!pci->cfg.win)
178                 return -ENOMEM;
179
180         /* Map our Configuration Space windows */
181         if (!devm_request_mem_region(dev, pci->cfg.res.start,
182                                      resource_size(&pci->cfg.res),
183                                      "Configuration Space"))
184                 return -ENOMEM;
185
186         bus_range = pci->cfg.bus_range;
187         for (busn = bus_range->start; busn <= bus_range->end; ++busn) {
188                 u32 idx = busn - bus_range->start;
189                 u32 sz = 1 << pci->cfg.ops->bus_shift;
190
191                 pci->cfg.win[idx] = devm_ioremap(dev,
192                                                  pci->cfg.res.start + busn * sz,
193                                                  sz);
194                 if (!pci->cfg.win[idx])
195                         return -ENOMEM;
196         }
197
198         return 0;
199 }
200
201 static int gen_pci_setup(int nr, struct pci_sys_data *sys)
202 {
203         struct gen_pci *pci = sys->private_data;
204         list_splice_init(&pci->resources, &sys->resources);
205         return 1;
206 }
207
208 static int gen_pci_probe(struct platform_device *pdev)
209 {
210         int err;
211         const char *type;
212         const struct of_device_id *of_id;
213         const int *prop;
214         struct device *dev = &pdev->dev;
215         struct device_node *np = dev->of_node;
216         struct gen_pci *pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
217         struct hw_pci hw = {
218                 .nr_controllers = 1,
219                 .private_data   = (void **)&pci,
220                 .setup          = gen_pci_setup,
221                 .map_irq        = of_irq_parse_and_map_pci,
222                 .ops            = &gen_pci_ops,
223         };
224
225         if (!pci)
226                 return -ENOMEM;
227
228         type = of_get_property(np, "device_type", NULL);
229         if (!type || strcmp(type, "pci")) {
230                 dev_err(dev, "invalid \"device_type\" %s\n", type);
231                 return -EINVAL;
232         }
233
234         prop = of_get_property(of_chosen, "linux,pci-probe-only", NULL);
235         if (prop) {
236                 if (*prop)
237                         pci_add_flags(PCI_PROBE_ONLY);
238                 else
239                         pci_clear_flags(PCI_PROBE_ONLY);
240         }
241
242         of_id = of_match_node(gen_pci_of_match, np);
243         pci->cfg.ops = of_id->data;
244         gen_pci_ops.map_bus = pci->cfg.ops->map_bus;
245         pci->host.dev.parent = dev;
246         INIT_LIST_HEAD(&pci->host.windows);
247         INIT_LIST_HEAD(&pci->resources);
248
249         /* Parse our PCI ranges and request their resources */
250         err = gen_pci_parse_request_of_pci_ranges(pci);
251         if (err)
252                 return err;
253
254         /* Parse and map our Configuration Space windows */
255         err = gen_pci_parse_map_cfg_windows(pci);
256         if (err) {
257                 gen_pci_release_of_pci_ranges(pci);
258                 return err;
259         }
260
261         pci_common_init_dev(dev, &hw);
262         return 0;
263 }
264
265 static struct platform_driver gen_pci_driver = {
266         .driver = {
267                 .name = "pci-host-generic",
268                 .of_match_table = gen_pci_of_match,
269         },
270         .probe = gen_pci_probe,
271 };
272 module_platform_driver(gen_pci_driver);
273
274 MODULE_DESCRIPTION("Generic PCI host driver");
275 MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
276 MODULE_LICENSE("GPL v2");