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
{
33 struct gen_pci_cfg_windows
{
35 struct resource
*bus_range
;
38 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
= {
69 .map_bus
= gen_pci_map_cfg_bus_cam
,
70 .read
= pci_generic_config_read
,
71 .write
= pci_generic_config_write
,
75 static void __iomem
*gen_pci_map_cfg_bus_ecam(struct pci_bus
*bus
,
79 struct gen_pci
*pci
= bus
->sysdata
;
80 resource_size_t idx
= bus
->number
- pci
->cfg
.bus_range
->start
;
82 return pci
->cfg
.win
[idx
] + ((devfn
<< 12) | where
);
85 static struct gen_pci_cfg_bus_ops gen_pci_cfg_ecam_bus_ops
= {
88 .map_bus
= gen_pci_map_cfg_bus_ecam
,
89 .read
= pci_generic_config_read
,
90 .write
= pci_generic_config_write
,
94 static const struct of_device_id gen_pci_of_match
[] = {
95 { .compatible
= "pci-host-cam-generic",
96 .data
= &gen_pci_cfg_cam_bus_ops
},
98 { .compatible
= "pci-host-ecam-generic",
99 .data
= &gen_pci_cfg_ecam_bus_ops
},
103 MODULE_DEVICE_TABLE(of
, gen_pci_of_match
);
105 static void gen_pci_release_of_pci_ranges(struct gen_pci
*pci
)
107 pci_free_resource_list(&pci
->resources
);
110 static int gen_pci_parse_request_of_pci_ranges(struct gen_pci
*pci
)
112 int err
, res_valid
= 0;
113 struct device
*dev
= pci
->host
.dev
.parent
;
114 struct device_node
*np
= dev
->of_node
;
115 resource_size_t iobase
;
116 struct resource_entry
*win
;
118 err
= of_pci_get_host_bridge_resources(np
, 0, 0xff, &pci
->resources
,
123 resource_list_for_each_entry(win
, &pci
->resources
) {
124 struct resource
*parent
, *res
= win
->res
;
126 switch (resource_type(res
)) {
128 parent
= &ioport_resource
;
129 err
= pci_remap_iospace(res
, iobase
);
131 dev_warn(dev
, "error %d: failed to map resource %pR\n",
137 parent
= &iomem_resource
;
138 res_valid
|= !(res
->flags
& IORESOURCE_PREFETCH
);
141 pci
->cfg
.bus_range
= res
;
146 err
= devm_request_resource(dev
, parent
, res
);
148 goto out_release_res
;
152 dev_err(dev
, "non-prefetchable memory resource required\n");
154 goto out_release_res
;
160 gen_pci_release_of_pci_ranges(pci
);
164 static int gen_pci_parse_map_cfg_windows(struct gen_pci
*pci
)
168 resource_size_t busn
;
169 struct resource
*bus_range
;
170 struct device
*dev
= pci
->host
.dev
.parent
;
171 struct device_node
*np
= dev
->of_node
;
172 u32 sz
= 1 << pci
->cfg
.ops
->bus_shift
;
174 err
= of_address_to_resource(np
, 0, &pci
->cfg
.res
);
176 dev_err(dev
, "missing \"reg\" property\n");
180 /* Limit the bus-range to fit within reg */
181 bus_max
= pci
->cfg
.bus_range
->start
+
182 (resource_size(&pci
->cfg
.res
) >> pci
->cfg
.ops
->bus_shift
) - 1;
183 pci
->cfg
.bus_range
->end
= min_t(resource_size_t
,
184 pci
->cfg
.bus_range
->end
, bus_max
);
186 pci
->cfg
.win
= devm_kcalloc(dev
, resource_size(pci
->cfg
.bus_range
),
187 sizeof(*pci
->cfg
.win
), GFP_KERNEL
);
191 /* Map our Configuration Space windows */
192 if (!devm_request_mem_region(dev
, pci
->cfg
.res
.start
,
193 resource_size(&pci
->cfg
.res
),
194 "Configuration Space"))
197 bus_range
= pci
->cfg
.bus_range
;
198 for (busn
= bus_range
->start
; busn
<= bus_range
->end
; ++busn
) {
199 u32 idx
= busn
- bus_range
->start
;
201 pci
->cfg
.win
[idx
] = devm_ioremap(dev
,
202 pci
->cfg
.res
.start
+ idx
* sz
,
204 if (!pci
->cfg
.win
[idx
])
211 static int gen_pci_probe(struct platform_device
*pdev
)
215 const struct of_device_id
*of_id
;
216 struct device
*dev
= &pdev
->dev
;
217 struct device_node
*np
= dev
->of_node
;
218 struct gen_pci
*pci
= devm_kzalloc(dev
, sizeof(*pci
), GFP_KERNEL
);
219 struct pci_bus
*bus
, *child
;
224 type
= of_get_property(np
, "device_type", NULL
);
225 if (!type
|| strcmp(type
, "pci")) {
226 dev_err(dev
, "invalid \"device_type\" %s\n", type
);
230 of_pci_check_probe_only();
232 of_id
= of_match_node(gen_pci_of_match
, np
);
233 pci
->cfg
.ops
= (struct gen_pci_cfg_bus_ops
*)of_id
->data
;
234 pci
->host
.dev
.parent
= dev
;
235 INIT_LIST_HEAD(&pci
->host
.windows
);
236 INIT_LIST_HEAD(&pci
->resources
);
238 /* Parse our PCI ranges and request their resources */
239 err
= gen_pci_parse_request_of_pci_ranges(pci
);
243 /* Parse and map our Configuration Space windows */
244 err
= gen_pci_parse_map_cfg_windows(pci
);
246 gen_pci_release_of_pci_ranges(pci
);
250 /* Do not reassign resources if probe only */
251 if (!pci_has_flag(PCI_PROBE_ONLY
))
252 pci_add_flags(PCI_REASSIGN_ALL_RSRC
| PCI_REASSIGN_ALL_BUS
);
255 bus
= pci_scan_root_bus(dev
, pci
->cfg
.bus_range
->start
,
256 &pci
->cfg
.ops
->ops
, pci
, &pci
->resources
);
258 dev_err(dev
, "Scanning rootbus failed");
262 pci_fixup_irqs(pci_common_swizzle
, of_irq_parse_and_map_pci
);
264 if (!pci_has_flag(PCI_PROBE_ONLY
)) {
265 pci_bus_size_bridges(bus
);
266 pci_bus_assign_resources(bus
);
268 list_for_each_entry(child
, &bus
->children
, node
)
269 pcie_bus_configure_settings(child
);
272 pci_bus_add_devices(bus
);
276 static struct platform_driver gen_pci_driver
= {
278 .name
= "pci-host-generic",
279 .of_match_table
= gen_pci_of_match
,
281 .probe
= gen_pci_probe
,
283 module_platform_driver(gen_pci_driver
);
285 MODULE_DESCRIPTION("Generic PCI host driver");
286 MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
287 MODULE_LICENSE("GPL v2");