]> git.ipfire.org Git - people/ms/u-boot.git/blob - common/cmd_pci.c
* Patch by Thomas Frieden, 13 Nov 2002:
[people/ms/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 * 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 */