pci: Refactor the pciinfo() function
[oweals/u-boot.git] / 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 /*
26  * Follows routines for the output of infos about devices on PCI bus.
27  */
28
29 void pci_header_show(pci_dev_t dev);
30 void pci_header_show_brief(pci_dev_t dev);
31
32 /*
33  * Subroutine:  pciinfo
34  *
35  * Description: Show information about devices on PCI bus.
36  *                              Depending on the define CONFIG_SYS_SHORT_PCI_LISTING
37  *                              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  */
44 void pciinfo(int BusNum, int ShortPCIListing)
45 {
46         struct pci_controller *hose = pci_bus_to_hose(BusNum);
47         int Device;
48         int Function;
49         unsigned char HeaderType;
50         unsigned short VendorID;
51         pci_dev_t dev;
52         int ret;
53
54         if (!hose)
55                 return;
56
57         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
76                         if (pci_skip_dev(hose, dev))
77                                 continue;
78
79                         ret = pci_read_config_word(dev, PCI_VENDOR_ID,
80                                                    &VendorID);
81                         if (ret)
82                                 goto error;
83                         if ((VendorID == 0xFFFF) || (VendorID == 0x0000))
84                                 continue;
85
86                         if (!Function) pci_read_config_byte(dev, PCI_HEADER_TYPE, &HeaderType);
87
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                         }
99                 }
100         }
101
102         return;
103 error:
104         printf("Cannot read bus configuration: %d\n", ret);
105 }
106
107
108 /*
109  * Subroutine:  pci_header_show_brief
110  *
111  * Description: Reads and prints the header of the
112  *              specified PCI device in short form.
113  *
114  * Inputs:      dev      Bus+Device+Function number
115  *
116  * Return:      None
117  *
118  */
119 void 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
129         printf("0x%.4x     0x%.4x     %-23s 0x%.2x\n",
130                vendor, device,
131                pci_class_str(class), subclass);
132 }
133
134 struct pci_reg_info {
135         const char *name;
136         enum pci_size_t size;
137         u8 offset;
138 };
139
140 static 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
153 static 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
174 static 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
184 static 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
193 static 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
204 static 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
221 static 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
245 static 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
273 /*
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  */
283 void pci_header_show(pci_dev_t dev)
284 {
285         u8 class, header_type;
286
287         pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
288         pci_show_regs(dev, regs_start);
289
290         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);
294
295         switch (header_type & 0x03) {
296         case PCI_HEADER_TYPE_NORMAL:    /* "normal" PCI device */
297                 pci_show_regs(dev, regs_normal);
298                 break;
299         case PCI_HEADER_TYPE_BRIDGE:    /* PCI-to-PCI bridge */
300                 pci_show_regs(dev, regs_bridge);
301                 break;
302         case PCI_HEADER_TYPE_CARDBUS:   /* PCI-to-CardBus bridge */
303                 pci_show_regs(dev, regs_cardbus);
304                 break;
305
306         default:
307                 printf("unknown header\n");
308                 break;
309     }
310 }
311
312 /* Convert the "bus.device.function" identifier into a number.
313  */
314 static 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
338 static 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
382 static 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
398 static int
399 pci_cfg_modify (pci_dev_t bdf, ulong addr, ulong size, ulong value, int incrflag)
400 {
401         ulong   i;
402         int     nbytes;
403         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
425                 nbytes = cli_readline(" ? ");
426                 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;
433                         /* good enough to not time out */
434                         bootretry_reset_cmd_timeout();
435                 }
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) {
446                                 /* good enough to not time out
447                                  */
448                                 bootretry_reset_cmd_timeout();
449                                 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  */
467 static int do_pci(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
468 {
469         ulong addr = 0, value = 0, size = 0;
470         int busnum = 0;
471         pci_dev_t bdf = 0;
472         char cmd = 's';
473         int ret = 0;
474
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;
495 #ifdef CONFIG_CMD_PCI_ENUM
496         case 'e':
497                 break;
498 #endif
499         default:                /* scan bus */
500                 value = 1; /* short listing */
501                 if (argc > 1) {
502                         if (argv[argc-1][0] == 'l') {
503                                 value = 0;
504                                 argc--;
505                         }
506                         if (argc > 1)
507                                 busnum = simple_strtoul(argv[1], NULL, 16);
508                 }
509                 pciinfo(busnum, value);
510                 return 0;
511         }
512
513         switch (argv[1][0]) {
514         case 'h':               /* header */
515                 pci_header_show(bdf);
516                 break;
517         case 'd':               /* display */
518                 return pci_cfg_display(bdf, addr, size, value);
519 #ifdef CONFIG_CMD_PCI_ENUM
520         case 'e':
521 # ifdef CONFIG_DM_PCI
522                 printf("This command is not yet supported with driver model\n");
523 # else
524                 pci_init();
525 # endif
526                 break;
527 #endif
528         case 'n':               /* next */
529                 if (argc < 4)
530                         goto usage;
531                 ret = pci_cfg_modify(bdf, addr, size, value, 0);
532                 break;
533         case 'm':               /* modify */
534                 if (argc < 4)
535                         goto usage;
536                 ret = pci_cfg_modify(bdf, addr, size, value, 1);
537                 break;
538         case 'w':               /* write */
539                 if (argc < 5)
540                         goto usage;
541                 ret = pci_cfg_write(bdf, addr, size, value);
542                 break;
543         default:
544                 ret = CMD_RET_USAGE;
545                 break;
546         }
547
548         return ret;
549  usage:
550         return CMD_RET_USAGE;
551 }
552
553 /***************************************************/
554
555 #ifdef CONFIG_SYS_LONGHELP
556 static char pci_help_text[] =
557         "[bus] [long]\n"
558         "    - short or long list of PCI devices on bus 'bus'\n"
559 #ifdef CONFIG_CMD_PCI_ENUM
560         "pci enum\n"
561         "    - re-enumerate PCI buses\n"
562 #endif
563         "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"
572         "    - write to CFG address";
573 #endif
574
575 U_BOOT_CMD(
576         pci,    5,      1,      do_pci,
577         "list and access PCI Configuration Space", pci_help_text
578 );