]> git.sur5r.net Git - u-boot/blob - common/cmd_pci.c
dm: pci: Reorder functions 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  * Subroutine:  PCI_Header_Show
166  *
167  * Description: Reads the header of the specified PCI device.
168  *
169  * Inputs:              BusDevFunc      Bus+Device+Function number
170  *
171  * Return:      None
172  *
173  */
174 void pci_header_show(pci_dev_t dev)
175 {
176         u8 class, header_type;
177
178         pci_read_config_byte(dev, PCI_CLASS_CODE, &class);
179         pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
180         pci_show_regs(dev, regs_start);
181
182         printf("  class code =                  0x%.2x (%s)\n", class,
183                pci_class_str(class));
184         pci_show_regs(dev, regs_rest);
185
186         switch (header_type & 0x03) {
187         case PCI_HEADER_TYPE_NORMAL:    /* "normal" PCI device */
188                 pci_show_regs(dev, regs_normal);
189                 break;
190         case PCI_HEADER_TYPE_BRIDGE:    /* PCI-to-PCI bridge */
191                 pci_show_regs(dev, regs_bridge);
192                 break;
193         case PCI_HEADER_TYPE_CARDBUS:   /* PCI-to-CardBus bridge */
194                 pci_show_regs(dev, regs_cardbus);
195                 break;
196
197         default:
198                 printf("unknown header\n");
199                 break;
200     }
201 }
202
203 /*
204  * Subroutine:  pci_header_show_brief
205  *
206  * Description: Reads and prints the header of the
207  *              specified PCI device in short form.
208  *
209  * Inputs:      dev      Bus+Device+Function number
210  *
211  * Return:      None
212  *
213  */
214 void pci_header_show_brief(pci_dev_t dev)
215 {
216         u16 vendor, device;
217         u8 class, subclass;
218
219         pci_read_config_word(dev, PCI_VENDOR_ID, &vendor);
220         pci_read_config_word(dev, PCI_DEVICE_ID, &device);
221         pci_read_config_byte(dev, PCI_CLASS_CODE, &class);
222         pci_read_config_byte(dev, PCI_CLASS_SUB_CODE, &subclass);
223
224         printf("0x%.4x     0x%.4x     %-23s 0x%.2x\n",
225                vendor, device,
226                pci_class_str(class), subclass);
227 }
228
229 /*
230  * Subroutine:  pciinfo
231  *
232  * Description: Show information about devices on PCI bus.
233  *              Depending on the defineCONFIG_SYS_SHORT_PCI_LISTING
234  *              the output will be more or less exhaustive.
235  *
236  * Inputs:      bus_no          the number of the bus to be scanned.
237  *
238  * Return:      None
239  *
240  */
241 void pciinfo(int bus_num, int short_pci_listing)
242 {
243         struct pci_controller *hose = pci_bus_to_hose(bus_num);
244         int Device;
245         int Function;
246         unsigned char HeaderType;
247         unsigned short VendorID;
248         pci_dev_t dev;
249         int ret;
250
251         if (!hose)
252                 return;
253
254         printf("Scanning PCI devices on bus %d\n", bus_num);
255
256         if (short_pci_listing) {
257                 printf("BusDevFun  VendorId   DeviceId   Device Class       Sub-Class\n");
258                 printf("_____________________________________________________________\n");
259         }
260
261         for (Device = 0; Device < PCI_MAX_PCI_DEVICES; Device++) {
262                 HeaderType = 0;
263                 VendorID = 0;
264                 for (Function = 0; Function < PCI_MAX_PCI_FUNCTIONS;
265                      Function++) {
266                         /*
267                          * If this is not a multi-function device, we skip
268                          * the rest.
269                          */
270                         if (Function && !(HeaderType & 0x80))
271                                 break;
272
273                         dev = PCI_BDF(bus_num, Device, Function);
274
275                         if (pci_skip_dev(hose, dev))
276                                 continue;
277
278                         ret = pci_read_config_word(dev, PCI_VENDOR_ID,
279                                                    &VendorID);
280                         if (ret)
281                                 goto error;
282                         if ((VendorID == 0xFFFF) || (VendorID == 0x0000))
283                                 continue;
284
285                         if (!Function) {
286                                 pci_read_config_byte(dev, PCI_HEADER_TYPE,
287                                                      &HeaderType);
288                         }
289
290                         if (short_pci_listing) {
291                                 printf("%02x.%02x.%02x   ", bus_num, Device,
292                                        Function);
293                                 pci_header_show_brief(dev);
294                         } else {
295                                 printf("\nFound PCI device %02x.%02x.%02x:\n",
296                                        bus_num, Device, Function);
297                                 pci_header_show(dev);
298                         }
299                 }
300         }
301
302         return;
303 error:
304         printf("Cannot read bus configuration: %d\n", ret);
305 }
306
307
308 /* Convert the "bus.device.function" identifier into a number.
309  */
310 static pci_dev_t get_pci_dev(char* name)
311 {
312         char cnum[12];
313         int len, i, iold, n;
314         int bdfs[3] = {0,0,0};
315
316         len = strlen(name);
317         if (len > 8)
318                 return -1;
319         for (i = 0, iold = 0, n = 0; i < len; i++) {
320                 if (name[i] == '.') {
321                         memcpy(cnum, &name[iold], i - iold);
322                         cnum[i - iold] = '\0';
323                         bdfs[n++] = simple_strtoul(cnum, NULL, 16);
324                         iold = i + 1;
325                 }
326         }
327         strcpy(cnum, &name[iold]);
328         if (n == 0)
329                 n = 1;
330         bdfs[n] = simple_strtoul(cnum, NULL, 16);
331         return PCI_BDF(bdfs[0], bdfs[1], bdfs[2]);
332 }
333
334 static int pci_cfg_display(pci_dev_t bdf, ulong addr, ulong size, ulong length)
335 {
336 #define DISP_LINE_LEN   16
337         ulong i, nbytes, linebytes;
338         int rc = 0;
339
340         if (length == 0)
341                 length = 0x40 / size; /* Standard PCI configuration space */
342
343         /* Print the lines.
344          * once, and all accesses are with the specified bus width.
345          */
346         nbytes = length * size;
347         do {
348                 uint    val4;
349                 ushort  val2;
350                 u_char  val1;
351
352                 printf("%08lx:", addr);
353                 linebytes = (nbytes>DISP_LINE_LEN)?DISP_LINE_LEN:nbytes;
354                 for (i=0; i<linebytes; i+= size) {
355                         if (size == 4) {
356                                 pci_read_config_dword(bdf, addr, &val4);
357                                 printf(" %08x", val4);
358                         } else if (size == 2) {
359                                 pci_read_config_word(bdf, addr, &val2);
360                                 printf(" %04x", val2);
361                         } else {
362                                 pci_read_config_byte(bdf, addr, &val1);
363                                 printf(" %02x", val1);
364                         }
365                         addr += size;
366                 }
367                 printf("\n");
368                 nbytes -= linebytes;
369                 if (ctrlc()) {
370                         rc = 1;
371                         break;
372                 }
373         } while (nbytes > 0);
374
375         return (rc);
376 }
377
378 static int pci_cfg_write (pci_dev_t bdf, ulong addr, ulong size, ulong value)
379 {
380         if (size == 4) {
381                 pci_write_config_dword(bdf, addr, value);
382         }
383         else if (size == 2) {
384                 ushort val = value & 0xffff;
385                 pci_write_config_word(bdf, addr, val);
386         }
387         else {
388                 u_char val = value & 0xff;
389                 pci_write_config_byte(bdf, addr, val);
390         }
391         return 0;
392 }
393
394 static int
395 pci_cfg_modify (pci_dev_t bdf, ulong addr, ulong size, ulong value, int incrflag)
396 {
397         ulong   i;
398         int     nbytes;
399         uint    val4;
400         ushort  val2;
401         u_char  val1;
402
403         /* Print the address, followed by value.  Then accept input for
404          * the next value.  A non-converted value exits.
405          */
406         do {
407                 printf("%08lx:", addr);
408                 if (size == 4) {
409                         pci_read_config_dword(bdf, addr, &val4);
410                         printf(" %08x", val4);
411                 }
412                 else if (size == 2) {
413                         pci_read_config_word(bdf, addr, &val2);
414                         printf(" %04x", val2);
415                 }
416                 else {
417                         pci_read_config_byte(bdf, addr, &val1);
418                         printf(" %02x", val1);
419                 }
420
421                 nbytes = cli_readline(" ? ");
422                 if (nbytes == 0 || (nbytes == 1 && console_buffer[0] == '-')) {
423                         /* <CR> pressed as only input, don't modify current
424                          * location and move to next. "-" pressed will go back.
425                          */
426                         if (incrflag)
427                                 addr += nbytes ? -size : size;
428                         nbytes = 1;
429                         /* good enough to not time out */
430                         bootretry_reset_cmd_timeout();
431                 }
432 #ifdef CONFIG_BOOT_RETRY_TIME
433                 else if (nbytes == -2) {
434                         break;  /* timed out, exit the command  */
435                 }
436 #endif
437                 else {
438                         char *endp;
439                         i = simple_strtoul(console_buffer, &endp, 16);
440                         nbytes = endp - console_buffer;
441                         if (nbytes) {
442                                 /* good enough to not time out
443                                  */
444                                 bootretry_reset_cmd_timeout();
445                                 pci_cfg_write (bdf, addr, size, i);
446                                 if (incrflag)
447                                         addr += size;
448                         }
449                 }
450         } while (nbytes);
451
452         return 0;
453 }
454
455 /* PCI Configuration Space access commands
456  *
457  * Syntax:
458  *      pci display[.b, .w, .l] bus.device.function} [addr] [len]
459  *      pci next[.b, .w, .l] bus.device.function [addr]
460  *      pci modify[.b, .w, .l] bus.device.function [addr]
461  *      pci write[.b, .w, .l] bus.device.function addr value
462  */
463 static int do_pci(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
464 {
465         ulong addr = 0, value = 0, size = 0;
466         int busnum = 0;
467         pci_dev_t bdf = 0;
468         char cmd = 's';
469         int ret = 0;
470
471         if (argc > 1)
472                 cmd = argv[1][0];
473
474         switch (cmd) {
475         case 'd':               /* display */
476         case 'n':               /* next */
477         case 'm':               /* modify */
478         case 'w':               /* write */
479                 /* Check for a size specification. */
480                 size = cmd_get_data_size(argv[1], 4);
481                 if (argc > 3)
482                         addr = simple_strtoul(argv[3], NULL, 16);
483                 if (argc > 4)
484                         value = simple_strtoul(argv[4], NULL, 16);
485         case 'h':               /* header */
486                 if (argc < 3)
487                         goto usage;
488                 if ((bdf = get_pci_dev(argv[2])) == -1)
489                         return 1;
490                 break;
491 #ifdef CONFIG_CMD_PCI_ENUM
492         case 'e':
493                 break;
494 #endif
495         default:                /* scan bus */
496                 value = 1; /* short listing */
497                 if (argc > 1) {
498                         if (argv[argc-1][0] == 'l') {
499                                 value = 0;
500                                 argc--;
501                         }
502                         if (argc > 1)
503                                 busnum = simple_strtoul(argv[1], NULL, 16);
504                 }
505                 pciinfo(busnum, value);
506                 return 0;
507         }
508
509         switch (argv[1][0]) {
510         case 'h':               /* header */
511                 pci_header_show(bdf);
512                 break;
513         case 'd':               /* display */
514                 return pci_cfg_display(bdf, addr, size, value);
515 #ifdef CONFIG_CMD_PCI_ENUM
516         case 'e':
517 # ifdef CONFIG_DM_PCI
518                 printf("This command is not yet supported with driver model\n");
519 # else
520                 pci_init();
521 # endif
522                 break;
523 #endif
524         case 'n':               /* next */
525                 if (argc < 4)
526                         goto usage;
527                 ret = pci_cfg_modify(bdf, addr, size, value, 0);
528                 break;
529         case 'm':               /* modify */
530                 if (argc < 4)
531                         goto usage;
532                 ret = pci_cfg_modify(bdf, addr, size, value, 1);
533                 break;
534         case 'w':               /* write */
535                 if (argc < 5)
536                         goto usage;
537                 ret = pci_cfg_write(bdf, addr, size, value);
538                 break;
539         default:
540                 ret = CMD_RET_USAGE;
541                 break;
542         }
543
544         return ret;
545  usage:
546         return CMD_RET_USAGE;
547 }
548
549 /***************************************************/
550
551 #ifdef CONFIG_SYS_LONGHELP
552 static char pci_help_text[] =
553         "[bus] [long]\n"
554         "    - short or long list of PCI devices on bus 'bus'\n"
555 #ifdef CONFIG_CMD_PCI_ENUM
556         "pci enum\n"
557         "    - re-enumerate PCI buses\n"
558 #endif
559         "pci header b.d.f\n"
560         "    - show header of PCI device 'bus.device.function'\n"
561         "pci display[.b, .w, .l] b.d.f [address] [# of objects]\n"
562         "    - display PCI configuration space (CFG)\n"
563         "pci next[.b, .w, .l] b.d.f address\n"
564         "    - modify, read and keep CFG address\n"
565         "pci modify[.b, .w, .l] b.d.f address\n"
566         "    -  modify, auto increment CFG address\n"
567         "pci write[.b, .w, .l] b.d.f address value\n"
568         "    - write to CFG address";
569 #endif
570
571 U_BOOT_CMD(
572         pci,    5,      1,      do_pci,
573         "list and access PCI Configuration Space", pci_help_text
574 );