blob: 190e3b620df060f7bee706748c5ad9bc4241ba1e [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
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 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02009 * SPDX-License-Identifier: GPL-2.0+
wdenkc6097192002-11-03 00:24:07 +000010 */
11
12/*
13 * PCI routines
14 */
15
16#include <common.h>
Simon Glass0098e172014-04-10 20:01:30 -060017#include <bootretry.h>
Simon Glass18d66532014-04-10 20:01:25 -060018#include <cli.h>
wdenkc6097192002-11-03 00:24:07 +000019#include <command.h>
Simon Glass24b852a2015-11-08 23:47:45 -070020#include <console.h>
wdenkc6097192002-11-03 00:24:07 +000021#include <asm/processor.h>
22#include <asm/io.h>
wdenkc6097192002-11-03 00:24:07 +000023#include <pci.h>
24
wdenkc6097192002-11-03 00:24:07 +000025/*
26 * Follows routines for the output of infos about devices on PCI bus.
27 */
28
29void pci_header_show(pci_dev_t dev);
30void pci_header_show_brief(pci_dev_t dev);
31
32/*
33 * Subroutine: pciinfo
34 *
35 * Description: Show information about devices on PCI bus.
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020036 * Depending on the define CONFIG_SYS_SHORT_PCI_LISTING
wdenkc6097192002-11-03 00:24:07 +000037 * the output will be more or less exhaustive.
38 *
39 * Inputs: bus_no the number of the bus to be scanned.
40 *
41 * Return: None
42 *
43 */
44void pciinfo(int BusNum, int ShortPCIListing)
45{
Thierry Reding042b83d2014-11-12 18:26:48 -070046 struct pci_controller *hose = pci_bus_to_hose(BusNum);
wdenkc6097192002-11-03 00:24:07 +000047 int Device;
48 int Function;
49 unsigned char HeaderType;
50 unsigned short VendorID;
51 pci_dev_t dev;
Simon Glassff3e0772015-03-05 12:25:25 -070052 int ret;
wdenkc6097192002-11-03 00:24:07 +000053
Thierry Reding042b83d2014-11-12 18:26:48 -070054 if (!hose)
55 return;
56
wdenkc6097192002-11-03 00:24:07 +000057 printf("Scanning PCI devices on bus %d\n", BusNum);
58
59 if (ShortPCIListing) {
60 printf("BusDevFun VendorId DeviceId Device Class Sub-Class\n");
61 printf("_____________________________________________________________\n");
62 }
63
64 for (Device = 0; Device < PCI_MAX_PCI_DEVICES; Device++) {
65 HeaderType = 0;
66 VendorID = 0;
67 for (Function = 0; Function < PCI_MAX_PCI_FUNCTIONS; Function++) {
68 /*
69 * If this is not a multi-function device, we skip the rest.
70 */
71 if (Function && !(HeaderType & 0x80))
72 break;
73
74 dev = PCI_BDF(BusNum, Device, Function);
75
Thierry Reding4efe52b2014-11-12 18:26:49 -070076 if (pci_skip_dev(hose, dev))
77 continue;
78
Simon Glassff3e0772015-03-05 12:25:25 -070079 ret = pci_read_config_word(dev, PCI_VENDOR_ID,
80 &VendorID);
81 if (ret)
82 goto error;
wdenkc6097192002-11-03 00:24:07 +000083 if ((VendorID == 0xFFFF) || (VendorID == 0x0000))
84 continue;
85
wdenkc7de8292002-11-19 11:04:11 +000086 if (!Function) pci_read_config_byte(dev, PCI_HEADER_TYPE, &HeaderType);
wdenkc6097192002-11-03 00:24:07 +000087
88 if (ShortPCIListing)
89 {
90 printf("%02x.%02x.%02x ", BusNum, Device, Function);
91 pci_header_show_brief(dev);
92 }
93 else
94 {
95 printf("\nFound PCI device %02x.%02x.%02x:\n",
96 BusNum, Device, Function);
97 pci_header_show(dev);
98 }
Simon Glassff3e0772015-03-05 12:25:25 -070099 }
100 }
101
102 return;
103error:
104 printf("Cannot read bus configuration: %d\n", ret);
wdenkc6097192002-11-03 00:24:07 +0000105}
106
wdenkc6097192002-11-03 00:24:07 +0000107
108/*
109 * Subroutine: pci_header_show_brief
110 *
111 * Description: Reads and prints the header of the
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200112 * specified PCI device in short form.
wdenkc6097192002-11-03 00:24:07 +0000113 *
114 * Inputs: dev Bus+Device+Function number
115 *
116 * Return: None
117 *
118 */
119void pci_header_show_brief(pci_dev_t dev)
120{
121 u16 vendor, device;
122 u8 class, subclass;
123
124 pci_read_config_word(dev, PCI_VENDOR_ID, &vendor);
125 pci_read_config_word(dev, PCI_DEVICE_ID, &device);
126 pci_read_config_byte(dev, PCI_CLASS_CODE, &class);
127 pci_read_config_byte(dev, PCI_CLASS_SUB_CODE, &subclass);
128
wdenk5d232d02003-05-22 22:52:13 +0000129 printf("0x%.4x 0x%.4x %-23s 0x%.2x\n",
wdenkc6097192002-11-03 00:24:07 +0000130 vendor, device,
Peter Tyser983eb9d2010-10-29 17:59:27 -0500131 pci_class_str(class), subclass);
wdenkc6097192002-11-03 00:24:07 +0000132}
133
Simon Glass07a58872015-11-26 19:51:20 -0700134struct pci_reg_info {
135 const char *name;
136 enum pci_size_t size;
137 u8 offset;
138};
139
140static int pci_field_width(enum pci_size_t size)
141{
142 switch (size) {
143 case PCI_SIZE_8:
144 return 2;
145 case PCI_SIZE_16:
146 return 4;
147 case PCI_SIZE_32:
148 default:
149 return 8;
150 }
151}
152
153static unsigned long pci_read_config(pci_dev_t dev, int offset,
154 enum pci_size_t size)
155{
156 u32 val32;
157 u16 val16;
158 u8 val8;
159
160 switch (size) {
161 case PCI_SIZE_8:
162 pci_read_config_byte(dev, offset, &val8);
163 return val8;
164 case PCI_SIZE_16:
165 pci_read_config_word(dev, offset, &val16);
166 return val16;
167 case PCI_SIZE_32:
168 default:
169 pci_read_config_dword(dev, offset, &val32);
170 return val32;
171 }
172}
173
174static void pci_show_regs(pci_dev_t dev, struct pci_reg_info *regs)
175{
176 for (; regs->name; regs++) {
177 printf(" %s =%*s%#.*lx\n", regs->name,
178 (int)(28 - strlen(regs->name)), "",
179 pci_field_width(regs->size),
180 pci_read_config(dev, regs->offset, regs->size));
181 }
182}
183
184static struct pci_reg_info regs_start[] = {
185 { "vendor ID", PCI_SIZE_16, PCI_VENDOR_ID },
186 { "device ID", PCI_SIZE_16, PCI_DEVICE_ID },
187 { "command register ID", PCI_SIZE_16, PCI_COMMAND },
188 { "status register", PCI_SIZE_16, PCI_STATUS },
189 { "revision ID", PCI_SIZE_8, PCI_REVISION_ID },
190 {},
191};
192
193static struct pci_reg_info regs_rest[] = {
194 { "sub class code", PCI_SIZE_8, PCI_CLASS_SUB_CODE },
195 { "programming interface", PCI_SIZE_8, PCI_CLASS_PROG },
196 { "cache line", PCI_SIZE_8, PCI_CACHE_LINE_SIZE },
197 { "latency time", PCI_SIZE_8, PCI_LATENCY_TIMER },
198 { "header type", PCI_SIZE_8, PCI_HEADER_TYPE },
199 { "BIST", PCI_SIZE_8, PCI_BIST },
200 { "base address 0", PCI_SIZE_32, PCI_BASE_ADDRESS_0 },
201 {},
202};
203
204static struct pci_reg_info regs_normal[] = {
205 { "base address 1", PCI_SIZE_32, PCI_BASE_ADDRESS_1 },
206 { "base address 2", PCI_SIZE_32, PCI_BASE_ADDRESS_2 },
207 { "base address 3", PCI_SIZE_32, PCI_BASE_ADDRESS_3 },
208 { "base address 4", PCI_SIZE_32, PCI_BASE_ADDRESS_4 },
209 { "base address 5", PCI_SIZE_32, PCI_BASE_ADDRESS_5 },
210 { "cardBus CIS pointer", PCI_SIZE_32, PCI_CARDBUS_CIS },
211 { "sub system vendor ID", PCI_SIZE_16, PCI_SUBSYSTEM_VENDOR_ID },
212 { "sub system ID", PCI_SIZE_16, PCI_SUBSYSTEM_ID },
213 { "expansion ROM base address", PCI_SIZE_32, PCI_ROM_ADDRESS },
214 { "interrupt line", PCI_SIZE_8, PCI_INTERRUPT_LINE },
215 { "interrupt pin", PCI_SIZE_8, PCI_INTERRUPT_PIN },
216 { "min Grant", PCI_SIZE_8, PCI_MIN_GNT },
217 { "max Latency", PCI_SIZE_8, PCI_MAX_LAT },
218 {},
219};
220
221static struct pci_reg_info regs_bridge[] = {
222 { "base address 1", PCI_SIZE_32, PCI_BASE_ADDRESS_1 },
223 { "primary bus number", PCI_SIZE_8, PCI_PRIMARY_BUS },
224 { "secondary bus number", PCI_SIZE_8, PCI_SECONDARY_BUS },
225 { "subordinate bus number", PCI_SIZE_8, PCI_SUBORDINATE_BUS },
226 { "secondary latency timer", PCI_SIZE_8, PCI_SEC_LATENCY_TIMER },
227 { "IO base", PCI_SIZE_8, PCI_IO_BASE },
228 { "IO limit", PCI_SIZE_8, PCI_IO_LIMIT },
229 { "secondary status", PCI_SIZE_16, PCI_SEC_STATUS },
230 { "memory base", PCI_SIZE_16, PCI_MEMORY_BASE },
231 { "memory limit", PCI_SIZE_16, PCI_MEMORY_LIMIT },
232 { "prefetch memory base", PCI_SIZE_16, PCI_PREF_MEMORY_BASE },
233 { "prefetch memory limit", PCI_SIZE_16, PCI_PREF_MEMORY_LIMIT },
234 { "prefetch memory base upper", PCI_SIZE_32, PCI_PREF_BASE_UPPER32 },
235 { "prefetch memory limit upper", PCI_SIZE_32, PCI_PREF_LIMIT_UPPER32 },
236 { "IO base upper 16 bits", PCI_SIZE_16, PCI_IO_BASE_UPPER16 },
237 { "IO limit upper 16 bits", PCI_SIZE_16, PCI_IO_LIMIT_UPPER16 },
238 { "expansion ROM base address", PCI_SIZE_32, PCI_ROM_ADDRESS1 },
239 { "interrupt line", PCI_SIZE_8, PCI_INTERRUPT_LINE },
240 { "interrupt pin", PCI_SIZE_8, PCI_INTERRUPT_PIN },
241 { "bridge control", PCI_SIZE_16, PCI_BRIDGE_CONTROL },
242 {},
243};
244
245static struct pci_reg_info regs_cardbus[] = {
246 { "capabilities", PCI_SIZE_8, PCI_CB_CAPABILITY_LIST },
247 { "secondary status", PCI_SIZE_16, PCI_CB_SEC_STATUS },
248 { "primary bus number", PCI_SIZE_8, PCI_CB_PRIMARY_BUS },
249 { "CardBus number", PCI_SIZE_8, PCI_CB_CARD_BUS },
250 { "subordinate bus number", PCI_SIZE_8, PCI_CB_SUBORDINATE_BUS },
251 { "CardBus latency timer", PCI_SIZE_8, PCI_CB_LATENCY_TIMER },
252 { "CardBus memory base 0", PCI_SIZE_32, PCI_CB_MEMORY_BASE_0 },
253 { "CardBus memory limit 0", PCI_SIZE_32, PCI_CB_MEMORY_LIMIT_0 },
254 { "CardBus memory base 1", PCI_SIZE_32, PCI_CB_MEMORY_BASE_1 },
255 { "CardBus memory limit 1", PCI_SIZE_32, PCI_CB_MEMORY_LIMIT_1 },
256 { "CardBus IO base 0", PCI_SIZE_16, PCI_CB_IO_BASE_0 },
257 { "CardBus IO base high 0", PCI_SIZE_16, PCI_CB_IO_BASE_0_HI },
258 { "CardBus IO limit 0", PCI_SIZE_16, PCI_CB_IO_LIMIT_0 },
259 { "CardBus IO limit high 0", PCI_SIZE_16, PCI_CB_IO_LIMIT_0_HI },
260 { "CardBus IO base 1", PCI_SIZE_16, PCI_CB_IO_BASE_1 },
261 { "CardBus IO base high 1", PCI_SIZE_16, PCI_CB_IO_BASE_1_HI },
262 { "CardBus IO limit 1", PCI_SIZE_16, PCI_CB_IO_LIMIT_1 },
263 { "CardBus IO limit high 1", PCI_SIZE_16, PCI_CB_IO_LIMIT_1_HI },
264 { "interrupt line", PCI_SIZE_8, PCI_INTERRUPT_LINE },
265 { "interrupt pin", PCI_SIZE_8, PCI_INTERRUPT_PIN },
266 { "bridge control", PCI_SIZE_16, PCI_CB_BRIDGE_CONTROL },
267 { "subvendor ID", PCI_SIZE_16, PCI_CB_SUBSYSTEM_VENDOR_ID },
268 { "subdevice ID", PCI_SIZE_16, PCI_CB_SUBSYSTEM_ID },
269 { "PC Card 16bit base address", PCI_SIZE_32, PCI_CB_LEGACY_MODE_BASE },
270 {},
271};
272
wdenkc6097192002-11-03 00:24:07 +0000273/*
274 * Subroutine: PCI_Header_Show
275 *
276 * Description: Reads the header of the specified PCI device.
277 *
278 * Inputs: BusDevFunc Bus+Device+Function number
279 *
280 * Return: None
281 *
282 */
283void pci_header_show(pci_dev_t dev)
284{
Simon Glass07a58872015-11-26 19:51:20 -0700285 u8 class, header_type;
wdenkc6097192002-11-03 00:24:07 +0000286
287 pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
Simon Glass07a58872015-11-26 19:51:20 -0700288 pci_show_regs(dev, regs_start);
wdenkc6097192002-11-03 00:24:07 +0000289
Simon Glass07a58872015-11-26 19:51:20 -0700290 pci_read_config_byte(dev, PCI_CLASS_CODE, &class);
291 printf(" class code = 0x%.2x (%s)\n", class,
292 pci_class_str(class));
293 pci_show_regs(dev, regs_rest);
wdenkc6097192002-11-03 00:24:07 +0000294
wdenk7c7a23b2002-12-07 00:20:59 +0000295 switch (header_type & 0x03) {
296 case PCI_HEADER_TYPE_NORMAL: /* "normal" PCI device */
Simon Glass07a58872015-11-26 19:51:20 -0700297 pci_show_regs(dev, regs_normal);
wdenk7c7a23b2002-12-07 00:20:59 +0000298 break;
wdenk7c7a23b2002-12-07 00:20:59 +0000299 case PCI_HEADER_TYPE_BRIDGE: /* PCI-to-PCI bridge */
Simon Glass07a58872015-11-26 19:51:20 -0700300 pci_show_regs(dev, regs_bridge);
wdenk7c7a23b2002-12-07 00:20:59 +0000301 break;
wdenk7c7a23b2002-12-07 00:20:59 +0000302 case PCI_HEADER_TYPE_CARDBUS: /* PCI-to-CardBus bridge */
Simon Glass07a58872015-11-26 19:51:20 -0700303 pci_show_regs(dev, regs_cardbus);
wdenk7c7a23b2002-12-07 00:20:59 +0000304 break;
wdenk8bde7f72003-06-27 21:31:46 +0000305
wdenk7c7a23b2002-12-07 00:20:59 +0000306 default:
307 printf("unknown header\n");
wdenk8bde7f72003-06-27 21:31:46 +0000308 break;
wdenkc6097192002-11-03 00:24:07 +0000309 }
wdenkc6097192002-11-03 00:24:07 +0000310}
311
312/* Convert the "bus.device.function" identifier into a number.
313 */
314static pci_dev_t get_pci_dev(char* name)
315{
316 char cnum[12];
317 int len, i, iold, n;
318 int bdfs[3] = {0,0,0};
319
320 len = strlen(name);
321 if (len > 8)
322 return -1;
323 for (i = 0, iold = 0, n = 0; i < len; i++) {
324 if (name[i] == '.') {
325 memcpy(cnum, &name[iold], i - iold);
326 cnum[i - iold] = '\0';
327 bdfs[n++] = simple_strtoul(cnum, NULL, 16);
328 iold = i + 1;
329 }
330 }
331 strcpy(cnum, &name[iold]);
332 if (n == 0)
333 n = 1;
334 bdfs[n] = simple_strtoul(cnum, NULL, 16);
335 return PCI_BDF(bdfs[0], bdfs[1], bdfs[2]);
336}
337
338static int pci_cfg_display(pci_dev_t bdf, ulong addr, ulong size, ulong length)
339{
340#define DISP_LINE_LEN 16
341 ulong i, nbytes, linebytes;
342 int rc = 0;
343
344 if (length == 0)
345 length = 0x40 / size; /* Standard PCI configuration space */
346
347 /* Print the lines.
348 * once, and all accesses are with the specified bus width.
349 */
350 nbytes = length * size;
351 do {
352 uint val4;
353 ushort val2;
354 u_char val1;
355
356 printf("%08lx:", addr);
357 linebytes = (nbytes>DISP_LINE_LEN)?DISP_LINE_LEN:nbytes;
358 for (i=0; i<linebytes; i+= size) {
359 if (size == 4) {
360 pci_read_config_dword(bdf, addr, &val4);
361 printf(" %08x", val4);
362 } else if (size == 2) {
363 pci_read_config_word(bdf, addr, &val2);
364 printf(" %04x", val2);
365 } else {
366 pci_read_config_byte(bdf, addr, &val1);
367 printf(" %02x", val1);
368 }
369 addr += size;
370 }
371 printf("\n");
372 nbytes -= linebytes;
373 if (ctrlc()) {
374 rc = 1;
375 break;
376 }
377 } while (nbytes > 0);
378
379 return (rc);
380}
381
382static int pci_cfg_write (pci_dev_t bdf, ulong addr, ulong size, ulong value)
383{
384 if (size == 4) {
385 pci_write_config_dword(bdf, addr, value);
386 }
387 else if (size == 2) {
388 ushort val = value & 0xffff;
389 pci_write_config_word(bdf, addr, val);
390 }
391 else {
392 u_char val = value & 0xff;
393 pci_write_config_byte(bdf, addr, val);
394 }
395 return 0;
396}
397
398static int
399pci_cfg_modify (pci_dev_t bdf, ulong addr, ulong size, ulong value, int incrflag)
400{
401 ulong i;
402 int nbytes;
wdenkc6097192002-11-03 00:24:07 +0000403 uint val4;
404 ushort val2;
405 u_char val1;
406
407 /* Print the address, followed by value. Then accept input for
408 * the next value. A non-converted value exits.
409 */
410 do {
411 printf("%08lx:", addr);
412 if (size == 4) {
413 pci_read_config_dword(bdf, addr, &val4);
414 printf(" %08x", val4);
415 }
416 else if (size == 2) {
417 pci_read_config_word(bdf, addr, &val2);
418 printf(" %04x", val2);
419 }
420 else {
421 pci_read_config_byte(bdf, addr, &val1);
422 printf(" %02x", val1);
423 }
424
Simon Glasse1bf8242014-04-10 20:01:27 -0600425 nbytes = cli_readline(" ? ");
wdenkc6097192002-11-03 00:24:07 +0000426 if (nbytes == 0 || (nbytes == 1 && console_buffer[0] == '-')) {
427 /* <CR> pressed as only input, don't modify current
428 * location and move to next. "-" pressed will go back.
429 */
430 if (incrflag)
431 addr += nbytes ? -size : size;
432 nbytes = 1;
Simon Glassb26440f2014-04-10 20:01:31 -0600433 /* good enough to not time out */
434 bootretry_reset_cmd_timeout();
wdenkc6097192002-11-03 00:24:07 +0000435 }
436#ifdef CONFIG_BOOT_RETRY_TIME
437 else if (nbytes == -2) {
438 break; /* timed out, exit the command */
439 }
440#endif
441 else {
442 char *endp;
443 i = simple_strtoul(console_buffer, &endp, 16);
444 nbytes = endp - console_buffer;
445 if (nbytes) {
wdenkc6097192002-11-03 00:24:07 +0000446 /* good enough to not time out
447 */
Simon Glassb26440f2014-04-10 20:01:31 -0600448 bootretry_reset_cmd_timeout();
wdenkc6097192002-11-03 00:24:07 +0000449 pci_cfg_write (bdf, addr, size, i);
450 if (incrflag)
451 addr += size;
452 }
453 }
454 } while (nbytes);
455
456 return 0;
457}
458
459/* PCI Configuration Space access commands
460 *
461 * Syntax:
462 * pci display[.b, .w, .l] bus.device.function} [addr] [len]
463 * pci next[.b, .w, .l] bus.device.function [addr]
464 * pci modify[.b, .w, .l] bus.device.function [addr]
465 * pci write[.b, .w, .l] bus.device.function addr value
466 */
Kim Phillips088f1b12012-10-29 13:34:31 +0000467static int do_pci(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
wdenkc6097192002-11-03 00:24:07 +0000468{
469 ulong addr = 0, value = 0, size = 0;
Simon Glassca7de762015-11-26 19:51:19 -0700470 int busnum = 0;
wdenkc6097192002-11-03 00:24:07 +0000471 pci_dev_t bdf = 0;
472 char cmd = 's';
Simon Glassbfa41912015-11-26 19:51:18 -0700473 int ret = 0;
wdenkc6097192002-11-03 00:24:07 +0000474
475 if (argc > 1)
476 cmd = argv[1][0];
477
478 switch (cmd) {
479 case 'd': /* display */
480 case 'n': /* next */
481 case 'm': /* modify */
482 case 'w': /* write */
483 /* Check for a size specification. */
484 size = cmd_get_data_size(argv[1], 4);
485 if (argc > 3)
486 addr = simple_strtoul(argv[3], NULL, 16);
487 if (argc > 4)
488 value = simple_strtoul(argv[4], NULL, 16);
489 case 'h': /* header */
490 if (argc < 3)
491 goto usage;
492 if ((bdf = get_pci_dev(argv[2])) == -1)
493 return 1;
494 break;
John Schmoller96d61602010-10-22 00:20:23 -0500495#ifdef CONFIG_CMD_PCI_ENUM
496 case 'e':
497 break;
498#endif
wdenkc6097192002-11-03 00:24:07 +0000499 default: /* scan bus */
500 value = 1; /* short listing */
wdenkc6097192002-11-03 00:24:07 +0000501 if (argc > 1) {
502 if (argv[argc-1][0] == 'l') {
503 value = 0;
504 argc--;
505 }
506 if (argc > 1)
Simon Glassca7de762015-11-26 19:51:19 -0700507 busnum = simple_strtoul(argv[1], NULL, 16);
wdenkc6097192002-11-03 00:24:07 +0000508 }
Simon Glassca7de762015-11-26 19:51:19 -0700509 pciinfo(busnum, value);
wdenkc6097192002-11-03 00:24:07 +0000510 return 0;
511 }
512
513 switch (argv[1][0]) {
514 case 'h': /* header */
515 pci_header_show(bdf);
Simon Glassbfa41912015-11-26 19:51:18 -0700516 break;
wdenkc6097192002-11-03 00:24:07 +0000517 case 'd': /* display */
518 return pci_cfg_display(bdf, addr, size, value);
John Schmoller96d61602010-10-22 00:20:23 -0500519#ifdef CONFIG_CMD_PCI_ENUM
520 case 'e':
Simon Glass871bc922015-11-19 20:26:56 -0700521# ifdef CONFIG_DM_PCI
522 printf("This command is not yet supported with driver model\n");
523# else
John Schmoller96d61602010-10-22 00:20:23 -0500524 pci_init();
Simon Glass871bc922015-11-19 20:26:56 -0700525# endif
Simon Glassbfa41912015-11-26 19:51:18 -0700526 break;
John Schmoller96d61602010-10-22 00:20:23 -0500527#endif
wdenkc6097192002-11-03 00:24:07 +0000528 case 'n': /* next */
529 if (argc < 4)
530 goto usage;
Simon Glassbfa41912015-11-26 19:51:18 -0700531 ret = pci_cfg_modify(bdf, addr, size, value, 0);
532 break;
wdenkc6097192002-11-03 00:24:07 +0000533 case 'm': /* modify */
534 if (argc < 4)
535 goto usage;
Simon Glassbfa41912015-11-26 19:51:18 -0700536 ret = pci_cfg_modify(bdf, addr, size, value, 1);
537 break;
wdenkc6097192002-11-03 00:24:07 +0000538 case 'w': /* write */
539 if (argc < 5)
540 goto usage;
Simon Glassbfa41912015-11-26 19:51:18 -0700541 ret = pci_cfg_write(bdf, addr, size, value);
542 break;
543 default:
544 ret = CMD_RET_USAGE;
545 break;
wdenkc6097192002-11-03 00:24:07 +0000546 }
547
Simon Glassbfa41912015-11-26 19:51:18 -0700548 return ret;
wdenkc6097192002-11-03 00:24:07 +0000549 usage:
Simon Glass4c12eeb2011-12-10 08:44:01 +0000550 return CMD_RET_USAGE;
wdenkc6097192002-11-03 00:24:07 +0000551}
552
wdenk8bde7f72003-06-27 21:31:46 +0000553/***************************************************/
554
Kim Phillips088f1b12012-10-29 13:34:31 +0000555#ifdef CONFIG_SYS_LONGHELP
556static char pci_help_text[] =
wdenk8bde7f72003-06-27 21:31:46 +0000557 "[bus] [long]\n"
558 " - short or long list of PCI devices on bus 'bus'\n"
John Schmoller96d61602010-10-22 00:20:23 -0500559#ifdef CONFIG_CMD_PCI_ENUM
560 "pci enum\n"
561 " - re-enumerate PCI buses\n"
562#endif
wdenk8bde7f72003-06-27 21:31:46 +0000563 "pci header b.d.f\n"
564 " - show header of PCI device 'bus.device.function'\n"
565 "pci display[.b, .w, .l] b.d.f [address] [# of objects]\n"
566 " - display PCI configuration space (CFG)\n"
567 "pci next[.b, .w, .l] b.d.f address\n"
568 " - modify, read and keep CFG address\n"
569 "pci modify[.b, .w, .l] b.d.f address\n"
570 " - modify, auto increment CFG address\n"
571 "pci write[.b, .w, .l] b.d.f address value\n"
Kim Phillips088f1b12012-10-29 13:34:31 +0000572 " - write to CFG address";
573#endif
574
575U_BOOT_CMD(
576 pci, 5, 1, do_pci,
577 "list and access PCI Configuration Space", pci_help_text
wdenk8bde7f72003-06-27 21:31:46 +0000578);