2 * Simple, generic PCI host controller driver targetting firmware-initialised
3 * systems and virtual machines (e.g. the PCI emulation provided by kvmtool).
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.
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.
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/>.
17 * Copyright (C) 2014 ARM Limited
19 * Author: Will Deacon <will.deacon@arm.com>
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>
28 struct gen_pci_cfg_bus_ops
{
30 void __iomem
*(*map_bus
)(struct pci_bus
*, unsigned int, int);
33 struct gen_pci_cfg_windows
{
35 struct resource
*bus_range
;
38 const struct gen_pci_cfg_bus_ops
*ops
;
42 * ARM pcibios functions expect the ARM struct pci_sys_data as the PCI
43 * sysdata. Add pci_sys_data as the first element in struct gen_pci so
44 * that when we use a gen_pci pointer as sysdata, it is also a pointer to
45 * a struct pci_sys_data.
49 struct pci_sys_data sys
;
51 struct pci_host_bridge host
;
52 struct gen_pci_cfg_windows cfg
;
53 struct list_head resources
;
56 static void __iomem
*gen_pci_map_cfg_bus_cam(struct pci_bus
*bus
,
60 struct gen_pci
*pci
= bus
->sysdata
;
61 resource_size_t idx
= bus
->number
- pci
->cfg
.bus_range
->start
;
63 return pci
->cfg
.win
[idx
] + ((devfn
<< 8) | where
);
66 static struct gen_pci_cfg_bus_ops gen_pci_cfg_cam_bus_ops
= {
68 .map_bus
= gen_pci_map_cfg_bus_cam
,
71 static void __iomem
*gen_pci_map_cfg_bus_ecam(struct pci_bus
*bus
,
75 struct gen_pci
*pci
= bus
->sysdata
;
76 resource_size_t idx
= bus
->number
- pci
->cfg
.bus_range
->start
;
78 return pci
->cfg
.win
[idx
] + ((devfn
<< 12) | where
);
81 static struct gen_pci_cfg_bus_ops gen_pci_cfg_ecam_bus_ops
= {
83 .map_bus
= gen_pci_map_cfg_bus_ecam
,
86 static struct pci_ops gen_pci_ops
= {
87 .read
= pci_generic_config_read
,
88 .write
= pci_generic_config_write
,
91 static const struct of_device_id gen_pci_of_match
[] = {
92 { .compatible
= "pci-host-cam-generic",
93 .data
= &gen_pci_cfg_cam_bus_ops
},
95 { .compatible
= "pci-host-ecam-generic",
96 .data
= &gen_pci_cfg_ecam_bus_ops
},
100 MODULE_DEVICE_TABLE(of
, gen_pci_of_match
);
102 static void gen_pci_release_of_pci_ranges(struct gen_pci
*pci
)
104 pci_free_resource_list(&pci
->resources
);
107 static int gen_pci_parse_request_of_pci_ranges(struct gen_pci
*pci
)
109 int err
, res_valid
= 0;
110 struct device
*dev
= pci
->host
.dev
.parent
;
111 struct device_node
*np
= dev
->of_node
;
112 resource_size_t iobase
;
113 struct resource_entry
*win
;
115 err
= of_pci_get_host_bridge_resources(np
, 0, 0xff, &pci
->resources
,
120 resource_list_for_each_entry(win
, &pci
->resources
) {
121 struct resource
*parent
, *res
= win
->res
;
123 switch (resource_type(res
)) {
125 parent
= &ioport_resource
;
126 err
= pci_remap_iospace(res
, iobase
);
128 dev_warn(dev
, "error %d: failed to map resource %pR\n",
134 parent
= &iomem_resource
;
135 res_valid
|= !(res
->flags
& IORESOURCE_PREFETCH
);
138 pci
->cfg
.bus_range
= res
;
143 err
= devm_request_resource(dev
, parent
, res
);
145 goto out_release_res
;
149 dev_err(dev
, "non-prefetchable memory resource required\n");
151 goto out_release_res
;
157 gen_pci_release_of_pci_ranges(pci
);
161 static int gen_pci_parse_map_cfg_windows(struct gen_pci
*pci
)
165 resource_size_t busn
;
166 struct resource
*bus_range
;
167 struct device
*dev
= pci
->host
.dev
.parent
;
168 struct device_node
*np
= dev
->of_node
;
170 err
= of_address_to_resource(np
, 0, &pci
->cfg
.res
);
172 dev_err(dev
, "missing \"reg\" property\n");
176 /* Limit the bus-range to fit within reg */
177 bus_max
= pci
->cfg
.bus_range
->start
+
178 (resource_size(&pci
->cfg
.res
) >> pci
->cfg
.ops
->bus_shift
) - 1;
179 pci
->cfg
.bus_range
->end
= min_t(resource_size_t
,
180 pci
->cfg
.bus_range
->end
, bus_max
);
182 pci
->cfg
.win
= devm_kcalloc(dev
, resource_size(pci
->cfg
.bus_range
),
183 sizeof(*pci
->cfg
.win
), GFP_KERNEL
);
187 /* Map our Configuration Space windows */
188 if (!devm_request_mem_region(dev
, pci
->cfg
.res
.start
,
189 resource_size(&pci
->cfg
.res
),
190 "Configuration Space"))
193 bus_range
= pci
->cfg
.bus_range
;
194 for (busn
= bus_range
->start
; busn
<= bus_range
->end
; ++busn
) {
195 u32 idx
= busn
- bus_range
->start
;
196 u32 sz
= 1 << pci
->cfg
.ops
->bus_shift
;
198 pci
->cfg
.win
[idx
] = devm_ioremap(dev
,
199 pci
->cfg
.res
.start
+ busn
* sz
,
201 if (!pci
->cfg
.win
[idx
])
208 static int gen_pci_probe(struct platform_device
*pdev
)
212 const struct of_device_id
*of_id
;
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 pci_bus
*bus
, *child
;
222 type
= of_get_property(np
, "device_type", NULL
);
223 if (!type
|| strcmp(type
, "pci")) {
224 dev_err(dev
, "invalid \"device_type\" %s\n", type
);
228 prop
= of_get_property(of_chosen
, "linux,pci-probe-only", NULL
);
231 pci_add_flags(PCI_PROBE_ONLY
);
233 pci_clear_flags(PCI_PROBE_ONLY
);
236 of_id
= of_match_node(gen_pci_of_match
, np
);
237 pci
->cfg
.ops
= of_id
->data
;
238 gen_pci_ops
.map_bus
= pci
->cfg
.ops
->map_bus
;
239 pci
->host
.dev
.parent
= dev
;
240 INIT_LIST_HEAD(&pci
->host
.windows
);
241 INIT_LIST_HEAD(&pci
->resources
);
243 /* Parse our PCI ranges and request their resources */
244 err
= gen_pci_parse_request_of_pci_ranges(pci
);
248 /* Parse and map our Configuration Space windows */
249 err
= gen_pci_parse_map_cfg_windows(pci
);
251 gen_pci_release_of_pci_ranges(pci
);
255 /* Do not reassign resources if probe only */
256 if (!pci_has_flag(PCI_PROBE_ONLY
))
257 pci_add_flags(PCI_REASSIGN_ALL_RSRC
| PCI_REASSIGN_ALL_BUS
);
259 bus
= pci_scan_root_bus(dev
, 0, &gen_pci_ops
, pci
, &pci
->resources
);
261 dev_err(dev
, "Scanning rootbus failed");
265 pci_fixup_irqs(pci_common_swizzle
, of_irq_parse_and_map_pci
);
267 if (!pci_has_flag(PCI_PROBE_ONLY
)) {
268 pci_bus_size_bridges(bus
);
269 pci_bus_assign_resources(bus
);
271 list_for_each_entry(child
, &bus
->children
, node
)
272 pcie_bus_configure_settings(child
);
275 pci_bus_add_devices(bus
);
279 static struct platform_driver gen_pci_driver
= {
281 .name
= "pci-host-generic",
282 .of_match_table
= gen_pci_of_match
,
284 .probe
= gen_pci_probe
,
286 module_platform_driver(gen_pci_driver
);
288 MODULE_DESCRIPTION("Generic PCI host driver");
289 MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
290 MODULE_LICENSE("GPL v2");