]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - common/cmd_pci.c
* Patch by Thomas Frieden, 13 Nov 2002:
[karo-tx-uboot.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  * See file CREDITS for list of people who contributed to this
10  * project.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License as
14  * published by the Free Software Foundation; either version 2 of
15  * the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25  * MA 02111-1307 USA
26  */
27
28 /*
29  * PCI routines
30  */
31
32 #include <common.h>
33
34 #ifdef CONFIG_PCI
35
36 #include <command.h>
37 #include <cmd_boot.h>
38 #include <asm/processor.h>
39 #include <asm/io.h>
40 #include <cmd_pci.h>
41 #include <pci.h>
42
43 #if (CONFIG_COMMANDS & CFG_CMD_PCI)
44
45 extern int cmd_get_data_size(char* arg, int default_size);
46
47 unsigned char   ShortPCIListing = 1;
48
49 /*
50  * Follows routines for the output of infos about devices on PCI bus.
51  */
52
53 void pci_header_show(pci_dev_t dev);
54 void pci_header_show_brief(pci_dev_t dev);
55
56 /*
57  * Subroutine:  pciinfo
58  *
59  * Description: Show information about devices on PCI bus.
60  *                              Depending on the define CFG_SHORT_PCI_LISTING
61  *                              the output will be more or less exhaustive.
62  *
63  * Inputs:      bus_no          the number of the bus to be scanned.
64  *
65  * Return:      None
66  *
67  */
68 void pciinfo(int BusNum, int ShortPCIListing)
69 {
70         int Device;
71         int Function;
72         unsigned char HeaderType;
73         unsigned short VendorID;
74         pci_dev_t dev;
75
76         printf("Scanning PCI devices on bus %d\n", BusNum);
77
78         if (ShortPCIListing) {
79                 printf("BusDevFun  VendorId   DeviceId   Device Class       Sub-Class\n");
80                 printf("_____________________________________________________________\n");
81         }
82
83         for (Device = 0; Device < PCI_MAX_PCI_DEVICES; Device++) {
84                 HeaderType = 0;
85                 VendorID = 0;
86                 for (Function = 0; Function < PCI_MAX_PCI_FUNCTIONS; Function++) {
87                         /*
88                          * If this is not a multi-function device, we skip the rest.
89                          */
90                         if (Function && !(HeaderType & 0x80))
91                                 break;
92
93                         dev = PCI_BDF(BusNum, Device, Function);
94
95                         pci_read_config_word(dev, PCI_VENDOR_ID, &VendorID);
96                         if ((VendorID == 0xFFFF) || (VendorID == 0x0000))
97                                 continue;
98
99                         if (!Function) pci_read_config_byte(dev, PCI_HEADER_TYPE, &HeaderType);
100
101                         if (ShortPCIListing)
102                         {
103                                 printf("%02x.%02x.%02x   ", BusNum, Device, Function);
104                                 pci_header_show_brief(dev);
105                         }
106                         else
107                         {
108                                 printf("\nFound PCI device %02x.%02x.%02x:\n",
109                                        BusNum, Device, Function);
110                                 pci_header_show(dev);
111                         }
112             }
113     }
114 }
115
116 char* pci_classes_str(u8 class)
117 {
118         static char *pci_classes[] = {
119                 "Build before PCI Rev2.0",
120                 "Mass storage controller",
121                 "Network controller     ",
122                 "Display controller     ",
123                 "Multimedia device      ",
124                 "Memory controller      ",
125                 "Bridge device          ",
126                 "Simple comm. controller",
127                 "Base system peripheral ",
128                 "Input device           ",
129                 "Docking station        ",
130                 "Processor              ",
131                 "Serial bus controller  ",
132                 "Reserved entry         ",
133                 "Does not fit any class "
134         };
135
136         if (class < (sizeof pci_classes / sizeof *pci_classes))
137                 return pci_classes[(int) class];
138
139         return  "???                    ";
140 }
141
142 /*
143  * Subroutine:  pci_header_show_brief
144  *
145  * Description: Reads and prints the header of the
146  *              specified PCI device in short form.
147  *
148  * Inputs:      dev      Bus+Device+Function number
149  *
150  * Return:      None
151  *
152  */
153 void pci_header_show_brief(pci_dev_t dev)
154 {
155         u16 vendor, device;
156         u8 class, subclass;
157
158         pci_read_config_word(dev, PCI_VENDOR_ID, &vendor);
159         pci_read_config_word(dev, PCI_DEVICE_ID, &device);
160         pci_read_config_byte(dev, PCI_CLASS_CODE, &class);
161         pci_read_config_byte(dev, PCI_CLASS_SUB_CODE, &subclass);
162
163         printf("0x%.4x     0x%.4x     %s 0x%.2x\n",
164                vendor, device,
165                pci_classes_str(class), subclass);
166 }
167
168 /*
169  * Subroutine:  PCI_Header_Show
170  *
171  * Description: Reads the header of the specified PCI device.
172  *
173  * Inputs:              BusDevFunc      Bus+Device+Function number
174  *
175  * Return:      None
176  *
177  */
178 void pci_header_show(pci_dev_t dev)
179 {
180         u8 _byte, header_type;
181         u16 _word;
182         u32 _dword;
183
184 #define PRINT(msg, type, reg) \
185         pci_read_config_##type(dev, reg, &_##type); \
186         printf(msg, _##type)
187
188 #define PRINT2(msg, type, reg, func) \
189         pci_read_config_##type(dev, reg, &_##type); \
190         printf(msg, _##type, func(_##type))
191
192         pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
193
194         PRINT ("  vendor ID =                   0x%.4x\n", word, PCI_VENDOR_ID);
195         PRINT ("  device ID =                   0x%.4x\n", word, PCI_DEVICE_ID);
196         PRINT ("  command register =            0x%.4x\n", word, PCI_COMMAND);
197         PRINT ("  status register =             0x%.4x\n", word, PCI_STATUS);
198         PRINT ("  revision ID =                 0x%.2x\n", byte, PCI_REVISION_ID);
199         PRINT2("  class code =                  0x%.2x (%s)\n", byte, PCI_CLASS_CODE,
200                                                                 pci_classes_str);
201         PRINT ("  sub class code =              0x%.2x\n", byte, PCI_CLASS_SUB_CODE);
202         PRINT ("  programming interface =       0x%.2x\n", byte, PCI_CLASS_PROG);
203         PRINT ("  cache line =                  0x%.2x\n", byte, PCI_CACHE_LINE_SIZE);
204         PRINT ("  latency time =                0x%.2x\n", byte, PCI_LATENCY_TIMER);
205         PRINT ("  header type =                 0x%.2x\n", byte, PCI_HEADER_TYPE);
206         PRINT ("  BIST =                        0x%.2x\n", byte, PCI_BIST);
207         PRINT ("  base address 0 =              0x%.8x\n", dword, PCI_BASE_ADDRESS_0);
208         PRINT ("  base address 1 =              0x%.8x\n", dword, PCI_BASE_ADDRESS_1);
209
210         if (header_type & 0x01) {               /* PCI-to-PCI bridge */
211                 PRINT ("  primary bus number =          0x%.2x\n", byte, PCI_PRIMARY_BUS);
212                 PRINT ("  secondary bus number =        0x%.2x\n", byte, PCI_SECONDARY_BUS);
213                 PRINT ("  subordinate bus number =      0x%.2x\n", byte, PCI_SUBORDINATE_BUS);
214                 PRINT ("  secondary latency timer =     0x%.2x\n", byte, PCI_SEC_LATENCY_TIMER);
215                 PRINT ("  IO base =                     0x%.2x\n", byte, PCI_IO_BASE);
216                 PRINT ("  IO limit =                    0x%.2x\n", byte, PCI_IO_LIMIT);
217                 PRINT ("  secondary status =            0x%.4x\n", word, PCI_SEC_STATUS);
218                 PRINT ("  memory base =                 0x%.4x\n", word, PCI_MEMORY_BASE);
219                 PRINT ("  memory limit =                0x%.4x\n", word, PCI_MEMORY_LIMIT);
220                 PRINT ("  prefetch memory base =        0x%.4x\n", word, PCI_PREF_MEMORY_BASE);
221                 PRINT ("  prefetch memory limit =       0x%.4x\n", word, PCI_PREF_MEMORY_LIMIT);
222                 PRINT ("  prefetch memory base upper =  0x%.8x\n", dword, PCI_PREF_BASE_UPPER32);
223                 PRINT ("  prefetch memory limit upper = 0x%.8x\n", dword, PCI_PREF_LIMIT_UPPER32);
224                 PRINT ("  IO base upper 16 bits =       0x%.4x\n", word, PCI_IO_BASE_UPPER16);
225                 PRINT ("  IO limit upper 16 bits =      0x%.4x\n", word, PCI_IO_LIMIT_UPPER16);
226                 PRINT ("  expansion ROM base address =  0x%.8x\n", dword, PCI_ROM_ADDRESS1);
227                 PRINT ("  interrupt line =              0x%.2x\n", byte, PCI_INTERRUPT_LINE);
228                 PRINT ("  interrupt pin =               0x%.2x\n", byte, PCI_INTERRUPT_PIN);
229                 PRINT ("  bridge control =              0x%.4x\n", word, PCI_BRIDGE_CONTROL);
230     } else {                                    /* PCI device */
231                 PRINT("  base address 2 =              0x%.8x\n", dword, PCI_BASE_ADDRESS_2);
232                 PRINT("  base address 3 =              0x%.8x\n", dword, PCI_BASE_ADDRESS_3);
233                 PRINT("  base address 4 =              0x%.8x\n", dword, PCI_BASE_ADDRESS_4);
234                 PRINT("  base address 5 =              0x%.8x\n", dword, PCI_BASE_ADDRESS_5);
235                 PRINT("  cardBus CIS pointer =         0x%.8x\n", dword, PCI_CARDBUS_CIS);
236                 PRINT("  sub system vendor ID =        0x%.4x\n", word, PCI_SUBSYSTEM_VENDOR_ID);
237                 PRINT("  sub system ID =               0x%.4x\n", word, PCI_SUBSYSTEM_ID);
238                 PRINT("  expansion ROM base address =  0x%.8x\n", dword, PCI_ROM_ADDRESS);
239                 PRINT("  interrupt line =              0x%.2x\n", byte, PCI_INTERRUPT_LINE);
240                 PRINT("  interrupt pin =               0x%.2x\n", byte, PCI_INTERRUPT_PIN);
241                 PRINT("  min Grant =                   0x%.2x\n", byte, PCI_MIN_GNT);
242                 PRINT("  max Latency =                 0x%.2x\n", byte, PCI_MAX_LAT);
243     }
244
245 #undef PRINT
246 #undef PRINT2
247 }
248
249 /* Convert the "bus.device.function" identifier into a number.
250  */
251 static pci_dev_t get_pci_dev(char* name)
252 {
253         char cnum[12];
254         int len, i, iold, n;
255         int bdfs[3] = {0,0,0};
256
257         len = strlen(name);
258         if (len > 8)
259                 return -1;
260         for (i = 0, iold = 0, n = 0; i < len; i++) {
261                 if (name[i] == '.') {
262                         memcpy(cnum, &name[iold], i - iold);
263                         cnum[i - iold] = '\0';
264                         bdfs[n++] = simple_strtoul(cnum, NULL, 16);
265                         iold = i + 1;
266                 }
267         }
268         strcpy(cnum, &name[iold]);
269         if (n == 0)
270                 n = 1;
271         bdfs[n] = simple_strtoul(cnum, NULL, 16);
272         return PCI_BDF(bdfs[0], bdfs[1], bdfs[2]);
273 }
274
275 static int pci_cfg_display(pci_dev_t bdf, ulong addr, ulong size, ulong length)
276 {
277 #define DISP_LINE_LEN   16
278         ulong i, nbytes, linebytes;
279         int rc = 0;
280
281         if (length == 0)
282                 length = 0x40 / size; /* Standard PCI configuration space */
283
284         /* Print the lines.
285          * once, and all accesses are with the specified bus width.
286          */
287         nbytes = length * size;
288         do {
289                 uint    val4;
290                 ushort  val2;
291                 u_char  val1;
292
293                 printf("%08lx:", addr);
294                 linebytes = (nbytes>DISP_LINE_LEN)?DISP_LINE_LEN:nbytes;
295                 for (i=0; i<linebytes; i+= size) {
296                         if (size == 4) {
297                                 pci_read_config_dword(bdf, addr, &val4);
298                                 printf(" %08x", val4);
299                         } else if (size == 2) {
300                                 pci_read_config_word(bdf, addr, &val2);
301                                 printf(" %04x", val2);
302                         } else {
303                                 pci_read_config_byte(bdf, addr, &val1);
304                                 printf(" %02x", val1);
305                         }
306                         addr += size;
307                 }
308                 printf("\n");
309                 nbytes -= linebytes;
310                 if (ctrlc()) {
311                         rc = 1;
312                         break;
313                 }
314         } while (nbytes > 0);
315
316         return (rc);
317 }
318
319 static int pci_cfg_write (pci_dev_t bdf, ulong addr, ulong size, ulong value)
320 {
321         if (size == 4) {
322                 pci_write_config_dword(bdf, addr, value);
323         }
324         else if (size == 2) {
325                 ushort val = value & 0xffff;
326                 pci_write_config_word(bdf, addr, val);
327         }
328         else {
329                 u_char val = value & 0xff;
330                 pci_write_config_byte(bdf, addr, val);
331         }
332         return 0;
333 }
334
335 static int
336 pci_cfg_modify (pci_dev_t bdf, ulong addr, ulong size, ulong value, int incrflag)
337 {
338         ulong   i;
339         int     nbytes;
340         extern char console_buffer[];
341         uint    val4;
342         ushort  val2;
343         u_char  val1;
344
345         /* Print the address, followed by value.  Then accept input for
346          * the next value.  A non-converted value exits.
347          */
348         do {
349                 printf("%08lx:", addr);
350                 if (size == 4) {
351                         pci_read_config_dword(bdf, addr, &val4);
352                         printf(" %08x", val4);
353                 }
354                 else if (size == 2) {
355                         pci_read_config_word(bdf, addr, &val2);
356                         printf(" %04x", val2);
357                 }
358                 else {
359                         pci_read_config_byte(bdf, addr, &val1);
360                         printf(" %02x", val1);
361                 }
362
363                 nbytes = readline (" ? ");
364                 if (nbytes == 0 || (nbytes == 1 && console_buffer[0] == '-')) {
365                         /* <CR> pressed as only input, don't modify current
366                          * location and move to next. "-" pressed will go back.
367                          */
368                         if (incrflag)
369                                 addr += nbytes ? -size : size;
370                         nbytes = 1;
371 #ifdef CONFIG_BOOT_RETRY_TIME
372                         reset_cmd_timeout(); /* good enough to not time out */
373 #endif
374                 }
375 #ifdef CONFIG_BOOT_RETRY_TIME
376                 else if (nbytes == -2) {
377                         break;  /* timed out, exit the command  */
378                 }
379 #endif
380                 else {
381                         char *endp;
382                         i = simple_strtoul(console_buffer, &endp, 16);
383                         nbytes = endp - console_buffer;
384                         if (nbytes) {
385 #ifdef CONFIG_BOOT_RETRY_TIME
386                                 /* good enough to not time out
387                                  */
388                                 reset_cmd_timeout();
389 #endif
390                                 pci_cfg_write (bdf, addr, size, i);
391                                 if (incrflag)
392                                         addr += size;
393                         }
394                 }
395         } while (nbytes);
396
397         return 0;
398 }
399
400 /* PCI Configuration Space access commands
401  *
402  * Syntax:
403  *      pci display[.b, .w, .l] bus.device.function} [addr] [len]
404  *      pci next[.b, .w, .l] bus.device.function [addr]
405  *      pci modify[.b, .w, .l] bus.device.function [addr]
406  *      pci write[.b, .w, .l] bus.device.function addr value
407  */
408 int do_pci (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
409 {
410         ulong addr = 0, value = 0, size = 0;
411         pci_dev_t bdf = 0;
412         char cmd = 's';
413
414         if (argc > 1)
415                 cmd = argv[1][0];
416
417         switch (cmd) {
418         case 'd':               /* display */
419         case 'n':               /* next */
420         case 'm':               /* modify */
421         case 'w':               /* write */
422                 /* Check for a size specification. */
423                 size = cmd_get_data_size(argv[1], 4);
424                 if (argc > 3)
425                         addr = simple_strtoul(argv[3], NULL, 16);
426                 if (argc > 4)
427                         value = simple_strtoul(argv[4], NULL, 16);
428         case 'h':               /* header */
429                 if (argc < 3)
430                         goto usage;
431                 if ((bdf = get_pci_dev(argv[2])) == -1)
432                         return 1;
433                 break;
434         default:                /* scan bus */
435                 value = 1; /* short listing */
436                 bdf = 0;   /* bus number  */
437                 if (argc > 1) {
438                         if (argv[argc-1][0] == 'l') {
439                                 value = 0;
440                                 argc--;
441                         }
442                         if (argc > 1)
443                                 bdf = simple_strtoul(argv[1], NULL, 16);
444                 }
445                 pciinfo(bdf, value);
446                 return 0;
447         }
448
449         switch (argv[1][0]) {
450         case 'h':               /* header */
451                 pci_header_show(bdf);
452                 return 0;
453         case 'd':               /* display */
454                 return pci_cfg_display(bdf, addr, size, value);
455         case 'n':               /* next */
456                 if (argc < 4)
457                         goto usage;
458                 return pci_cfg_modify(bdf, addr, size, value, 0);
459         case 'm':               /* modify */
460                 if (argc < 4)
461                         goto usage;
462                 return pci_cfg_modify(bdf, addr, size, value, 1);
463         case 'w':               /* write */
464                 if (argc < 5)
465                         goto usage;
466                 return pci_cfg_write(bdf, addr, size, value);
467         }
468
469         return 1;
470  usage:
471         printf ("Usage:\n%s\n", cmdtp->usage);
472         return 1;
473 }
474
475 #endif /* (CONFIG_COMMANDS & CFG_CMD_PCI) */
476
477 #endif /* CONFIG_PCI */