xref: /openbmc/u-boot/cmd/pci.c (revision 70341e2ed9a0ff98a777febb7b56dbcee4d885c4)
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