| /* |
| * (C) 2003-2004 Linux Networx |
| */ |
| #include <console/console.h> |
| #include <device/device.h> |
| #include <device/pci.h> |
| #include <device/pci_ids.h> |
| #include <device/pci_ops.h> |
| #include <device/pcix.h> |
| #include <pc80/mc146818rtc.h> |
| #include <delay.h> |
| #include "pxhd.h" |
| |
| static void pxhd_enable(device_t dev) |
| { |
| device_t bridge; |
| uint16_t value; |
| if ((dev->path.u.pci.devfn & 1) == 0) { |
| /* Can we enable/disable the bridges? */ |
| return; |
| } |
| bridge = dev_find_slot(dev->bus->secondary, dev->path.u.pci.devfn & ~1); |
| if (!bridge) { |
| printk_err("Cannot find bridge for ioapic: %s\n", |
| dev_path(dev)); |
| return; |
| } |
| value = pci_read_config16(bridge, 0x40); |
| value &= ~(1 << 13); |
| if (!dev->enabled) { |
| value |= (1 << 13); |
| } |
| pci_write_config16(bridge, 0x40, value); |
| } |
| |
| |
| #define NMI_OFF 0 |
| |
| static unsigned int pxhd_scan_bridge(device_t dev, unsigned int max) |
| { |
| int bus_100Mhz = 0; |
| |
| dev->link[0].dev = dev; |
| dev->links = 1; |
| |
| get_option(&bus_100Mhz, "pxhd_bus_speed_100"); |
| if(bus_100Mhz) { |
| uint16_t word; |
| |
| printk_debug("setting pxhd bus to 100 Mhz\n"); |
| /* set to pcix 100 mhz */ |
| word = pci_read_config16(dev, 0x40); |
| word &= ~(3 << 14); |
| word |= (1 << 14); |
| word &= ~(3 << 9); |
| word |= (2 << 9); |
| pci_write_config16(dev, 0x40, word); |
| |
| /* reset the bus to make the new frequencies effective */ |
| pci_bus_reset(&dev->link[0]); |
| } |
| return pcix_scan_bridge(dev, max); |
| } |
| static void pcix_init(device_t dev) |
| { |
| uint32_t dword; |
| uint16_t word; |
| uint8_t byte; |
| int nmi_option; |
| |
| /* Bridge control ISA enable */ |
| pci_write_config8(dev, 0x3e, 0x07); |
| |
| #if 0 |
| |
| /* 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); |
| |
| /* Set discard unrequested prefetch data */ |
| word = pci_read_config16(dev, 0x4c); |
| word |= 1; |
| pci_write_config16(dev, 0x4c, word); |
| |
| /* Set split transaction limits */ |
| word = pci_read_config16(dev, 0xa8); |
| pci_write_config16(dev, 0xaa, word); |
| word = pci_read_config16(dev, 0xac); |
| pci_write_config16(dev, 0xae, word); |
| |
| /* Set up error reporting, enable all */ |
| /* system error enable */ |
| dword = pci_read_config32(dev, 0x04); |
| dword |= (1<<8); |
| pci_write_config32(dev, 0x04, dword); |
| |
| /* system and error parity enable */ |
| dword = pci_read_config32(dev, 0x3c); |
| dword |= (3<<16); |
| pci_write_config32(dev, 0x3c, dword); |
| |
| /* NMI enable */ |
| nmi_option = NMI_OFF; |
| get_option(&nmi_option, "nmi"); |
| if(nmi_option) { |
| dword = pci_read_config32(dev, 0x44); |
| dword |= (1<<0); |
| pci_write_config32(dev, 0x44, dword); |
| } |
| |
| /* Set up CRC flood enable */ |
| dword = pci_read_config32(dev, 0xc0); |
| if(dword) { /* do device A only */ |
| dword = pci_read_config32(dev, 0xc4); |
| dword |= (1<<1); |
| pci_write_config32(dev, 0xc4, dword); |
| dword = pci_read_config32(dev, 0xc8); |
| dword |= (1<<1); |
| pci_write_config32(dev, 0xc8, dword); |
| } |
| |
| return; |
| #endif |
| } |
| |
| static struct device_operations pcix_ops = { |
| .read_resources = pci_bus_read_resources, |
| .set_resources = pci_dev_set_resources, |
| .enable_resources = pci_bus_enable_resources, |
| .init = pcix_init, |
| .scan_bus = pxhd_scan_bridge, |
| .reset_bus = pci_bus_reset, |
| .ops_pci = 0, |
| }; |
| |
| static const struct pci_driver pcix_driver __pci_driver = { |
| .ops = &pcix_ops, |
| .vendor = PCI_VENDOR_ID_INTEL, |
| .device = 0x0329, |
| }; |
| |
| static const struct pci_driver pcix_driver2 __pci_driver = { |
| .ops = &pcix_ops, |
| .vendor = PCI_VENDOR_ID_INTEL, |
| .device = 0x032a, |
| }; |
| |
| #define ALL (0xff << 24) |
| #define NONE (0) |
| #define DISABLED (1 << 16) |
| #define ENABLED (0 << 16) |
| #define TRIGGER_EDGE (0 << 15) |
| #define TRIGGER_LEVEL (1 << 15) |
| #define POLARITY_HIGH (0 << 13) |
| #define POLARITY_LOW (1 << 13) |
| #define PHYSICAL_DEST (0 << 11) |
| #define LOGICAL_DEST (1 << 11) |
| #define ExtINT (7 << 8) |
| #define NMI (4 << 8) |
| #define SMI (2 << 8) |
| #define INT (1 << 8) |
| /* IO-APIC virtual wire mode configuration */ |
| /* mask, trigger, polarity, destination, delivery, vector */ |
| |
| static void setup_ioapic(device_t dev) |
| { |
| int i; |
| unsigned long value_low, value_high; |
| unsigned long ioapic_base; |
| volatile unsigned long *l; |
| unsigned interrupts; |
| |
| ioapic_base = pci_read_config32(dev, PCI_BASE_ADDRESS_0); |
| l = (unsigned long *) ioapic_base; |
| |
| /* Enable front side bus delivery */ |
| l[0] = 0x03; |
| l[4] = 1; |
| |
| l[0] = 0x01; |
| interrupts = (l[04] >> 16) & 0xff; |
| for (i = 0; i < interrupts; i++) { |
| l[0] = (i * 2) + 0x10; |
| l[4] = DISABLED; |
| value_low = l[4]; |
| l[0] = (i * 2) + 0x11; |
| l[4] = NONE; /* Should this be an address? */ |
| value_high = l[4]; |
| if (value_low == 0xffffffff) { |
| printk_warning("IO APIC not responding.\n"); |
| return; |
| } |
| } |
| } |
| |
| static void ioapic_init(device_t dev) |
| { |
| uint32_t value; |
| /* Enable bus mastering so IOAPICs work */ |
| value = pci_read_config16(dev, PCI_COMMAND); |
| value |= PCI_COMMAND_MASTER; |
| pci_write_config16(dev, PCI_COMMAND, value); |
| |
| setup_ioapic(dev); |
| } |
| |
| static void intel_set_subsystem(device_t dev, unsigned vendor, unsigned device) |
| { |
| pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, |
| ((device & 0xffff) << 16) | (vendor & 0xffff)); |
| } |
| |
| static struct pci_operations intel_ops_pci = { |
| .set_subsystem = intel_set_subsystem, |
| }; |
| |
| static struct device_operations ioapic_ops = { |
| .read_resources = pci_dev_read_resources, |
| .set_resources = pci_dev_set_resources, |
| .enable_resources = pci_dev_enable_resources, |
| .init = ioapic_init, |
| .scan_bus = 0, |
| .enable = pxhd_enable, |
| .ops_pci = &intel_ops_pci, |
| }; |
| |
| static const struct pci_driver ioapic_driver __pci_driver = { |
| .ops = &ioapic_ops, |
| .vendor = PCI_VENDOR_ID_INTEL, |
| .device = 0x0326, |
| |
| }; |
| |
| static const struct pci_driver ioapic2_driver __pci_driver = { |
| .ops = &ioapic_ops, |
| .vendor = PCI_VENDOR_ID_INTEL, |
| .device = 0x0327, |
| |
| }; |
| |
| struct chip_operations southbridge_intel_pxhd_ops = { |
| CHIP_NAME("Intel PXHD Southbridge") |
| .enable_dev = pxhd_enable, |
| }; |