xref: /openbmc/u-boot/cmd/pci.c (revision ea743e65)
1 /*
2  * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
3  * Andreas Heppel <aheppel@sysgo.de>
4  *
5  * (C) Copyright 2002
6  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
7  * Wolfgang Grandegger, DENX Software Engineering, wg@denx.de.
8  *
9  * SPDX-License-Identifier:	GPL-2.0+
10  */
11 
12 /*
13  * PCI routines
14  */
15 
16 #include <common.h>
17 #include <bootretry.h>
18 #include <cli.h>
19 #include <command.h>
20 #include <console.h>
21 #include <dm.h>
22 #include <asm/processor.h>
23 #include <asm/io.h>
24 #include <pci.h>
25 
26 struct pci_reg_info {
27 	const char *name;
28 	enum pci_size_t size;
29 	u8 offset;
30 };
31 
32 static int pci_byte_size(enum pci_size_t size)
33 {
34 	switch (size) {
35 	case PCI_SIZE_8:
36 		return 1;
37 	case PCI_SIZE_16:
38 		return 2;
39 	case PCI_SIZE_32:
40 	default:
41 		return 4;
42 	}
43 }
44 
45 static int pci_field_width(enum pci_size_t size)
46 {
47 	return pci_byte_size(size) * 2;
48 }
49 
50 #ifdef CONFIG_DM_PCI
51 static void pci_show_regs(struct udevice *dev, struct pci_reg_info *regs)
52 {
53 	for (; regs->name; regs++) {
54 		unsigned long val;
55 
56 		dm_pci_read_config(dev, regs->offset, &val, regs->size);
57 		printf("  %s =%*s%#.*lx\n", regs->name,
58 		       (int)(28 - strlen(regs->name)), "",
59 		       pci_field_width(regs->size), val);
60 	}
61 }
62 #else
63 static unsigned long pci_read_config(pci_dev_t dev, int offset,
64 				     enum pci_size_t size)
65 {
66 	u32 val32;
67 	u16 val16;
68 	u8 val8;
69 
70 	switch (size) {
71 	case PCI_SIZE_8:
72 		pci_read_config_byte(dev, offset, &val8);
73 		return val8;
74 	case PCI_SIZE_16:
75 		pci_read_config_word(dev, offset, &val16);
76 		return val16;
77 	case PCI_SIZE_32:
78 	default:
79 		pci_read_config_dword(dev, offset, &val32);
80 		return val32;
81 	}
82 }
83 
84 static void pci_show_regs(pci_dev_t dev, struct pci_reg_info *regs)
85 {
86 	for (; regs->name; regs++) {
87 		printf("  %s =%*s%#.*lx\n", regs->name,
88 		       (int)(28 - strlen(regs->name)), "",
89 		       pci_field_width(regs->size),
90 		       pci_read_config(dev, regs->offset, regs->size));
91 	}
92 }
93 #endif
94 
95 static struct pci_reg_info regs_start[] = {
96 	{ "vendor ID", PCI_SIZE_16, PCI_VENDOR_ID },
97 	{ "device ID", PCI_SIZE_16, PCI_DEVICE_ID },
98 	{ "command register ID", PCI_SIZE_16, PCI_COMMAND },
99 	{ "status register", PCI_SIZE_16, PCI_STATUS },
100 	{ "revision ID", PCI_SIZE_8, PCI_REVISION_ID },
101 	{},
102 };
103 
104 static struct pci_reg_info regs_rest[] = {
105 	{ "sub class code", PCI_SIZE_8, PCI_CLASS_SUB_CODE },
106 	{ "programming interface", PCI_SIZE_8, PCI_CLASS_PROG },
107 	{ "cache line", PCI_SIZE_8, PCI_CACHE_LINE_SIZE },
108 	{ "latency time", PCI_SIZE_8, PCI_LATENCY_TIMER },
109 	{ "header type", PCI_SIZE_8, PCI_HEADER_TYPE },
110 	{ "BIST", PCI_SIZE_8, PCI_BIST },
111 	{ "base address 0", PCI_SIZE_32, PCI_BASE_ADDRESS_0 },
112 	{},
113 };
114 
115 static struct pci_reg_info regs_normal[] = {
116 	{ "base address 1", PCI_SIZE_32, PCI_BASE_ADDRESS_1 },
117 	{ "base address 2", PCI_SIZE_32, PCI_BASE_ADDRESS_2 },
118 	{ "base address 3", PCI_SIZE_32, PCI_BASE_ADDRESS_3 },
119 	{ "base address 4", PCI_SIZE_32, PCI_BASE_ADDRESS_4 },
120 	{ "base address 5", PCI_SIZE_32, PCI_BASE_ADDRESS_5 },
121 	{ "cardBus CIS pointer", PCI_SIZE_32, PCI_CARDBUS_CIS },
122 	{ "sub system vendor ID", PCI_SIZE_16, PCI_SUBSYSTEM_VENDOR_ID },
123 	{ "sub system ID", PCI_SIZE_16, PCI_SUBSYSTEM_ID },
124 	{ "expansion ROM base address", PCI_SIZE_32, PCI_ROM_ADDRESS },
125 	{ "interrupt line", PCI_SIZE_8, PCI_INTERRUPT_LINE },
126 	{ "interrupt pin", PCI_SIZE_8, PCI_INTERRUPT_PIN },
127 	{ "min Grant", PCI_SIZE_8, PCI_MIN_GNT },
128 	{ "max Latency", PCI_SIZE_8, PCI_MAX_LAT },
129 	{},
130 };
131 
132 static struct pci_reg_info regs_bridge[] = {
133 	{ "base address 1", PCI_SIZE_32, PCI_BASE_ADDRESS_1 },
134 	{ "primary bus number", PCI_SIZE_8, PCI_PRIMARY_BUS },
135 	{ "secondary bus number", PCI_SIZE_8, PCI_SECONDARY_BUS },
136 	{ "subordinate bus number", PCI_SIZE_8, PCI_SUBORDINATE_BUS },
137 	{ "secondary latency timer", PCI_SIZE_8, PCI_SEC_LATENCY_TIMER },
138 	{ "IO base", PCI_SIZE_8, PCI_IO_BASE },
139 	{ "IO limit", PCI_SIZE_8, PCI_IO_LIMIT },
140 	{ "secondary status", PCI_SIZE_16, PCI_SEC_STATUS },
141 	{ "memory base", PCI_SIZE_16, PCI_MEMORY_BASE },
142 	{ "memory limit", PCI_SIZE_16, PCI_MEMORY_LIMIT },
143 	{ "prefetch memory base", PCI_SIZE_16, PCI_PREF_MEMORY_BASE },
144 	{ "prefetch memory limit", PCI_SIZE_16, PCI_PREF_MEMORY_LIMIT },
145 	{ "prefetch memory base upper", PCI_SIZE_32, PCI_PREF_BASE_UPPER32 },
146 	{ "prefetch memory limit upper", PCI_SIZE_32, PCI_PREF_LIMIT_UPPER32 },
147 	{ "IO base upper 16 bits", PCI_SIZE_16, PCI_IO_BASE_UPPER16 },
148 	{ "IO limit upper 16 bits", PCI_SIZE_16, PCI_IO_LIMIT_UPPER16 },
149 	{ "expansion ROM base address", PCI_SIZE_32, PCI_ROM_ADDRESS1 },
150 	{ "interrupt line", PCI_SIZE_8, PCI_INTERRUPT_LINE },
151 	{ "interrupt pin", PCI_SIZE_8, PCI_INTERRUPT_PIN },
152 	{ "bridge control", PCI_SIZE_16, PCI_BRIDGE_CONTROL },
153 	{},
154 };
155 
156 static struct pci_reg_info regs_cardbus[] = {
157 	{ "capabilities", PCI_SIZE_8, PCI_CB_CAPABILITY_LIST },
158 	{ "secondary status", PCI_SIZE_16, PCI_CB_SEC_STATUS },
159 	{ "primary bus number", PCI_SIZE_8, PCI_CB_PRIMARY_BUS },
160 	{ "CardBus number", PCI_SIZE_8, PCI_CB_CARD_BUS },
161 	{ "subordinate bus number", PCI_SIZE_8, PCI_CB_SUBORDINATE_BUS },
162 	{ "CardBus latency timer", PCI_SIZE_8, PCI_CB_LATENCY_TIMER },
163 	{ "CardBus memory base 0", PCI_SIZE_32, PCI_CB_MEMORY_BASE_0 },
164 	{ "CardBus memory limit 0", PCI_SIZE_32, PCI_CB_MEMORY_LIMIT_0 },
165 	{ "CardBus memory base 1", PCI_SIZE_32, PCI_CB_MEMORY_BASE_1 },
166 	{ "CardBus memory limit 1", PCI_SIZE_32, PCI_CB_MEMORY_LIMIT_1 },
167 	{ "CardBus IO base 0", PCI_SIZE_16, PCI_CB_IO_BASE_0 },
168 	{ "CardBus IO base high 0", PCI_SIZE_16, PCI_CB_IO_BASE_0_HI },
169 	{ "CardBus IO limit 0", PCI_SIZE_16, PCI_CB_IO_LIMIT_0 },
170 	{ "CardBus IO limit high 0", PCI_SIZE_16, PCI_CB_IO_LIMIT_0_HI },
171 	{ "CardBus IO base 1", PCI_SIZE_16, PCI_CB_IO_BASE_1 },
172 	{ "CardBus IO base high 1", PCI_SIZE_16, PCI_CB_IO_BASE_1_HI },
173 	{ "CardBus IO limit 1", PCI_SIZE_16, PCI_CB_IO_LIMIT_1 },
174 	{ "CardBus IO limit high 1", PCI_SIZE_16, PCI_CB_IO_LIMIT_1_HI },
175 	{ "interrupt line", PCI_SIZE_8, PCI_INTERRUPT_LINE },
176 	{ "interrupt pin", PCI_SIZE_8, PCI_INTERRUPT_PIN },
177 	{ "bridge control", PCI_SIZE_16, PCI_CB_BRIDGE_CONTROL },
178 	{ "subvendor ID", PCI_SIZE_16, PCI_CB_SUBSYSTEM_VENDOR_ID },
179 	{ "subdevice ID", PCI_SIZE_16, PCI_CB_SUBSYSTEM_ID },
180 	{ "PC Card 16bit base address", PCI_SIZE_32, PCI_CB_LEGACY_MODE_BASE },
181 	{},
182 };
183 
184 /**
185  * pci_header_show() - Show the header of the specified PCI device.
186  *
187  * @dev: Bus+Device+Function number
188  */
189 #ifdef CONFIG_DM_PCI
190 void pci_header_show(struct udevice *dev)
191 #else
192 void pci_header_show(pci_dev_t dev)
193 #endif
194 {
195 #ifdef CONFIG_DM_PCI
196 	unsigned long class, header_type;
197 
198 	dm_pci_read_config(dev, PCI_CLASS_CODE, &class, PCI_SIZE_8);
199 	dm_pci_read_config(dev, PCI_HEADER_TYPE, &header_type, PCI_SIZE_8);
200 #else
201 	u8 class, header_type;
202 
203 	pci_read_config_byte(dev, PCI_CLASS_CODE, &class);
204 	pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
205 #endif
206 	pci_show_regs(dev, regs_start);
207 	printf("  class code =                  0x%.2x (%s)\n", (int)class,
208 	       pci_class_str(class));
209 	pci_show_regs(dev, regs_rest);
210 
211 	switch (header_type & 0x03) {
212 	case PCI_HEADER_TYPE_NORMAL:	/* "normal" PCI device */
213 		pci_show_regs(dev, regs_normal);
214 		break;
215 	case PCI_HEADER_TYPE_BRIDGE:	/* PCI-to-PCI bridge */
216 		pci_show_regs(dev, regs_bridge);
217 		break;
218 	case PCI_HEADER_TYPE_CARDBUS:	/* PCI-to-CardBus bridge */
219 		pci_show_regs(dev, regs_cardbus);
220 		break;
221 
222 	default:
223 		printf("unknown header\n");
224 		break;
225     }
226 }
227 
228 void pciinfo_header(int busnum, bool short_listing)
229 {
230 	printf("Scanning PCI devices on bus %d\n", busnum);
231 
232 	if (short_listing) {
233 		printf("BusDevFun  VendorId   DeviceId   Device Class       Sub-Class\n");
234 		printf("_____________________________________________________________\n");
235 	}
236 }
237 
238 #ifdef CONFIG_DM_PCI
239 /**
240  * pci_header_show_brief() - Show the short-form PCI device header
241  *
242  * Reads and prints the header of the specified PCI device in short form.
243  *
244  * @dev: PCI device to show
245  */
246 static void pci_header_show_brief(struct udevice *dev)
247 {
248 	ulong vendor, device;
249 	ulong class, subclass;
250 
251 	dm_pci_read_config(dev, PCI_VENDOR_ID, &vendor, PCI_SIZE_16);
252 	dm_pci_read_config(dev, PCI_DEVICE_ID, &device, PCI_SIZE_16);
253 	dm_pci_read_config(dev, PCI_CLASS_CODE, &class, PCI_SIZE_8);
254 	dm_pci_read_config(dev, PCI_CLASS_SUB_CODE, &subclass, PCI_SIZE_8);
255 
256 	printf("0x%.4lx     0x%.4lx     %-23s 0x%.2lx\n",
257 	       vendor, device,
258 	       pci_class_str(class), subclass);
259 }
260 
261 static void pciinfo(struct udevice *bus, bool short_listing)
262 {
263 	struct udevice *dev;
264 
265 	pciinfo_header(bus->seq, short_listing);
266 
267 	for (device_find_first_child(bus, &dev);
268 	     dev;
269 	     device_find_next_child(&dev)) {
270 		struct pci_child_platdata *pplat;
271 
272 		pplat = dev_get_parent_platdata(dev);
273 		if (short_listing) {
274 			printf("%02x.%02x.%02x   ", bus->seq,
275 			       PCI_DEV(pplat->devfn), PCI_FUNC(pplat->devfn));
276 			pci_header_show_brief(dev);
277 		} else {
278 			printf("\nFound PCI device %02x.%02x.%02x:\n", bus->seq,
279 			       PCI_DEV(pplat->devfn), PCI_FUNC(pplat->devfn));
280 			pci_header_show(dev);
281 		}
282 	}
283 }
284 
285 #else
286 
287 /**
288  * pci_header_show_brief() - Show the short-form PCI device header
289  *
290  * Reads and prints the header of the specified PCI device in short form.
291  *
292  * @dev: Bus+Device+Function number
293  */
294 void pci_header_show_brief(pci_dev_t dev)
295 {
296 	u16 vendor, device;
297 	u8 class, subclass;
298 
299 	pci_read_config_word(dev, PCI_VENDOR_ID, &vendor);
300 	pci_read_config_word(dev, PCI_DEVICE_ID, &device);
301 	pci_read_config_byte(dev, PCI_CLASS_CODE, &class);
302 	pci_read_config_byte(dev, PCI_CLASS_SUB_CODE, &subclass);
303 
304 	printf("0x%.4x     0x%.4x     %-23s 0x%.2x\n",
305 	       vendor, device,
306 	       pci_class_str(class), subclass);
307 }
308 
309 /**
310  * pciinfo() - Show a list of devices on the PCI bus
311  *
312  * Show information about devices on PCI bus. Depending on @short_pci_listing
313  * the output will be more or less exhaustive.
314  *
315  * @bus_num: The number of the bus to be scanned
316  * @short_pci_listing: true to use short form, showing only a brief header
317  * for each device
318  */
319 void pciinfo(int bus_num, int short_pci_listing)
320 {
321 	struct pci_controller *hose = pci_bus_to_hose(bus_num);
322 	int device;
323 	int function;
324 	unsigned char header_type;
325 	unsigned short vendor_id;
326 	pci_dev_t dev;
327 	int ret;
328 
329 	if (!hose)
330 		return;
331 
332 	pciinfo_header(bus_num, short_pci_listing);
333 
334 	for (device = 0; device < PCI_MAX_PCI_DEVICES; device++) {
335 		header_type = 0;
336 		vendor_id = 0;
337 		for (function = 0; function < PCI_MAX_PCI_FUNCTIONS;
338 		     function++) {
339 			/*
340 			 * If this is not a multi-function device, we skip
341 			 * the rest.
342 			 */
343 			if (function && !(header_type & 0x80))
344 				break;
345 
346 			dev = PCI_BDF(bus_num, device, function);
347 
348 			if (pci_skip_dev(hose, dev))
349 				continue;
350 
351 			ret = pci_read_config_word(dev, PCI_VENDOR_ID,
352 						   &vendor_id);
353 			if (ret)
354 				goto error;
355 			if ((vendor_id == 0xFFFF) || (vendor_id == 0x0000))
356 				continue;
357 
358 			if (!function) {
359 				pci_read_config_byte(dev, PCI_HEADER_TYPE,
360 						     &header_type);
361 			}
362 
363 			if (short_pci_listing) {
364 				printf("%02x.%02x.%02x   ", bus_num, device,
365 				       function);
366 				pci_header_show_brief(dev);
367 			} else {
368 				printf("\nFound PCI device %02x.%02x.%02x:\n",
369 				       bus_num, device, function);
370 				pci_header_show(dev);
371 			}
372 		}
373 	}
374 
375 	return;
376 error:
377 	printf("Cannot read bus configuration: %d\n", ret);
378 }
379 #endif
380 
381 /**
382  * get_pci_dev() - Convert the "bus.device.function" identifier into a number
383  *
384  * @name: Device string in the form "bus.device.function" where each is in hex
385  * @return encoded pci_dev_t or -1 if the string was invalid
386  */
387 static pci_dev_t get_pci_dev(char *name)
388 {
389 	char cnum[12];
390 	int len, i, iold, n;
391 	int bdfs[3] = {0,0,0};
392 
393 	len = strlen(name);
394 	if (len > 8)
395 		return -1;
396 	for (i = 0, iold = 0, n = 0; i < len; i++) {
397 		if (name[i] == '.') {
398 			memcpy(cnum, &name[iold], i - iold);
399 			cnum[i - iold] = '\0';
400 			bdfs[n++] = simple_strtoul(cnum, NULL, 16);
401 			iold = i + 1;
402 		}
403 	}
404 	strcpy(cnum, &name[iold]);
405 	if (n == 0)
406 		n = 1;
407 	bdfs[n] = simple_strtoul(cnum, NULL, 16);
408 
409 	return PCI_BDF(bdfs[0], bdfs[1], bdfs[2]);
410 }
411 
412 #ifdef CONFIG_DM_PCI
413 static int pci_cfg_display(struct udevice *dev, ulong addr,
414 			   enum pci_size_t size, ulong length)
415 #else
416 static int pci_cfg_display(pci_dev_t bdf, ulong addr, enum pci_size_t size,
417 			   ulong length)
418 #endif
419 {
420 #define DISP_LINE_LEN	16
421 	ulong i, nbytes, linebytes;
422 	int byte_size;
423 	int rc = 0;
424 
425 	byte_size = pci_byte_size(size);
426 	if (length == 0)
427 		length = 0x40 / byte_size; /* Standard PCI config space */
428 
429 	/* Print the lines.
430 	 * once, and all accesses are with the specified bus width.
431 	 */
432 	nbytes = length * byte_size;
433 	do {
434 		printf("%08lx:", addr);
435 		linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes;
436 		for (i = 0; i < linebytes; i += byte_size) {
437 			unsigned long val;
438 
439 #ifdef CONFIG_DM_PCI
440 			dm_pci_read_config(dev, addr, &val, size);
441 #else
442 			val = pci_read_config(bdf, addr, size);
443 #endif
444 			printf(" %0*lx", pci_field_width(size), val);
445 			addr += byte_size;
446 		}
447 		printf("\n");
448 		nbytes -= linebytes;
449 		if (ctrlc()) {
450 			rc = 1;
451 			break;
452 		}
453 	} while (nbytes > 0);
454 
455 	return (rc);
456 }
457 
458 #ifndef CONFIG_DM_PCI
459 static int pci_cfg_write (pci_dev_t bdf, ulong addr, ulong size, ulong value)
460 {
461 	if (size == 4) {
462 		pci_write_config_dword(bdf, addr, value);
463 	}
464 	else if (size == 2) {
465 		ushort val = value & 0xffff;
466 		pci_write_config_word(bdf, addr, val);
467 	}
468 	else {
469 		u_char val = value & 0xff;
470 		pci_write_config_byte(bdf, addr, val);
471 	}
472 	return 0;
473 }
474 #endif
475 
476 #ifdef CONFIG_DM_PCI
477 static int pci_cfg_modify(struct udevice *dev, ulong addr, ulong size,
478 			  ulong value, int incrflag)
479 #else
480 static int pci_cfg_modify(pci_dev_t bdf, ulong addr, ulong size, ulong value,
481 			  int incrflag)
482 #endif
483 {
484 	ulong	i;
485 	int	nbytes;
486 	ulong val;
487 
488 	/* Print the address, followed by value.  Then accept input for
489 	 * the next value.  A non-converted value exits.
490 	 */
491 	do {
492 		printf("%08lx:", addr);
493 #ifdef CONFIG_DM_PCI
494 		dm_pci_read_config(dev, addr, &val, size);
495 #else
496 		val = pci_read_config(bdf, addr, size);
497 #endif
498 		printf(" %0*lx", pci_field_width(size), val);
499 
500 		nbytes = cli_readline(" ? ");
501 		if (nbytes == 0 || (nbytes == 1 && console_buffer[0] == '-')) {
502 			/* <CR> pressed as only input, don't modify current
503 			 * location and move to next. "-" pressed will go back.
504 			 */
505 			if (incrflag)
506 				addr += nbytes ? -size : size;
507 			nbytes = 1;
508 			/* good enough to not time out */
509 			bootretry_reset_cmd_timeout();
510 		}
511 #ifdef CONFIG_BOOT_RETRY_TIME
512 		else if (nbytes == -2) {
513 			break;	/* timed out, exit the command	*/
514 		}
515 #endif
516 		else {
517 			char *endp;
518 			i = simple_strtoul(console_buffer, &endp, 16);
519 			nbytes = endp - console_buffer;
520 			if (nbytes) {
521 				/* good enough to not time out
522 				 */
523 				bootretry_reset_cmd_timeout();
524 #ifdef CONFIG_DM_PCI
525 				dm_pci_write_config(dev, addr, i, size);
526 #else
527 				pci_cfg_write(bdf, addr, size, i);
528 #endif
529 				if (incrflag)
530 					addr += size;
531 			}
532 		}
533 	} while (nbytes);
534 
535 	return 0;
536 }
537 
538 /* PCI Configuration Space access commands
539  *
540  * Syntax:
541  *	pci display[.b, .w, .l] bus.device.function} [addr] [len]
542  *	pci next[.b, .w, .l] bus.device.function [addr]
543  *      pci modify[.b, .w, .l] bus.device.function [addr]
544  *      pci write[.b, .w, .l] bus.device.function addr value
545  */
546 static int do_pci(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
547 {
548 	ulong addr = 0, value = 0, cmd_size = 0;
549 	enum pci_size_t size = PCI_SIZE_32;
550 #ifdef CONFIG_DM_PCI
551 	struct udevice *dev, *bus;
552 #else
553 	pci_dev_t dev;
554 #endif
555 	int busnum = 0;
556 	pci_dev_t bdf = 0;
557 	char cmd = 's';
558 	int ret = 0;
559 
560 	if (argc > 1)
561 		cmd = argv[1][0];
562 
563 	switch (cmd) {
564 	case 'd':		/* display */
565 	case 'n':		/* next */
566 	case 'm':		/* modify */
567 	case 'w':		/* write */
568 		/* Check for a size specification. */
569 		cmd_size = cmd_get_data_size(argv[1], 4);
570 		size = (cmd_size == 4) ? PCI_SIZE_32 : cmd_size - 1;
571 		if (argc > 3)
572 			addr = simple_strtoul(argv[3], NULL, 16);
573 		if (argc > 4)
574 			value = simple_strtoul(argv[4], NULL, 16);
575 	case 'h':		/* header */
576 		if (argc < 3)
577 			goto usage;
578 		if ((bdf = get_pci_dev(argv[2])) == -1)
579 			return 1;
580 		break;
581 #if defined(CONFIG_CMD_PCI_ENUM) || defined(CONFIG_DM_PCI)
582 	case 'e':
583 		pci_init();
584 		return 0;
585 #endif
586 	default:		/* scan bus */
587 		value = 1; /* short listing */
588 		if (argc > 1) {
589 			if (argv[argc-1][0] == 'l') {
590 				value = 0;
591 				argc--;
592 			}
593 			if (argc > 1)
594 				busnum = simple_strtoul(argv[1], NULL, 16);
595 		}
596 #ifdef CONFIG_DM_PCI
597 		ret = uclass_get_device_by_seq(UCLASS_PCI, busnum, &bus);
598 		if (ret) {
599 			printf("No such bus\n");
600 			return CMD_RET_FAILURE;
601 		}
602 		pciinfo(bus, value);
603 #else
604 		pciinfo(busnum, value);
605 #endif
606 		return 0;
607 	}
608 
609 #ifdef CONFIG_DM_PCI
610 	ret = dm_pci_bus_find_bdf(bdf, &dev);
611 	if (ret) {
612 		printf("No such device\n");
613 		return CMD_RET_FAILURE;
614 	}
615 #else
616 	dev = bdf;
617 #endif
618 
619 	switch (argv[1][0]) {
620 	case 'h':		/* header */
621 		pci_header_show(dev);
622 		break;
623 	case 'd':		/* display */
624 		return pci_cfg_display(dev, addr, size, value);
625 	case 'n':		/* next */
626 		if (argc < 4)
627 			goto usage;
628 		ret = pci_cfg_modify(dev, addr, size, value, 0);
629 		break;
630 	case 'm':		/* modify */
631 		if (argc < 4)
632 			goto usage;
633 		ret = pci_cfg_modify(dev, addr, size, value, 1);
634 		break;
635 	case 'w':		/* write */
636 		if (argc < 5)
637 			goto usage;
638 #ifdef CONFIG_DM_PCI
639 		ret = dm_pci_write_config(dev, addr, value, size);
640 #else
641 		ret = pci_cfg_write(dev, addr, size, value);
642 #endif
643 		break;
644 	default:
645 		ret = CMD_RET_USAGE;
646 		break;
647 	}
648 
649 	return ret;
650  usage:
651 	return CMD_RET_USAGE;
652 }
653 
654 /***************************************************/
655 
656 #ifdef CONFIG_SYS_LONGHELP
657 static char pci_help_text[] =
658 	"[bus] [long]\n"
659 	"    - short or long list of PCI devices on bus 'bus'\n"
660 #if defined(CONFIG_CMD_PCI_ENUM) || defined(CONFIG_DM_PCI)
661 	"pci enum\n"
662 	"    - Enumerate PCI buses\n"
663 #endif
664 	"pci header b.d.f\n"
665 	"    - show header of PCI device 'bus.device.function'\n"
666 	"pci display[.b, .w, .l] b.d.f [address] [# of objects]\n"
667 	"    - display PCI configuration space (CFG)\n"
668 	"pci next[.b, .w, .l] b.d.f address\n"
669 	"    - modify, read and keep CFG address\n"
670 	"pci modify[.b, .w, .l] b.d.f address\n"
671 	"    -  modify, auto increment CFG address\n"
672 	"pci write[.b, .w, .l] b.d.f address value\n"
673 	"    - write to CFG address";
674 #endif
675 
676 U_BOOT_CMD(
677 	pci,	5,	1,	do_pci,
678 	"list and access PCI Configuration Space", pci_help_text
679 );
680