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