diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/devices/pci_device.c | 146 | ||||
-rw-r--r-- | src/include/device/pci_def.h | 13 | ||||
-rw-r--r-- | src/mainboard/arima/hdama/mptable.c | 32 | ||||
-rw-r--r-- | src/southbridge/amd/amd8131/amd8131_bridge.c | 22 |
4 files changed, 189 insertions, 24 deletions
diff --git a/src/devices/pci_device.c b/src/devices/pci_device.c index 1c6498c167..a951aa5c5c 100644 --- a/src/devices/pci_device.c +++ b/src/devices/pci_device.c @@ -473,7 +473,8 @@ unsigned int pci_scan_bus(struct device *bus, unsigned int max) struct device *old_devices; struct device *child; #if HYPERTRANSPORT_SUPPORT - unsigned next_unitid, last_unitid; + unsigned next_unitid, last_unitid, previous_unitid; + int reset_needed; #endif printk_debug("PCI: pci_scan_bus for bus %d\n", bus->secondary); @@ -486,17 +487,65 @@ unsigned int pci_scan_bus(struct device *bus, unsigned int max) #if HYPERTRANSPORT_SUPPORT + /* Spin through the devices and collapse any early + * hypertransport enumeration. + */ + for(devfn = 0; devfn <= 0xff; devfn += 8) { + struct device dummy; + uint32_t id; + uint8_t hdr_type, pos; + dummy.bus = bus; + dummy.devfn = devfn; + id = pci_read_config32(&dummy, PCI_VENDOR_ID); + if (id == 0xffffffff || id == 0x00000000 || + id == 0x0000ffff || id == 0xffff0000) { + continue; + } + hdr_type = pci_read_config8(&dummy, PCI_HEADER_TYPE); + pos = 0; + switch(hdr_type & 0x7f) { + case PCI_HEADER_TYPE_NORMAL: + case PCI_HEADER_TYPE_BRIDGE: + pos = PCI_CAPABILITY_LIST; + break; + } + if (pos > PCI_CAP_LIST_NEXT) { + pos = pci_read_config8(&dummy, pos); + } + while(pos != 0) { + uint8_t cap; + cap = pci_read_config8(&dummy, pos + PCI_CAP_LIST_ID); + printk_debug("Capability: 0x%02x @ 0x%02x\n", cap, pos); + if (cap == PCI_CAP_ID_HT) { + uint16_t flags; + flags = pci_read_config16(&dummy, pos + PCI_CAP_FLAGS); + printk_debug("flags: 0x%04x\n", (unsigned)flags); + if ((flags >> 13) == 0) { + /* Clear the unitid */ + flags &= ~0x1f; + pci_write_config16(&dummy, pos + PCI_CAP_FLAGS, flags); + break; + } + } + pos = pci_read_config8(&dummy, pos + PCI_CAP_LIST_NEXT); + } + } /* If present assign unitid to a hypertransport chain */ + last_unitid = 0; next_unitid = 1; do { struct device dummy; uint32_t id; - uint8_t hdr_type, pos; + uint8_t hdr_type, pos, previous_pos; + + previous_unitid = last_unitid; last_unitid = next_unitid; + /* Read the next unassigned device off the stack */ dummy.bus = bus; dummy.devfn = 0; id = pci_read_config32(&dummy, PCI_VENDOR_ID); + /* If the chain is enumerated quit */ if (id == 0xffffffff || id == 0x00000000 || id == 0x0000ffff || id == 0xffff0000) { break; @@ -512,28 +561,111 @@ unsigned int pci_scan_bus(struct device *bus, unsigned int max) if (pos > PCI_CAP_LIST_NEXT) { pos = pci_read_config8(&dummy, pos); } - while(pos != 0) { + while(pos != 0) { /* loop through the linked list */ uint8_t cap; cap = pci_read_config8(&dummy, pos + PCI_CAP_LIST_ID); printk_debug("Capability: 0x%02x @ 0x%02x\n", cap, pos); if (cap == PCI_CAP_ID_HT) { uint16_t flags; + uint16_t links; flags = pci_read_config16(&dummy, pos + PCI_CAP_FLAGS); printk_debug("flags: 0x%04x\n", (unsigned)flags); - if ((flags >> 13) == 0) { + if ((flags >> 13) == 0) { /* Entry is a Slave secondary */ + struct device last, previous; unsigned count; - flags &= ~0x1f; - flags |= next_unitid & 0x1f; - count = (flags >> 5) & 0x1f; + unsigned width; + flags &= ~0x1f; /* mask out base unit ID */ + flags |= next_unitid & 0x1f; /* assign ID */ + count = (flags >> 5) & 0x1f; /* get unit count */ printk_debug("unitid: 0x%02x, count: 0x%02x\n", next_unitid, count); pci_write_config16(&dummy, pos + PCI_CAP_FLAGS, flags); next_unitid += count; + + if (previous_unitid == 0) { /* the link is back to the host */ + /* calculate the previous pos for the host */ + previous_pos = 0x80; + previous.bus = 0; + previous.devfn = 0x18 << 3; +#warning "FIXME we should not hard code this!" + } else { + previous.bus = bus; + previous.devfn = previous_unitid << 3; + } + last.bus = bus; + last.devfn = last_unitid << 3; + /* Set link width and frequency */ + flags = pci_read_config16(&last, pos + PCI_HT_CAP_SLAVE_FREQ_CAP0); + cap = pci_read_config8(&last, pos + PCI_HT_CAP_SLAVE_WIDTH0); + if(previous_unitid == 0) { /* the link is back to the host */ + links = pci_read_config16(&previous, + previous_pos + PCI_HT_CAP_HOST_FREQ_CAP); + width = pci_read_config8(&previous, + previous_pos + PCI_HT_CAP_HOST_WIDTH); + } + else { /* The link is back up the chain */ + links = pci_read_config16(&previous, + previous_pos + PCI_HT_CAP_SLAVE_FREQ_CAP1); + width = pci_read_config8(&previous, + previous_pos + PCI_HT_CAP_SLAVE_WIDTH1); + } + /* Calculate the highest possible frequency */ + links &= flags; + for(flags = 0x40, count = 6; count; count--, flags >>= 1) { + if(flags & links) break; + } + /* Calculate the highest width */ + width &= cap; + /* set the present device */ + if(count != pci_read_config8(&last, pos + PCI_HT_CAP_HOST_FREQ)) { + pci_write_config8(&last, pos + PCI_HT_CAP_HOST_FREQ, count); + reset_needed = 1; + } + if(width != pci_read_config8(&last, pos + PCI_HT_CAP_SLAVE_WIDTH0 + 1)) { + pci_write_config8(&last, + pos + PCI_HT_CAP_SLAVE_WIDTH0 + 1, width); + reset_needed = 1; + } + + /* set the upstream device */ + if(previous_unitid == 0) { /* the link is back to the host */ + cap = pci_read_config8(&previous, previous_pos + PCI_HT_CAP_HOST_FREQ); + cap &= 0x0f; + if(count != cap) { + pci_write_config8(&previous, + previous_pos + PCI_HT_CAP_HOST_FREQ, count); + reset_needed = 1; + } + cap = pci_read_config8(&previous, previous_pos + PCI_HT_CAP_HOST_WIDTH + 1); + if(width != cap) { + pci_write_config8(&previous, + previous_pos + PCI_HT_CAP_HOST_WIDTH + 1, width); + reset_needed = 1; + } + } + else { /* The link is back up the chain */ + cap = pci_read_config8(&previous, + previous_pos + PCI_HT_CAP_SLAVE_FREQ1); + cap &= 0x0f; + if(count != cap) { + pci_write_config8(&previous, + previous_pos + PCI_HT_CAP_SLAVE_FREQ1, count); + reset_needed = 1; + } + cap = pci_read_config8(&previous, + previous_pos + PCI_HT_CAP_SLAVE_WIDTH1 + 1); + if(width != cap) { + pci_write_config8(&previous, + previous_pos + PCI_HT_CAP_SLAVE_WIDTH1, width); + reset_needed = 1; + } + } break; } } pos = pci_read_config8(&dummy, pos + PCI_CAP_LIST_NEXT); } + previous_pos = pos; } while((last_unitid != next_unitid) && (next_unitid <= 0x1f)); #endif /* HYPERTRANSPORT_SUPPORT */ diff --git a/src/include/device/pci_def.h b/src/include/device/pci_def.h index 6a22cbe67f..ad8f1e6b88 100644 --- a/src/include/device/pci_def.h +++ b/src/include/device/pci_def.h @@ -182,7 +182,18 @@ #define PCI_CAP_ID_HT 0x08 #define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ #define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ -#define PCI_CAP_SIZEOF 4 + +/* Hypertransport Registers */ +#define PCI_HT_CAP_SIZEOF 4 +#define PCI_HT_CAP_HOST_WIDTH 6 /* width value & capability */ +#define PCI_HT_CAP_HOST_FREQ 0x09 /* Host frequency */ +#define PCI_HT_CAP_HOST_FREQ_CAP 0x0a /* Host Frequency capability */ +#define PCI_HT_CAP_SLAVE_WIDTH0 6 /* width value & capability */ +#define PCI_HT_CAP_SLAVE_WIDTH1 0x0a /* width value & capability to */ +#define PCI_HT_CAP_SLAVE_FREQ0 0x0d /* Slave frequency from */ +#define PCI_HT_CAP_SLAVE_FREQ1 0x011 /* Slave frequency to */ +#define PCI_HT_CAP_SLAVE_FREQ_CAP0 0x0e /* Frequency capability from */ +#define PCI_HT_CAP_SLAVE_FREQ_CAP1 0x12 /* Frequency capability to */ /* Power Management Registers */ diff --git a/src/mainboard/arima/hdama/mptable.c b/src/mainboard/arima/hdama/mptable.c index 43c122e129..856288590d 100644 --- a/src/mainboard/arima/hdama/mptable.c +++ b/src/mainboard/arima/hdama/mptable.c @@ -150,43 +150,43 @@ void *smp_write_config_table(void *v, unsigned long * processor_map) /* PCI Slot 1 */ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, - bus_8131_2, (1<<2)|0, 0x04, 0x1); + bus_8131_2, (1<<2)|0, 0x02, 0x11); smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, - bus_8131_2, (1<<2)|1, 0x04, 0x2); + bus_8131_2, (1<<2)|1, 0x02, 0x12); smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, - bus_8131_2, (1<<2)|2, 0x04, 0x3); + bus_8131_2, (1<<2)|2, 0x02, 0x13); smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, - bus_8131_2, (1<<2)|3, 0x04, 0x0); + bus_8131_2, (1<<2)|3, 0x02, 0x10); /* PCI Slot 2 */ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, - bus_8131_2, (2<<2)|0, 0x04, 0x2); + bus_8131_2, (2<<2)|0, 0x02, 0x12); smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, - bus_8131_2, (2<<2)|1, 0x04, 0x3); + bus_8131_2, (2<<2)|1, 0x02, 0x13); smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, - bus_8131_2, (2<<2)|2, 0x04, 0x0); + bus_8131_2, (2<<2)|2, 0x02, 0x10); smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, - bus_8131_2, (2<<2)|3, 0x04, 0x1); + bus_8131_2, (2<<2)|3, 0x02, 0x11); /* PCI Slot 3 */ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, - bus_8131_1, (1<<2)|0, 0x03, 0x1); + bus_8131_1, (1<<2)|0, 0x02, 0x11); smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, - bus_8131_1, (1<<2)|1, 0x03, 0x2); + bus_8131_1, (1<<2)|1, 0x02, 0x12); smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, - bus_8131_1, (1<<2)|2, 0x03, 0x3); + bus_8131_1, (1<<2)|2, 0x02, 0x13); smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, - bus_8131_1, (1<<2)|3, 0x03, 0x0); + bus_8131_1, (1<<2)|3, 0x02, 0x10); /* PCI Slot 4 */ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, - bus_8131_1, (2<<2)|0, 0x03, 0x2); + bus_8131_1, (2<<2)|0, 0x02, 0x12); smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, - bus_8131_1, (2<<2)|1, 0x03, 0x3); + bus_8131_1, (2<<2)|1, 0x02, 0x13); smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, - bus_8131_1, (2<<2)|2, 0x03, 0x0); + bus_8131_1, (2<<2)|2, 0x02, 0x10); smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_DEFAULT|MP_IRQ_POLARITY_DEFAULT, - bus_8131_1, (2<<2)|3, 0x03, 0x1); + bus_8131_1, (2<<2)|3, 0x02, 0x11); /* PCI Slot 5 */ #warning "FIXME get the irqs right, it's just hacked to work for now" diff --git a/src/southbridge/amd/amd8131/amd8131_bridge.c b/src/southbridge/amd/amd8131/amd8131_bridge.c index 9ef83da50d..ded5480234 100644 --- a/src/southbridge/amd/amd8131/amd8131_bridge.c +++ b/src/southbridge/amd/amd8131/amd8131_bridge.c @@ -9,6 +9,28 @@ static void pcix_init(device_t dev) { + uint16_t word; + uint8_t byte; + + + /* Enable memory write and invalidate ??? */ + byte = pci_read_config8(dev, 0x04); + byte |= 0x10; + pci_write_config8(dev, 0x04, byte); + + /* Set drive strength */ + word = pci_read_config16(dev, 0xe0); + word = 0x0404; + pci_write_config16(dev, 0xe0, word); + word = pci_read_config16(dev, 0xe4); + word = 0x0404; + pci_write_config16(dev, 0xe4, word); + + /* Set impedance */ + word = pci_read_config16(dev, 0xe8); + word = 0x0404; + pci_write_config16(dev, 0xe8, word); + return; } |