4 * This driver is compliant to the
5 * PCI bus binding to IEEE 1275-1994 Rev 2.1
7 * (C) 2004 Stefan Reinauer <stepan@openbios.org>
8 * (C) 2005 Ed Schouten <ed@fxq.nl>
10 * Some parts from OpenHackWare-0.4, Copyright (c) 2004-2005 Jocelyn Mayer
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
19 #include "libopenbios/bindings.h"
20 #include "kernel/kernel.h"
21 #include "drivers/pci.h"
22 #include "libc/byteorder.h"
23 #include "libc/vsprintf.h"
25 #include "drivers/drivers.h"
26 #include "drivers/vga.h"
29 #include "pci_database.h"
30 #ifdef CONFIG_DRIVER_MACIO
35 #if defined (CONFIG_DEBUG_PCI)
36 # define PCI_DPRINTF(format, ...) printk(format, ## __VA_ARGS__)
38 # define PCI_DPRINTF(format, ...) do { } while (0)
41 #define set_bool_property(ph, name) set_property(ph, name, NULL, 0);
43 /* DECLARE data structures for the nodes. */
45 DECLARE_UNNAMED_NODE( ob_pci_bus_node
, INSTALL_OPEN
, 2*sizeof(int) );
46 DECLARE_UNNAMED_NODE( ob_pci_simple_node
, INSTALL_OPEN
, 2*sizeof(int) );
48 const pci_arch_t
*arch
;
50 #define IS_NOT_RELOCATABLE 0x80000000
51 #define IS_PREFETCHABLE 0x40000000
52 #define IS_ALIASED 0x20000000
55 CONFIGURATION_SPACE
= 0,
61 static int encode_int32_cells(int num_cells
, u32
*prop
, ucell val
)
66 for (i
=0; i
< num_cells
; ++i
) {
67 prop
[num_cells
- i
- 1] = val
;
75 static inline int pci_encode_phys_addr(u32
*phys
, int flags
, int space_code
,
76 pci_addr dev
, uint8_t reg
, uint64_t addr
)
81 phys
[0] = flags
| (space_code
<< 24) | dev
| reg
;
94 static inline int pci_encode_size(u32
*prop
, uint64_t size
)
96 return encode_int32_cells(2, prop
, size
);
99 static int host_address_cells(void)
101 return get_int_property(find_dev("/"), "#address-cells", NULL
);
104 static int host_encode_phys_addr(u32
*prop
, ucell addr
)
106 return encode_int32_cells(host_address_cells(), prop
, addr
);
109 static int host_size_cells(void)
111 return get_int_property(find_dev("/"), "#size-cells", NULL
);
115 static int parent_address_cells(void)
117 phandle_t parent_ph = ih_to_phandle(my_parent());
118 return get_int_property(parent_ph, "#address-cells", NULL);
121 static int parent_size_cells(void)
123 phandle_t parent_ph = ih_to_phandle(my_parent());
124 return get_int_property(parent_ph, "#size-cells", NULL);
128 #if defined(CONFIG_DEBUG_PCI)
129 static void dump_reg_property(const char* description
, int nreg
, u32
*reg
)
132 printk("%s reg", description
);
133 for (i
=0; i
< nreg
; ++i
) {
134 printk(" %08X", reg
[i
]);
141 ob_pci_open(int *idx
)
148 ob_pci_close(int *idx
)
153 ob_pci_initialize(int *idx
)
157 /* ( str len -- phys.lo phys.mid phys.hi ) */
160 ob_pci_decode_unit(int *idx
)
163 const char *arg
= pop_fstr_copy();
164 int dev
, fn
, reg
, ss
, n
, p
, t
;
165 int bus
= 0; /* no information */
168 PCI_DPRINTF("ob_pci_decode_unit idx=%p\n", idx
);
178 n
= IS_NOT_RELOCATABLE
;
189 /* DD,F,RR,NNNNNNNN */
191 dev
= strtol(ptr
, &ptr
, 16);
193 fn
= strtol(ptr
, &ptr
, 16);
195 reg
= strtol(ptr
, &ptr
, 16);
197 lo
= strtol(ptr
, &ptr
, 16);
200 } else if (*ptr
== 'm') {
201 ss
= MEMORY_SPACE_32
;
212 /* DD,F,RR,NNNNNNNN */
214 dev
= strtol(ptr
, &ptr
, 16);
216 fn
= strtol(ptr
, &ptr
, 16);
218 reg
= strtol(ptr
, &ptr
, 16);
220 lo
= strtol(ptr
, &ptr
, 16);
223 } else if (*ptr
== 'x') {
224 unsigned long long addr64
;
225 ss
= MEMORY_SPACE_64
;
232 /* DD,F,RR,NNNNNNNNNNNNNNNN */
234 dev
= strtol(ptr
, &ptr
, 16);
236 fn
= strtol(ptr
, &ptr
, 16);
238 reg
= strtol(ptr
, &ptr
, 16);
240 addr64
= strtoll(ptr
, &ptr
, 16);
245 ss
= CONFIGURATION_SPACE
;
246 /* "DD" or "DD,FF" */
247 dev
= strtol(ptr
, &ptr
, 16);
250 fn
= strtol(ptr
, NULL
, 16);
257 hi
= n
| p
| t
| (ss
<< 24) | (bus
<< 16) | (dev
<< 11) | (fn
<< 8) | reg
;
263 PCI_DPRINTF("ob_pci_decode_unit idx=%p addr="
264 FMT_ucellx
" " FMT_ucellx
" " FMT_ucellx
"\n",
268 /* ( phys.lo phy.mid phys.hi -- str len ) */
271 ob_pci_encode_unit(int *idx
)
277 int n
, p
, t
, ss
, dev
, fn
, reg
;
279 n
= hi
& IS_NOT_RELOCATABLE
;
280 p
= hi
& IS_PREFETCHABLE
;
282 ss
= (hi
>> 24) & 0x03;
284 dev
= (hi
>> 11) & 0x1F;
285 fn
= (hi
>> 8) & 0x07;
289 case CONFIGURATION_SPACE
:
291 if (fn
== 0) /* DD */
292 snprintf(buf
, sizeof(buf
), "%x", dev
);
294 snprintf(buf
, sizeof(buf
), "%x,%x", dev
, fn
);
299 /* [n]i[t]DD,F,RR,NNNNNNNN */
300 snprintf(buf
, sizeof(buf
), "%si%s%x,%x,%x," FMT_ucellx
,
301 n
? "n" : "", /* relocatable */
302 t
? "t" : "", /* aliased */
303 dev
, fn
, reg
, t
? lo
& 0x03FF : lo
);
306 case MEMORY_SPACE_32
:
308 /* [n]m[t][p]DD,F,RR,NNNNNNNN */
309 snprintf(buf
, sizeof(buf
), "%sm%s%s%x,%x,%x," FMT_ucellx
,
310 n
? "n" : "", /* relocatable */
311 t
? "t" : "", /* aliased */
312 p
? "p" : "", /* prefetchable */
316 case MEMORY_SPACE_64
:
318 /* [n]x[p]DD,F,RR,NNNNNNNNNNNNNNNN */
319 snprintf(buf
, sizeof(buf
), "%sx%s%x,%x,%x,%llx",
320 n
? "n" : "", /* relocatable */
321 p
? "p" : "", /* prefetchable */
322 dev
, fn
, reg
, ((long long)mid
<< 32) | (long long)lo
);
327 PCI_DPRINTF("ob_pci_encode_unit space=%d dev=%d fn=%d buf=%s\n",
331 NODE_METHODS(ob_pci_bus_node
) = {
332 { NULL
, ob_pci_initialize
},
333 { "open", ob_pci_open
},
334 { "close", ob_pci_close
},
335 { "decode-unit", ob_pci_decode_unit
},
336 { "encode-unit", ob_pci_encode_unit
},
339 NODE_METHODS(ob_pci_simple_node
) = {
340 { NULL
, ob_pci_initialize
},
341 { "open", ob_pci_open
},
342 { "close", ob_pci_close
},
345 static void pci_set_bus_range(const pci_config_t
*config
)
347 phandle_t dev
= find_dev(config
->path
);
350 props
[0] = config
->secondary_bus
;
351 props
[1] = config
->subordinate_bus
;
353 PCI_DPRINTF("setting bus range for %s PCI device, "
354 "package handle " FMT_ucellx
" "
355 "bus primary=%d secondary=%d subordinate=%d\n",
359 config
->secondary_bus
,
360 config
->subordinate_bus
);
363 set_property(dev
, "bus-range", (char *)props
, 2 * sizeof(props
[0]));
366 static void pci_host_set_interrupt_map(const pci_config_t
*config
)
368 /* XXX We currently have a hook in the MPIC init code to fill in its handle.
369 * If you want to have interrupt maps for your PCI host bus, add your
370 * architecture to the #if and make your bridge detect code fill in its
373 * It would be great if someone clever could come up with a more universal
376 #if defined(CONFIG_PPC)
377 phandle_t dev
= get_cur_dev();
381 #if defined(CONFIG_PPC)
382 /* Oldworld macs do interrupt maps differently */
387 for (i
= 0; i
< (7*4); i
+=7) {
388 props
[i
+PCI_INT_MAP_PCI0
] = 0;
389 props
[i
+PCI_INT_MAP_PCI1
] = 0;
390 props
[i
+PCI_INT_MAP_PCI2
] = 0;
391 props
[i
+PCI_INT_MAP_PCI_INT
] = (i
/ 7) + 1; // starts at PINA=1
392 props
[i
+PCI_INT_MAP_PIC_HANDLE
] = 0; // gets patched in later
393 props
[i
+PCI_INT_MAP_PIC_INT
] = arch
->irqs
[i
/ 7];
394 props
[i
+PCI_INT_MAP_PIC_POL
] = 3;
396 set_property(dev
, "interrupt-map", (char *)props
, 7 * 4 * sizeof(props
[0]));
398 props
[PCI_INT_MAP_PCI0
] = 0;
399 props
[PCI_INT_MAP_PCI1
] = 0;
400 props
[PCI_INT_MAP_PCI2
] = 0;
401 props
[PCI_INT_MAP_PCI_INT
] = 0x7;
403 set_property(dev
, "interrupt-map-mask", (char *)props
, 4 * sizeof(props
[0]));
407 static void pci_host_set_reg(phandle_t phandle
)
409 phandle_t dev
= phandle
;
411 /* at most 2 integers for address and size */
415 ncells
+= encode_int32_cells(host_address_cells(), props
+ ncells
,
418 ncells
+= encode_int32_cells(host_size_cells(), props
+ ncells
,
421 set_property(dev
, "reg", (char *)props
, ncells
* sizeof(props
[0]));
423 #if defined(CONFIG_DEBUG_PCI)
424 dump_reg_property("pci_host_set_reg", 4, props
);
428 /* child-phys : parent-phys : size */
429 /* 3 cells for PCI : 2 cells for 64bit parent : 2 cells for PCI */
431 static void pci_host_set_ranges(const pci_config_t
*config
)
433 phandle_t dev
= get_cur_dev();
438 /* first encode PCI configuration space */
440 ncells
+= pci_encode_phys_addr(props
+ ncells
, 0, CONFIGURATION_SPACE
,
442 ncells
+= host_encode_phys_addr(props
+ ncells
, arch
->cfg_addr
);
443 ncells
+= pci_encode_size(props
+ ncells
, arch
->cfg_len
);
447 ncells
+= pci_encode_phys_addr(props
+ ncells
, 0, IO_SPACE
,
449 ncells
+= host_encode_phys_addr(props
+ ncells
, arch
->io_base
);
450 ncells
+= pci_encode_size(props
+ ncells
, arch
->io_len
);
453 ncells
+= pci_encode_phys_addr(props
+ ncells
, 0, MEMORY_SPACE_32
,
455 ncells
+= host_encode_phys_addr(props
+ ncells
, arch
->rbase
);
456 ncells
+= pci_encode_size(props
+ ncells
, arch
->rlen
);
458 if (arch
->host_mem_base
) {
459 ncells
+= pci_encode_phys_addr(props
+ ncells
, 0, MEMORY_SPACE_32
,
460 config
->dev
, 0, arch
->pci_mem_base
);
461 ncells
+= host_encode_phys_addr(props
+ ncells
, arch
->host_mem_base
);
462 ncells
+= pci_encode_size(props
+ ncells
, arch
->mem_len
);
464 set_property(dev
, "ranges", (char *)props
, ncells
* sizeof(props
[0]));
467 static unsigned long pci_bus_addr_to_host_addr(uint32_t ba
)
469 #ifdef CONFIG_SPARC64
470 return arch
->cfg_data
+ (unsigned long)ba
;
472 return (unsigned long)ba
;
476 int host_config_cb(const pci_config_t
*config
)
478 //XXX this overrides "reg" property
479 pci_host_set_reg(get_cur_dev());
480 pci_host_set_ranges(config
);
481 pci_host_set_interrupt_map(config
);
486 static int sabre_configure(phandle_t dev
)
490 props
[0] = 0xc0000000;
491 props
[1] = 0x20000000;
492 set_property(dev
, "virtual-dma", (char *)props
, 2 * sizeof(props
[0]));
494 set_property(dev
, "#virtual-dma-size-cells", (char *)props
,
496 set_property(dev
, "#virtual-dma-addr-cells", (char *)props
,
498 props
[0] = 0x000007f0;
499 props
[1] = 0x000007ee;
500 props
[2] = 0x000007ef;
501 props
[3] = 0x000007e5;
502 set_property(dev
, "interrupts", (char *)props
, 4 * sizeof(props
[0]));
503 props
[0] = 0x0000001f;
504 set_property(dev
, "upa-portid", (char *)props
, 1 * sizeof(props
[0]));
508 int sabre_config_cb(const pci_config_t
*config
)
510 host_config_cb(config
);
512 return sabre_configure(get_cur_dev());
515 int bridge_config_cb(const pci_config_t
*config
)
519 aliases
= find_dev("/aliases");
520 set_property(aliases
, "bridge", config
->path
, strlen(config
->path
) + 1);
525 int ide_config_cb2 (const pci_config_t
*config
)
527 ob_ide_init(config
->path
,
528 config
->assigned
[0] & ~0x0000000F,
529 config
->assigned
[1] & ~0x0000000F,
530 config
->assigned
[2] & ~0x0000000F,
531 config
->assigned
[3] & ~0x0000000F);
535 int eth_config_cb (const pci_config_t
*config
)
537 phandle_t ph
= get_cur_dev();
539 set_property(ph
, "network-type", "ethernet", 9);
540 set_property(ph
, "removable", "network", 8);
541 set_property(ph
, "category", "net", 4);
546 static inline void pci_decode_pci_addr(pci_addr addr
, int *flags
,
547 int *space_code
, uint32_t *mask
)
552 *space_code
= IO_SPACE
;
556 *space_code
= MEMORY_SPACE_64
;
557 *flags
|= IS_NOT_RELOCATABLE
; /* XXX: why not relocatable? */
559 *space_code
= MEMORY_SPACE_32
;
563 *flags
|= IS_PREFETCHABLE
;
571 * "Designing PCI Cards and Drivers for Power Macintosh Computers", p. 454
573 * "AAPL,address" provides an array of 32-bit logical addresses
574 * Nth entry corresponding to Nth "assigned-address" base address entry.
577 static void pci_set_AAPL_address(const pci_config_t
*config
)
579 phandle_t dev
= get_cur_dev();
584 for (i
= 0; i
< 6; i
++) {
585 if (!config
->assigned
[i
] || !config
->sizes
[i
])
587 props
[ncells
++] = config
->assigned
[i
] & ~0x0000000F;
590 set_property(dev
, "AAPL,address", (char *)props
,
591 ncells
* sizeof(cell
));
594 static void pci_set_assigned_addresses(phandle_t phandle
,
595 const pci_config_t
*config
, int num_bars
)
597 phandle_t dev
= phandle
;
602 int flags
, space_code
;
605 for (i
= 0; i
< num_bars
; i
++) {
606 /* consider only bars with non-zero region size */
607 if (!config
->sizes
[i
])
609 pci_decode_pci_addr(config
->assigned
[i
],
610 &flags
, &space_code
, &mask
);
612 ncells
+= pci_encode_phys_addr(props
+ ncells
,
613 flags
, space_code
, config
->dev
,
614 PCI_BASE_ADDR_0
+ (i
* sizeof(uint32_t)),
615 config
->assigned
[i
] & ~mask
);
617 props
[ncells
++] = 0x00000000;
618 props
[ncells
++] = config
->sizes
[i
];
621 set_property(dev
, "assigned-addresses", (char *)props
,
622 ncells
* sizeof(props
[0]));
625 /* call after writing "reg" property to update config->path */
626 static void ob_pci_reload_device_path(phandle_t phandle
, pci_config_t
*config
)
628 /* since "name" and "reg" are now assigned
629 we need to reload current node name */
632 fword("get-package-path");
633 char *new_path
= pop_fstr_copy();
635 if (0 != strcmp(config
->path
, new_path
)) {
636 PCI_DPRINTF("\n=== CHANGED === package path old=%s new=%s\n",
637 config
->path
, new_path
);
638 strncpy(config
->path
, new_path
, sizeof(config
->path
));
639 config
->path
[sizeof(config
->path
)-1] = '\0';
643 PCI_DPRINTF("\n=== package path old=%s new=NULL\n", config
->path
);
647 static void pci_set_reg(phandle_t phandle
,
648 pci_config_t
*config
, int num_bars
)
650 phandle_t dev
= phandle
;
655 int space_code
, flags
;
659 /* first (addr, size) pair is the beginning of configuration address space */
660 ncells
+= pci_encode_phys_addr(props
+ ncells
, 0, CONFIGURATION_SPACE
,
663 ncells
+= pci_encode_size(props
+ ncells
, 0);
665 for (i
= 0; i
< num_bars
; i
++) {
666 /* consider only bars with non-zero region size */
667 if (!config
->sizes
[i
])
670 pci_decode_pci_addr(config
->regions
[i
],
671 &flags
, &space_code
, &mask
);
673 ncells
+= pci_encode_phys_addr(props
+ ncells
,
674 flags
, space_code
, config
->dev
,
675 PCI_BASE_ADDR_0
+ (i
* sizeof(uint32_t)),
676 config
->regions
[i
] & ~mask
);
679 ncells
+= pci_encode_size(props
+ ncells
, config
->sizes
[i
]);
682 set_property(dev
, "reg", (char *)props
, ncells
* sizeof(props
[0]));
683 ob_pci_reload_device_path(dev
, config
);
685 #if defined(CONFIG_DEBUG_PCI)
686 dump_reg_property("pci_set_reg", ncells
, props
);
691 static void pci_set_ranges(const pci_config_t
*config
)
693 phandle_t dev
= get_cur_dev();
702 for (i
= 0; i
< 6; i
++) {
703 if (!config
->assigned
[i
] || !config
->sizes
[i
])
708 props
[ncells
++] = 0x00000000;
712 pci_decode_pci_addr(config
->assigned
[i
],
713 &flags
, &space_code
, &mask
);
714 ncells
+= pci_encode_phys_addr(props
+ ncells
, flags
, space_code
,
715 config
->dev
, 0x10 + i
* 4,
716 config
->assigned
[i
] & ~mask
);
720 props
[ncells
++] = config
->sizes
[i
];
722 set_property(dev
, "ranges", (char *)props
, ncells
* sizeof(props
[0]));
725 int macio_heathrow_config_cb (const pci_config_t
*config
)
727 pci_set_ranges(config
);
729 #ifdef CONFIG_DRIVER_MACIO
730 ob_macio_heathrow_init(config
->path
, config
->assigned
[0] & ~0x0000000F);
735 int macio_keylargo_config_cb (const pci_config_t
*config
)
737 pci_set_ranges(config
);
739 #ifdef CONFIG_DRIVER_MACIO
740 ob_macio_keylargo_init(config
->path
, config
->assigned
[0] & ~0x0000000F);
745 int vga_config_cb (const pci_config_t
*config
)
747 if (config
->assigned
[0] != 0x00000000)
748 vga_vbe_init(config
->path
,
749 pci_bus_addr_to_host_addr(config
->assigned
[0] & ~0x0000000F),
751 pci_bus_addr_to_host_addr(config
->assigned
[1] & ~0x0000000F),
756 int ebus_config_cb(const pci_config_t
*config
)
758 #ifdef CONFIG_DRIVER_EBUS
759 #ifdef CONFIG_DRIVER_FLOPPY
760 ob_floppy_init(config
->path
, "fdthree", 0x3f0ULL
, 0);
762 #ifdef CONFIG_DRIVER_PC_SERIAL
763 ob_pc_serial_init(config
->path
, "su", arch
->io_base
, 0x3f8ULL
, 0);
765 #ifdef CONFIG_DRIVER_PC_KBD
766 ob_pc_kbd_init(config
->path
, "kb_ps2", arch
->io_base
, 0x60ULL
, 0);
772 static void ob_pci_add_properties(phandle_t phandle
,
773 pci_addr addr
, const pci_dev_t
*pci_dev
,
774 const pci_config_t
*config
, int num_bars
)
776 /* cannot use get_cur_dev() path resolution since "name" and "reg"
777 properties are being changed */
778 phandle_t dev
=phandle
;
780 uint16_t vendor_id
, device_id
;
784 vendor_id
= pci_config_read16(addr
, PCI_VENDOR_ID
);
785 device_id
= pci_config_read16(addr
, PCI_DEVICE_ID
);
786 rev
= pci_config_read8(addr
, PCI_REVISION_ID
);
787 class_code
= pci_config_read16(addr
, PCI_CLASS_DEVICE
);
792 push_str(pci_dev
->name
);
793 fword("encode-string");
798 snprintf(path
, sizeof(path
),
799 "pci%x,%x", vendor_id
, device_id
);
801 fword("encode-string");
806 PCI_DPRINTF("*** missing pci_dev\n");
809 /* create properties as described in 2.5 */
811 set_int_property(dev
, "vendor-id", vendor_id
);
812 set_int_property(dev
, "device-id", device_id
);
813 set_int_property(dev
, "revision-id", rev
);
814 set_int_property(dev
, "class-code", class_code
<< 8);
816 if (config
->irq_pin
) {
817 OLDWORLD(set_int_property(dev
, "AAPL,interrupts",
819 set_int_property(dev
, "interrupts", config
->irq_pin
);
822 set_int_property(dev
, "min-grant", pci_config_read8(addr
, PCI_MIN_GNT
));
823 set_int_property(dev
, "max-latency", pci_config_read8(addr
, PCI_MAX_LAT
));
825 status
=pci_config_read16(addr
, PCI_STATUS
);
827 set_int_property(dev
, "devsel-speed",
828 (status
&PCI_STATUS_DEVSEL_MASK
)>>10);
830 if(status
&PCI_STATUS_FAST_BACK
)
831 set_bool_property(dev
, "fast-back-to-back");
832 if(status
&PCI_STATUS_66MHZ
)
833 set_bool_property(dev
, "66mhz-capable");
834 if(status
&PCI_STATUS_UDF
)
835 set_bool_property(dev
, "udf-supported");
837 id
=pci_config_read16(addr
, PCI_SUBSYSTEM_VENDOR_ID
);
839 set_int_property(dev
, "subsystem-vendor-id", id
);
840 id
=pci_config_read16(addr
, PCI_SUBSYSTEM_ID
);
842 set_int_property(dev
, "subsystem-id", id
);
844 set_int_property(dev
, "cache-line-size",
845 pci_config_read16(addr
, PCI_CACHE_LINE_SIZE
));
849 push_str(pci_dev
->type
);
850 fword("encode-string");
851 push_str("device_type");
854 if (pci_dev
->model
) {
855 push_str(pci_dev
->model
);
856 fword("encode-string");
861 set_property(dev
, "compatible",
862 pci_dev
->compat
, pci_compat_len(pci_dev
));
865 set_int_property(dev
, "#address-cells",
868 set_int_property(dev
, "#size-cells",
871 set_int_property(dev
, "#interrupt-cells",
875 pci_set_assigned_addresses(phandle
, config
, num_bars
);
876 OLDWORLD(pci_set_AAPL_address(config
));
882 static char pci_xbox_blacklisted (int bus
, int devnum
, int fn
)
885 * The Xbox MCPX chipset is a derivative of the nForce 1
886 * chipset. It almost has the same bus layout; some devices
887 * cannot be used, because they have been removed.
891 * Devices 00:00.1 and 00:00.2 used to be memory controllers on
892 * the nForce chipset, but on the Xbox, using them will lockup
895 if ((bus
== 0) && (devnum
== 0) && ((fn
== 1) || (fn
== 2)))
899 * Bus 1 only contains a VGA controller at 01:00.0. When you try
900 * to probe beyond that device, you only get garbage, which
901 * could cause lockups.
903 if ((bus
== 1) && ((devnum
!= 0) || (fn
!= 0)))
907 * Bus 2 used to contain the AGP controller, but the Xbox MCPX
908 * doesn't have one. Probing it can cause lockups.
914 * The device is not blacklisted.
920 static void ob_pci_configure_bar(pci_addr addr
, pci_config_t
*config
,
921 int reg
, int config_addr
,
923 unsigned long *mem_base
,
924 unsigned long *io_base
)
926 uint32_t smask
, amask
, size
, reloc
, min_align
;
929 config
->assigned
[reg
] = 0x00000000;
930 config
->sizes
[reg
] = 0x00000000;
932 if ((*p_omask
& 0x0000000f) == 0x4) {
933 /* 64 bits memory mapping */
937 config
->regions
[reg
] = pci_config_read32(addr
, config_addr
);
939 /* get region size */
941 pci_config_write32(addr
, config_addr
, 0xffffffff);
942 smask
= pci_config_read32(addr
, config_addr
);
943 if (smask
== 0x00000000 || smask
== 0xffffffff)
946 if (smask
& 0x00000001 && reg
!= 6) {
957 smask
|= 1; /* ROM */
960 *p_omask
= smask
& amask
;
963 config
->sizes
[reg
] = size
;
965 if (size
< min_align
)
967 reloc
= (reloc
+ size
-1) & ~(size
- 1);
968 if (*io_base
== base
) {
969 *io_base
= reloc
+ size
;
970 reloc
-= arch
->io_base
;
972 *mem_base
= reloc
+ size
;
974 pci_config_write32(addr
, config_addr
, reloc
| *p_omask
);
975 config
->assigned
[reg
] = reloc
| *p_omask
;
978 static void ob_pci_configure_irq(pci_addr addr
, pci_config_t
*config
)
980 uint8_t irq_pin
, irq_line
;
982 irq_pin
= pci_config_read8(addr
, PCI_INTERRUPT_PIN
);
984 config
->irq_pin
= irq_pin
;
985 irq_pin
= (((config
->dev
>> 11) & 0x1F) + irq_pin
- 1) & 3;
986 irq_line
= arch
->irqs
[irq_pin
];
987 pci_config_write8(addr
, PCI_INTERRUPT_LINE
, irq_line
);
988 config
->irq_line
= irq_line
;
990 config
->irq_line
= -1;
994 ob_pci_configure(pci_addr addr
, pci_config_t
*config
, int num_regs
, int rom_bar
,
995 unsigned long *mem_base
, unsigned long *io_base
)
1001 pci_addr config_addr
;
1003 ob_pci_configure_irq(addr
, config
);
1006 for (reg
= 0; reg
< num_regs
; ++reg
) {
1007 config_addr
= PCI_BASE_ADDR_0
+ reg
* 4;
1009 ob_pci_configure_bar(addr
, config
, reg
, config_addr
,
1015 config_addr
= rom_bar
;
1016 ob_pci_configure_bar(addr
, config
, reg
, config_addr
,
1017 &omask
, mem_base
, io_base
);
1019 cmd
= pci_config_read16(addr
, PCI_COMMAND
);
1020 cmd
|= PCI_COMMAND_IO
| PCI_COMMAND_MEMORY
;
1021 pci_config_write16(addr
, PCI_COMMAND
, cmd
);
1024 static void ob_configure_pci_device(const char* parent_path
,
1025 int *bus_num
, unsigned long *mem_base
, unsigned long *io_base
,
1026 int bus
, int devnum
, int fn
, int *p_is_multi
);
1028 static void ob_scan_pci_bus(int *bus_num
, unsigned long *mem_base
,
1029 unsigned long *io_base
, const char *path
,
1032 int devnum
, fn
, is_multi
;
1034 PCI_DPRINTF("\nScanning bus %d at %s...\n", bus
, path
);
1036 for (devnum
= 0; devnum
< 32; devnum
++) {
1038 for (fn
= 0; fn
==0 || (is_multi
&& fn
<8); fn
++) {
1039 ob_configure_pci_device(path
, bus_num
, mem_base
, io_base
,
1040 bus
, devnum
, fn
, &is_multi
);
1046 static void ob_configure_pci_bridge(pci_addr addr
,
1047 int *bus_num
, unsigned long *mem_base
,
1048 unsigned long *io_base
,
1049 int primary_bus
, pci_config_t
*config
)
1051 config
->primary_bus
= primary_bus
;
1052 pci_config_write8(addr
, PCI_PRIMARY_BUS
, config
->primary_bus
);
1054 config
->secondary_bus
= *bus_num
;
1055 pci_config_write8(addr
, PCI_SECONDARY_BUS
, config
->secondary_bus
);
1057 config
->subordinate_bus
= 0xff;
1058 pci_config_write8(addr
, PCI_SUBORDINATE_BUS
, config
->subordinate_bus
);
1060 PCI_DPRINTF("scanning new pci bus %u under bridge %s\n",
1061 config
->secondary_bus
, config
->path
);
1063 /* make pci bridge parent device, prepare for recursion */
1065 ob_scan_pci_bus(bus_num
, mem_base
, io_base
,
1066 config
->path
, config
->secondary_bus
);
1068 /* bus scan updates *bus_num to last revealed pci bus number */
1069 config
->subordinate_bus
= *bus_num
;
1070 pci_config_write8(addr
, PCI_SUBORDINATE_BUS
, config
->subordinate_bus
);
1072 PCI_DPRINTF("bridge %s PCI bus primary=%d secondary=%d subordinate=%d\n",
1073 config
->path
, config
->primary_bus
, config
->secondary_bus
,
1074 config
->subordinate_bus
);
1076 pci_set_bus_range(config
);
1079 static int ob_pci_read_identification(int bus
, int devnum
, int fn
,
1080 int *p_vid
, int *p_did
,
1081 uint8_t *p_class
, uint8_t *p_subclass
)
1088 if (pci_xbox_blacklisted (bus
, devnum
, fn
))
1091 addr
= PCI_ADDR(bus
, devnum
, fn
);
1092 vid
= pci_config_read16(addr
, PCI_VENDOR_ID
);
1093 did
= pci_config_read16(addr
, PCI_DEVICE_ID
);
1095 if (vid
==0xffff || vid
==0) {
1107 ccode
= pci_config_read16(addr
, PCI_CLASS_DEVICE
);
1110 *p_class
= ccode
>> 8;
1114 *p_subclass
= ccode
;
1120 static void ob_configure_pci_device(const char* parent_path
,
1121 int *bus_num
, unsigned long *mem_base
, unsigned long *io_base
,
1122 int bus
, int devnum
, int fn
, int *p_is_multi
)
1127 pci_config_t config
= {};
1128 const pci_dev_t
*pci_dev
;
1129 uint8_t class, subclass
, iface
;
1130 int num_bars
, rom_bar
;
1132 phandle_t phandle
= 0;
1133 int is_host_bridge
= 0;
1135 if (!ob_pci_read_identification(bus
, devnum
, fn
, &vid
, &did
, &class, &subclass
)) {
1139 addr
= PCI_ADDR(bus
, devnum
, fn
);
1140 iface
= pci_config_read8(addr
, PCI_CLASS_PROG
);
1142 pci_dev
= pci_find_device(class, subclass
, iface
,
1145 PCI_DPRINTF("%x:%x.%x - %x:%x - ", bus
, devnum
, fn
,
1148 htype
= pci_config_read8(addr
, PCI_HEADER_TYPE
);
1152 *p_is_multi
= htype
& 0x80;
1156 /* stop adding host bridge accessible from it's primary bus
1157 PCI host bridge is to be added by host code
1159 if (class == PCI_BASE_CLASS_BRIDGE
&&
1160 subclass
== PCI_SUBCLASS_BRIDGE_HOST
) {
1164 if (is_host_bridge
) {
1165 /* reuse device tree node */
1166 PCI_DPRINTF("host bridge found - ");
1167 snprintf(config
.path
, sizeof(config
.path
),
1169 } else if (pci_dev
== NULL
|| pci_dev
->name
== NULL
) {
1170 snprintf(config
.path
, sizeof(config
.path
),
1171 "%s/pci%x,%x", parent_path
, vid
, did
);
1174 snprintf(config
.path
, sizeof(config
.path
),
1175 "%s/%s", parent_path
, pci_dev
->name
);
1178 PCI_DPRINTF("%s - ", config
.path
);
1180 config
.dev
= addr
& 0x00FFFFFF;
1183 case PCI_BASE_CLASS_BRIDGE
:
1184 if (subclass
!= PCI_SUBCLASS_BRIDGE_HOST
) {
1185 REGISTER_NAMED_NODE_PHANDLE(ob_pci_bus_node
, config
.path
, phandle
);
1189 REGISTER_NAMED_NODE_PHANDLE(ob_pci_simple_node
, config
.path
, phandle
);
1193 if (is_host_bridge
) {
1194 phandle
= find_dev(config
.path
);
1196 if (get_property(phandle
, "vendor-id", NULL
)) {
1197 PCI_DPRINTF("host bridge already configured\n");
1202 activate_dev(phandle
);
1204 if (htype
& PCI_HEADER_TYPE_BRIDGE
) {
1206 rom_bar
= PCI_ROM_ADDRESS1
;
1209 rom_bar
= PCI_ROM_ADDRESS
;
1212 ob_pci_configure(addr
, &config
, num_bars
, rom_bar
,
1215 ob_pci_add_properties(phandle
, addr
, pci_dev
, &config
, num_bars
);
1217 if (!is_host_bridge
) {
1218 pci_set_reg(phandle
, &config
, num_bars
);
1221 /* call device-specific configuration callback */
1222 if (pci_dev
&& pci_dev
->config_cb
) {
1223 //activate_device(config.path);
1224 pci_dev
->config_cb(&config
);
1227 /* device is configured so we may move it out of scope */
1230 /* scan bus behind bridge device */
1231 //if (htype & PCI_HEADER_TYPE_BRIDGE && class == PCI_BASE_CLASS_BRIDGE) {
1232 if ( class == PCI_BASE_CLASS_BRIDGE
&&
1233 ( subclass
== PCI_SUBCLASS_BRIDGE_PCI
||
1234 subclass
== PCI_SUBCLASS_BRIDGE_HOST
) ) {
1236 if (subclass
== PCI_SUBCLASS_BRIDGE_PCI
) {
1237 /* reserve next pci bus number for this PCI bridge */
1241 ob_configure_pci_bridge(addr
, bus_num
, mem_base
, io_base
, bus
, &config
);
1245 int ob_pci_init(void)
1247 int bus
, devnum
, fn
;
1248 uint8_t class, subclass
;
1249 unsigned long mem_base
, io_base
;
1251 pci_config_t config
= {}; /* host bridge */
1252 phandle_t phandle_host
;
1254 PCI_DPRINTF("Initializing PCI host bridge...\n");
1256 activate_device("/");
1258 /* Find all PCI bridges */
1260 mem_base
= arch
->pci_mem_base
;
1261 /* I/O ports under 0x400 are used by devices mapped at fixed
1263 io_base
= arch
->io_base
+ 0x400;
1267 for (devnum
= 0; devnum
< 32; devnum
++) {
1268 /* scan only fn 0 */
1271 if (!ob_pci_read_identification(bus
, devnum
, fn
,
1272 0, 0, &class, &subclass
)) {
1276 if (class != PCI_BASE_CLASS_BRIDGE
|| subclass
!= PCI_SUBCLASS_BRIDGE_HOST
) {
1280 /* create root node for host PCI bridge */
1283 snprintf(config
.path
, sizeof(config
.path
), "/pci");
1285 REGISTER_NAMED_NODE_PHANDLE(ob_pci_bus_node
, config
.path
, phandle_host
);
1287 pci_host_set_reg(phandle_host
);
1289 /* update device path after changing "reg" property */
1290 ob_pci_reload_device_path(phandle_host
, &config
);
1292 ob_configure_pci_device(config
.path
, &bus
, &mem_base
, &io_base
,
1293 bus
, devnum
, fn
, 0);
1295 /* we expect single host PCI bridge
1296 but this may be machine-specific */