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