blob: a18251297fd0db3c37a837d467f010ca994b8851 [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
Tom Riniabb9a042024-05-18 20:20:43 -060012#include <common.h>
Simon Glassd82fbe92015-06-07 08:50:40 -060013#include <dm.h>
Simon Glass0af6e2d2019-08-01 09:46:52 -060014#include <env.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
Simon Glass75532d82015-03-05 12:25:24 -070082__weak int pci_skip_dev(struct pci_controller *hose, pci_dev_t dev)
83{
84 /*
85 * Check if pci device should be skipped in configuration
86 */
87 if (dev == PCI_BDF(hose->first_busno, 0, 0)) {
88#if defined(CONFIG_PCI_CONFIG_HOST_BRIDGE) /* don't skip host bridge */
89 /*
90 * Only skip configuration if "pciconfighost" is not set
91 */
Simon Glass64b723f2017-08-03 12:22:12 -060092 if (env_get("pciconfighost") == NULL)
Simon Glass75532d82015-03-05 12:25:24 -070093 return 1;
94#else
95 return 1;
96#endif
97 }
98
99 return 0;
100}
101
Simon Glass70a43052021-08-01 18:54:19 -0600102#if defined(CONFIG_DM_PCI_COMPAT)
Simon Glass75532d82015-03-05 12:25:24 -0700103/* Get a virtual address associated with a BAR region */
104void *pci_map_bar(pci_dev_t pdev, int bar, int flags)
105{
106 pci_addr_t pci_bus_addr;
107 u32 bar_response;
108
109 /* read BAR address */
110 pci_read_config_dword(pdev, bar, &bar_response);
111 pci_bus_addr = (pci_addr_t)(bar_response & ~0xf);
112
113 /*
114 * Pass "0" as the length argument to pci_bus_to_virt. The arg
115 * isn't actualy used on any platform because u-boot assumes a static
116 * linear mapping. In the future, this could read the BAR size
117 * and pass that as the size if needed.
118 */
119 return pci_bus_to_virt(pdev, pci_bus_addr, flags, 0, MAP_NOCACHE);
120}
121
122void pci_write_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum,
123 u32 addr_and_ctrl)
124{
125 int bar;
126
127 bar = PCI_BASE_ADDRESS_0 + barnum * 4;
128 pci_hose_write_config_dword(hose, dev, bar, addr_and_ctrl);
129}
130
131u32 pci_read_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum)
132{
133 u32 addr;
134 int bar;
135
136 bar = PCI_BASE_ADDRESS_0 + barnum * 4;
137 pci_hose_read_config_dword(hose, dev, bar, &addr);
138 if (addr & PCI_BASE_ADDRESS_SPACE_IO)
139 return addr & PCI_BASE_ADDRESS_IO_MASK;
140 else
141 return addr & PCI_BASE_ADDRESS_MEM_MASK;
142}
143
144int __pci_hose_bus_to_phys(struct pci_controller *hose,
Bin Meng8dadff12015-05-07 21:34:07 +0800145 pci_addr_t bus_addr,
146 unsigned long flags,
147 unsigned long skip_mask,
148 phys_addr_t *pa)
Simon Glass75532d82015-03-05 12:25:24 -0700149{
150 struct pci_region *res;
151 int i;
152
153 for (i = 0; i < hose->region_count; i++) {
154 res = &hose->regions[i];
155
156 if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
157 continue;
158
159 if (res->flags & skip_mask)
160 continue;
161
162 if (bus_addr >= res->bus_start &&
163 (bus_addr - res->bus_start) < res->size) {
164 *pa = (bus_addr - res->bus_start + res->phys_start);
165 return 0;
166 }
167 }
168
169 return 1;
170}
171
172phys_addr_t pci_hose_bus_to_phys(struct pci_controller *hose,
173 pci_addr_t bus_addr,
174 unsigned long flags)
175{
176 phys_addr_t phys_addr = 0;
177 int ret;
178
179 if (!hose) {
180 puts("pci_hose_bus_to_phys: invalid hose\n");
181 return phys_addr;
182 }
183
184 /*
185 * if PCI_REGION_MEM is set we do a two pass search with preference
186 * on matches that don't have PCI_REGION_SYS_MEMORY set
187 */
Cheng Gu76ea8b02015-10-23 21:48:01 +0000188 if ((flags & PCI_REGION_TYPE) == PCI_REGION_MEM) {
Simon Glass75532d82015-03-05 12:25:24 -0700189 ret = __pci_hose_bus_to_phys(hose, bus_addr,
190 flags, PCI_REGION_SYS_MEMORY, &phys_addr);
191 if (!ret)
192 return phys_addr;
193 }
194
195 ret = __pci_hose_bus_to_phys(hose, bus_addr, flags, 0, &phys_addr);
196
197 if (ret)
198 puts("pci_hose_bus_to_phys: invalid physical address\n");
199
200 return phys_addr;
201}
202
Bin Meng8dadff12015-05-07 21:34:07 +0800203int __pci_hose_phys_to_bus(struct pci_controller *hose,
204 phys_addr_t phys_addr,
205 unsigned long flags,
206 unsigned long skip_mask,
207 pci_addr_t *ba)
208{
209 struct pci_region *res;
210 pci_addr_t bus_addr;
211 int i;
212
213 for (i = 0; i < hose->region_count; i++) {
214 res = &hose->regions[i];
215
216 if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
217 continue;
218
219 if (res->flags & skip_mask)
220 continue;
221
222 bus_addr = phys_addr - res->phys_start + res->bus_start;
223
224 if (bus_addr >= res->bus_start &&
Marcel Ziswiler1324e2b2015-11-18 15:05:06 +0100225 (bus_addr - res->bus_start) < res->size) {
Bin Meng8dadff12015-05-07 21:34:07 +0800226 *ba = bus_addr;
227 return 0;
228 }
229 }
230
231 return 1;
232}
233
Minghuan Lian46e844c2016-12-13 14:54:10 +0800234/*
235 * pci_hose_phys_to_bus(): Convert physical address to bus address
236 * @hose: PCI hose of the root PCI controller
237 * @phys_addr: physical address to convert
238 * @flags: flags of pci regions
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100239 * Return: bus address if OK, 0 on error
Minghuan Lian46e844c2016-12-13 14:54:10 +0800240 */
Bin Meng8dadff12015-05-07 21:34:07 +0800241pci_addr_t pci_hose_phys_to_bus(struct pci_controller *hose,
242 phys_addr_t phys_addr,
243 unsigned long flags)
244{
245 pci_addr_t bus_addr = 0;
246 int ret;
247
248 if (!hose) {
249 puts("pci_hose_phys_to_bus: invalid hose\n");
250 return bus_addr;
251 }
252
253 /*
254 * if PCI_REGION_MEM is set we do a two pass search with preference
255 * on matches that don't have PCI_REGION_SYS_MEMORY set
256 */
Cheng Gu76ea8b02015-10-23 21:48:01 +0000257 if ((flags & PCI_REGION_TYPE) == PCI_REGION_MEM) {
Bin Meng8dadff12015-05-07 21:34:07 +0800258 ret = __pci_hose_phys_to_bus(hose, phys_addr,
259 flags, PCI_REGION_SYS_MEMORY, &bus_addr);
260 if (!ret)
261 return bus_addr;
262 }
263
264 ret = __pci_hose_phys_to_bus(hose, phys_addr, flags, 0, &bus_addr);
265
266 if (ret)
267 puts("pci_hose_phys_to_bus: invalid physical address\n");
268
269 return bus_addr;
270}
271
Simon Glass75532d82015-03-05 12:25:24 -0700272pci_dev_t pci_find_device(unsigned int vendor, unsigned int device, int index)
273{
274 struct pci_device_id ids[2] = { {}, {0, 0} };
275
276 ids[0].vendor = vendor;
277 ids[0].device = device;
278
279 return pci_find_devices(ids, index);
280}
281
282pci_dev_t pci_hose_find_devices(struct pci_controller *hose, int busnum,
283 struct pci_device_id *ids, int *indexp)
284{
285 int found_multi = 0;
286 u16 vendor, device;
287 u8 header_type;
288 pci_dev_t bdf;
289 int i;
290
291 for (bdf = PCI_BDF(busnum, 0, 0);
292 bdf < PCI_BDF(busnum + 1, 0, 0);
293 bdf += PCI_BDF(0, 0, 1)) {
294 if (pci_skip_dev(hose, bdf))
295 continue;
296
297 if (!PCI_FUNC(bdf)) {
298 pci_read_config_byte(bdf, PCI_HEADER_TYPE,
299 &header_type);
300 found_multi = header_type & 0x80;
301 } else {
302 if (!found_multi)
303 continue;
304 }
305
306 pci_read_config_word(bdf, PCI_VENDOR_ID, &vendor);
307 pci_read_config_word(bdf, PCI_DEVICE_ID, &device);
308
309 for (i = 0; ids[i].vendor != 0; i++) {
310 if (vendor == ids[i].vendor &&
311 device == ids[i].device) {
312 if ((*indexp) <= 0)
313 return bdf;
314
315 (*indexp)--;
316 }
317 }
318 }
319
320 return -1;
321}
Simon Glassb8699732015-11-29 13:18:00 -0700322
323pci_dev_t pci_find_class(uint find_class, int index)
324{
325 int bus;
326 int devnum;
327 pci_dev_t bdf;
328 uint32_t class;
329
330 for (bus = 0; bus <= pci_last_busno(); bus++) {
331 for (devnum = 0; devnum < PCI_MAX_PCI_DEVICES - 1; devnum++) {
332 pci_read_config_dword(PCI_BDF(bus, devnum, 0),
333 PCI_CLASS_REVISION, &class);
334 if (class >> 16 == 0xffff)
335 continue;
336
337 for (bdf = PCI_BDF(bus, devnum, 0);
338 bdf <= PCI_BDF(bus, devnum,
339 PCI_MAX_PCI_FUNCTIONS - 1);
340 bdf += PCI_BDF(0, 0, 1)) {
341 pci_read_config_dword(bdf, PCI_CLASS_REVISION,
342 &class);
343 class >>= 8;
344
345 if (class != find_class)
346 continue;
347 /*
348 * Decrement the index. We want to return the
349 * correct device, so index is 0 for the first
350 * matching device, 1 for the second, etc.
351 */
352 if (index) {
353 index--;
354 continue;
355 }
356 /* Return index'th controller. */
357 return bdf;
358 }
359 }
360 }
361
362 return -ENODEV;
363}
Simon Glass70a43052021-08-01 18:54:19 -0600364#endif /* CONFIG_DM_PCI_COMPAT */