2 * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
3 * Andreas Heppel <aheppel@sysgo.de>
6 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
7 * Wolfgang Grandegger, DENX Software Engineering, wg@denx.de.
9 * See file CREDITS for list of people who contributed to this
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.
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.
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,
38 #include <asm/processor.h>
43 #if (CONFIG_COMMANDS & CFG_CMD_PCI)
45 extern int cmd_get_data_size(char* arg, int default_size);
47 unsigned char ShortPCIListing = 1;
50 * Follows routines for the output of infos about devices on PCI bus.
53 void pci_header_show(pci_dev_t dev);
54 void pci_header_show_brief(pci_dev_t dev);
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.
63 * Inputs: bus_no the number of the bus to be scanned.
68 void pciinfo(int BusNum, int ShortPCIListing)
72 unsigned char HeaderType;
73 unsigned short VendorID;
76 printf("Scanning PCI devices on bus %d\n", BusNum);
78 if (ShortPCIListing) {
79 printf("BusDevFun VendorId DeviceId Device Class Sub-Class\n");
80 printf("_____________________________________________________________\n");
83 for (Device = 0; Device < PCI_MAX_PCI_DEVICES; Device++) {
86 for (Function = 0; Function < PCI_MAX_PCI_FUNCTIONS; Function++) {
88 * If this is not a multi-function device, we skip the rest.
90 if (Function && !(HeaderType & 0x80))
93 dev = PCI_BDF(BusNum, Device, Function);
95 pci_read_config_word(dev, PCI_VENDOR_ID, &VendorID);
96 if ((VendorID == 0xFFFF) || (VendorID == 0x0000))
99 if (!Function) pci_read_config_byte(dev, PCI_HEADER_TYPE, &HeaderType);
103 printf("%02x.%02x.%02x ", BusNum, Device, Function);
104 pci_header_show_brief(dev);
108 printf("\nFound PCI device %02x.%02x.%02x:\n",
109 BusNum, Device, Function);
110 pci_header_show(dev);
116 char* pci_classes_str(u8 class)
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 ",
126 "Simple comm. controller",
127 "Base system peripheral ",
131 "Serial bus controller ",
133 "Does not fit any class "
136 if (class < (sizeof pci_classes / sizeof *pci_classes))
137 return pci_classes[(int) class];
143 * Subroutine: pci_header_show_brief
145 * Description: Reads and prints the header of the
146 * specified PCI device in short form.
148 * Inputs: dev Bus+Device+Function number
153 void pci_header_show_brief(pci_dev_t dev)
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);
163 printf("0x%.4x 0x%.4x %s 0x%.2x\n",
165 pci_classes_str(class), subclass);
169 * Subroutine: PCI_Header_Show
171 * Description: Reads the header of the specified PCI device.
173 * Inputs: BusDevFunc Bus+Device+Function number
178 void pci_header_show(pci_dev_t dev)
180 u8 _byte, header_type;
184 #define PRINT(msg, type, reg) \
185 pci_read_config_##type(dev, reg, &_##type); \
188 #define PRINT2(msg, type, reg, func) \
189 pci_read_config_##type(dev, reg, &_##type); \
190 printf(msg, _##type, func(_##type))
192 pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
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,
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);
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);
249 /* Convert the "bus.device.function" identifier into a number.
251 static pci_dev_t get_pci_dev(char* name)
255 int bdfs[3] = {0,0,0};
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);
268 strcpy(cnum, &name[iold]);
271 bdfs[n] = simple_strtoul(cnum, NULL, 16);
272 return PCI_BDF(bdfs[0], bdfs[1], bdfs[2]);
275 static int pci_cfg_display(pci_dev_t bdf, ulong addr, ulong size, ulong length)
277 #define DISP_LINE_LEN 16
278 ulong i, nbytes, linebytes;
282 length = 0x40 / size; /* Standard PCI configuration space */
285 * once, and all accesses are with the specified bus width.
287 nbytes = length * size;
293 printf("%08lx:", addr);
294 linebytes = (nbytes>DISP_LINE_LEN)?DISP_LINE_LEN:nbytes;
295 for (i=0; i<linebytes; i+= size) {
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);
303 pci_read_config_byte(bdf, addr, &val1);
304 printf(" %02x", val1);
314 } while (nbytes > 0);
319 static int pci_cfg_write (pci_dev_t bdf, ulong addr, ulong size, ulong value)
322 pci_write_config_dword(bdf, addr, value);
324 else if (size == 2) {
325 ushort val = value & 0xffff;
326 pci_write_config_word(bdf, addr, val);
329 u_char val = value & 0xff;
330 pci_write_config_byte(bdf, addr, val);
336 pci_cfg_modify (pci_dev_t bdf, ulong addr, ulong size, ulong value, int incrflag)
340 extern char console_buffer[];
345 /* Print the address, followed by value. Then accept input for
346 * the next value. A non-converted value exits.
349 printf("%08lx:", addr);
351 pci_read_config_dword(bdf, addr, &val4);
352 printf(" %08x", val4);
354 else if (size == 2) {
355 pci_read_config_word(bdf, addr, &val2);
356 printf(" %04x", val2);
359 pci_read_config_byte(bdf, addr, &val1);
360 printf(" %02x", val1);
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.
369 addr += nbytes ? -size : size;
371 #ifdef CONFIG_BOOT_RETRY_TIME
372 reset_cmd_timeout(); /* good enough to not time out */
375 #ifdef CONFIG_BOOT_RETRY_TIME
376 else if (nbytes == -2) {
377 break; /* timed out, exit the command */
382 i = simple_strtoul(console_buffer, &endp, 16);
383 nbytes = endp - console_buffer;
385 #ifdef CONFIG_BOOT_RETRY_TIME
386 /* good enough to not time out
390 pci_cfg_write (bdf, addr, size, i);
400 /* PCI Configuration Space access commands
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
408 int do_pci (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
410 ulong addr = 0, value = 0, size = 0;
418 case 'd': /* display */
420 case 'm': /* modify */
421 case 'w': /* write */
422 /* Check for a size specification. */
423 size = cmd_get_data_size(argv[1], 4);
425 addr = simple_strtoul(argv[3], NULL, 16);
427 value = simple_strtoul(argv[4], NULL, 16);
428 case 'h': /* header */
431 if ((bdf = get_pci_dev(argv[2])) == -1)
434 default: /* scan bus */
435 value = 1; /* short listing */
436 bdf = 0; /* bus number */
438 if (argv[argc-1][0] == 'l') {
443 bdf = simple_strtoul(argv[1], NULL, 16);
449 switch (argv[1][0]) {
450 case 'h': /* header */
451 pci_header_show(bdf);
453 case 'd': /* display */
454 return pci_cfg_display(bdf, addr, size, value);
458 return pci_cfg_modify(bdf, addr, size, value, 0);
459 case 'm': /* modify */
462 return pci_cfg_modify(bdf, addr, size, value, 1);
463 case 'w': /* write */
466 return pci_cfg_write(bdf, addr, size, value);
471 printf ("Usage:\n%s\n", cmdtp->usage);
475 #endif /* (CONFIG_COMMANDS & CFG_CMD_PCI) */
477 #endif /* CONFIG_PCI */