blob: a57cf11cc537775a393c8565a7caf753900d4fd3 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass75532d82015-03-05 12:25:24 -07002/*
3 * Copyright (c) 2014 Google, Inc
4 *
5 * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
6 * Andreas Heppel <aheppel@sysgo.de>
7 *
8 * (C) Copyright 2002, 2003
9 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
Simon Glass75532d82015-03-05 12:25:24 -070010 */
11
Simon Glassd82fbe92015-06-07 08:50:40 -060012#include <dm.h>
Simon Glass0af6e2d2019-08-01 09:46:52 -060013#include <env.h>
Simon Glass75532d82015-03-05 12:25:24 -070014#include <errno.h>
15#include <pci.h>
16#include <asm/io.h>
17
18const char *pci_class_str(u8 class)
19{
20 switch (class) {
21 case PCI_CLASS_NOT_DEFINED:
22 return "Build before PCI Rev2.0";
23 break;
24 case PCI_BASE_CLASS_STORAGE:
25 return "Mass storage controller";
26 break;
27 case PCI_BASE_CLASS_NETWORK:
28 return "Network controller";
29 break;
30 case PCI_BASE_CLASS_DISPLAY:
31 return "Display controller";
32 break;
33 case PCI_BASE_CLASS_MULTIMEDIA:
34 return "Multimedia device";
35 break;
36 case PCI_BASE_CLASS_MEMORY:
37 return "Memory controller";
38 break;
39 case PCI_BASE_CLASS_BRIDGE:
40 return "Bridge device";
41 break;
42 case PCI_BASE_CLASS_COMMUNICATION:
43 return "Simple comm. controller";
44 break;
45 case PCI_BASE_CLASS_SYSTEM:
46 return "Base system peripheral";
47 break;
48 case PCI_BASE_CLASS_INPUT:
49 return "Input device";
50 break;
51 case PCI_BASE_CLASS_DOCKING:
52 return "Docking station";
53 break;
54 case PCI_BASE_CLASS_PROCESSOR:
55 return "Processor";
56 break;
57 case PCI_BASE_CLASS_SERIAL:
58 return "Serial bus controller";
59 break;
60 case PCI_BASE_CLASS_INTELLIGENT:
61 return "Intelligent controller";
62 break;
63 case PCI_BASE_CLASS_SATELLITE:
64 return "Satellite controller";
65 break;
66 case PCI_BASE_CLASS_CRYPT:
67 return "Cryptographic device";
68 break;
69 case PCI_BASE_CLASS_SIGNAL_PROCESSING:
70 return "DSP";
71 break;
72 case PCI_CLASS_OTHERS:
73 return "Does not fit any class";
74 break;
75 default:
76 return "???";
77 break;
78 };
79}
80
Simon Glass75532d82015-03-05 12:25:24 -070081__weak int pci_skip_dev(struct pci_controller *hose, pci_dev_t dev)
82{
83 /*
84 * Check if pci device should be skipped in configuration
85 */
86 if (dev == PCI_BDF(hose->first_busno, 0, 0)) {
87#if defined(CONFIG_PCI_CONFIG_HOST_BRIDGE) /* don't skip host bridge */
88 /*
89 * Only skip configuration if "pciconfighost" is not set
90 */
Simon Glass64b723f2017-08-03 12:22:12 -060091 if (env_get("pciconfighost") == NULL)
Simon Glass75532d82015-03-05 12:25:24 -070092 return 1;
93#else
94 return 1;
95#endif
96 }
97
98 return 0;
99}
100
Simon Glass70a43052021-08-01 18:54:19 -0600101#if defined(CONFIG_DM_PCI_COMPAT)
Simon Glass75532d82015-03-05 12:25:24 -0700102/* Get a virtual address associated with a BAR region */
103void *pci_map_bar(pci_dev_t pdev, int bar, int flags)
104{
105 pci_addr_t pci_bus_addr;
106 u32 bar_response;
107
108 /* read BAR address */
109 pci_read_config_dword(pdev, bar, &bar_response);
110 pci_bus_addr = (pci_addr_t)(bar_response & ~0xf);
111
112 /*
113 * Pass "0" as the length argument to pci_bus_to_virt. The arg
114 * isn't actualy used on any platform because u-boot assumes a static
115 * linear mapping. In the future, this could read the BAR size
116 * and pass that as the size if needed.
117 */
118 return pci_bus_to_virt(pdev, pci_bus_addr, flags, 0, MAP_NOCACHE);
119}
120
121void pci_write_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum,
122 u32 addr_and_ctrl)
123{
124 int bar;
125
126 bar = PCI_BASE_ADDRESS_0 + barnum * 4;
127 pci_hose_write_config_dword(hose, dev, bar, addr_and_ctrl);
128}
129
130u32 pci_read_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum)
131{
132 u32 addr;
133 int bar;
134
135 bar = PCI_BASE_ADDRESS_0 + barnum * 4;
136 pci_hose_read_config_dword(hose, dev, bar, &addr);
137 if (addr & PCI_BASE_ADDRESS_SPACE_IO)
138 return addr & PCI_BASE_ADDRESS_IO_MASK;
139 else
140 return addr & PCI_BASE_ADDRESS_MEM_MASK;
141}
142
143int __pci_hose_bus_to_phys(struct pci_controller *hose,
Bin Meng8dadff12015-05-07 21:34:07 +0800144 pci_addr_t bus_addr,
145 unsigned long flags,
146 unsigned long skip_mask,
147 phys_addr_t *pa)
Simon Glass75532d82015-03-05 12:25:24 -0700148{
149 struct pci_region *res;
150 int i;
151
152 for (i = 0; i < hose->region_count; i++) {
153 res = &hose->regions[i];
154
155 if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
156 continue;
157
158 if (res->flags & skip_mask)
159 continue;
160
161 if (bus_addr >= res->bus_start &&
162 (bus_addr - res->bus_start) < res->size) {
163 *pa = (bus_addr - res->bus_start + res->phys_start);
164 return 0;
165 }
166 }
167
168 return 1;
169}
170
171phys_addr_t pci_hose_bus_to_phys(struct pci_controller *hose,
172 pci_addr_t bus_addr,
173 unsigned long flags)
174{
175 phys_addr_t phys_addr = 0;
176 int ret;
177
178 if (!hose) {
179 puts("pci_hose_bus_to_phys: invalid hose\n");
180 return phys_addr;
181 }
182
183 /*
184 * if PCI_REGION_MEM is set we do a two pass search with preference
185 * on matches that don't have PCI_REGION_SYS_MEMORY set
186 */
Cheng Gu76ea8b02015-10-23 21:48:01 +0000187 if ((flags & PCI_REGION_TYPE) == PCI_REGION_MEM) {
Simon Glass75532d82015-03-05 12:25:24 -0700188 ret = __pci_hose_bus_to_phys(hose, bus_addr,
189 flags, PCI_REGION_SYS_MEMORY, &phys_addr);
190 if (!ret)
191 return phys_addr;
192 }
193
194 ret = __pci_hose_bus_to_phys(hose, bus_addr, flags, 0, &phys_addr);
195
196 if (ret)
197 puts("pci_hose_bus_to_phys: invalid physical address\n");
198
199 return phys_addr;
200}
201
Bin Meng8dadff12015-05-07 21:34:07 +0800202int __pci_hose_phys_to_bus(struct pci_controller *hose,
203 phys_addr_t phys_addr,
204 unsigned long flags,
205 unsigned long skip_mask,
206 pci_addr_t *ba)
207{
208 struct pci_region *res;
209 pci_addr_t bus_addr;
210 int i;
211
212 for (i = 0; i < hose->region_count; i++) {
213 res = &hose->regions[i];
214
215 if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
216 continue;
217
218 if (res->flags & skip_mask)
219 continue;
220
221 bus_addr = phys_addr - res->phys_start + res->bus_start;
222
223 if (bus_addr >= res->bus_start &&
Marcel Ziswiler1324e2b2015-11-18 15:05:06 +0100224 (bus_addr - res->bus_start) < res->size) {
Bin Meng8dadff12015-05-07 21:34:07 +0800225 *ba = bus_addr;
226 return 0;
227 }
228 }
229
230 return 1;
231}
232
Minghuan Lian46e844c2016-12-13 14:54:10 +0800233/*
234 * pci_hose_phys_to_bus(): Convert physical address to bus address
235 * @hose: PCI hose of the root PCI controller
236 * @phys_addr: physical address to convert
237 * @flags: flags of pci regions
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100238 * Return: bus address if OK, 0 on error
Minghuan Lian46e844c2016-12-13 14:54:10 +0800239 */
Bin Meng8dadff12015-05-07 21:34:07 +0800240pci_addr_t pci_hose_phys_to_bus(struct pci_controller *hose,
241 phys_addr_t phys_addr,
242 unsigned long flags)
243{
244 pci_addr_t bus_addr = 0;
245 int ret;
246
247 if (!hose) {
248 puts("pci_hose_phys_to_bus: invalid hose\n");
249 return bus_addr;
250 }
251
252 /*
253 * if PCI_REGION_MEM is set we do a two pass search with preference
254 * on matches that don't have PCI_REGION_SYS_MEMORY set
255 */
Cheng Gu76ea8b02015-10-23 21:48:01 +0000256 if ((flags & PCI_REGION_TYPE) == PCI_REGION_MEM) {
Bin Meng8dadff12015-05-07 21:34:07 +0800257 ret = __pci_hose_phys_to_bus(hose, phys_addr,
258 flags, PCI_REGION_SYS_MEMORY, &bus_addr);
259 if (!ret)
260 return bus_addr;
261 }
262
263 ret = __pci_hose_phys_to_bus(hose, phys_addr, flags, 0, &bus_addr);
264
265 if (ret)
266 puts("pci_hose_phys_to_bus: invalid physical address\n");
267
268 return bus_addr;
269}
270
Simon Glass75532d82015-03-05 12:25:24 -0700271pci_dev_t pci_find_device(unsigned int vendor, unsigned int device, int index)
272{
273 struct pci_device_id ids[2] = { {}, {0, 0} };
274
275 ids[0].vendor = vendor;
276 ids[0].device = device;
277
278 return pci_find_devices(ids, index);
279}
280
281pci_dev_t pci_hose_find_devices(struct pci_controller *hose, int busnum,
282 struct pci_device_id *ids, int *indexp)
283{
284 int found_multi = 0;
285 u16 vendor, device;
286 u8 header_type;
287 pci_dev_t bdf;
288 int i;
289
290 for (bdf = PCI_BDF(busnum, 0, 0);
291 bdf < PCI_BDF(busnum + 1, 0, 0);
292 bdf += PCI_BDF(0, 0, 1)) {
293 if (pci_skip_dev(hose, bdf))
294 continue;
295
296 if (!PCI_FUNC(bdf)) {
297 pci_read_config_byte(bdf, PCI_HEADER_TYPE,
298 &header_type);
299 found_multi = header_type & 0x80;
300 } else {
301 if (!found_multi)
302 continue;
303 }
304
305 pci_read_config_word(bdf, PCI_VENDOR_ID, &vendor);
306 pci_read_config_word(bdf, PCI_DEVICE_ID, &device);
307
308 for (i = 0; ids[i].vendor != 0; i++) {
309 if (vendor == ids[i].vendor &&
310 device == ids[i].device) {
311 if ((*indexp) <= 0)
312 return bdf;
313
314 (*indexp)--;
315 }
316 }
317 }
318
319 return -1;
320}
Simon Glassb8699732015-11-29 13:18:00 -0700321
322pci_dev_t pci_find_class(uint find_class, int index)
323{
324 int bus;
325 int devnum;
326 pci_dev_t bdf;
327 uint32_t class;
328
329 for (bus = 0; bus <= pci_last_busno(); bus++) {
330 for (devnum = 0; devnum < PCI_MAX_PCI_DEVICES - 1; devnum++) {
331 pci_read_config_dword(PCI_BDF(bus, devnum, 0),
332 PCI_CLASS_REVISION, &class);
333 if (class >> 16 == 0xffff)
334 continue;
335
336 for (bdf = PCI_BDF(bus, devnum, 0);
337 bdf <= PCI_BDF(bus, devnum,
338 PCI_MAX_PCI_FUNCTIONS - 1);
339 bdf += PCI_BDF(0, 0, 1)) {
340 pci_read_config_dword(bdf, PCI_CLASS_REVISION,
341 &class);
342 class >>= 8;
343
344 if (class != find_class)
345 continue;
346 /*
347 * Decrement the index. We want to return the
348 * correct device, so index is 0 for the first
349 * matching device, 1 for the second, etc.
350 */
351 if (index) {
352 index--;
353 continue;
354 }
355 /* Return index'th controller. */
356 return bdf;
357 }
358 }
359 }
360
361 return -ENODEV;
362}
Simon Glass70a43052021-08-01 18:54:19 -0600363#endif /* CONFIG_DM_PCI_COMPAT */