/* * Copyright 2004 Tyan Computer * by yhlu@tyan.com */ #include <console/console.h> #include <arch/io.h> #include <device/device.h> #include <device/pci.h> #include <device/pci_ids.h> #include <device/pci_ops.h> #include "ck804.h" static uint32_t final_reg; static device_t find_lpc_dev( device_t dev, unsigned devfn) { device_t lpc_dev; lpc_dev = dev_find_slot(dev->bus->secondary, devfn); if ( !lpc_dev ) return lpc_dev; if ((lpc_dev->vendor != PCI_VENDOR_ID_NVIDIA) || ( (lpc_dev->device != PCI_DEVICE_ID_NVIDIA_CK804_LPC) && (lpc_dev->device != PCI_DEVICE_ID_NVIDIA_CK804_PRO) && (lpc_dev->device != PCI_DEVICE_ID_NVIDIA_CK804_SLAVE)) ) { uint32_t id; id = pci_read_config32(lpc_dev, PCI_VENDOR_ID); if ( (id != (PCI_VENDOR_ID_NVIDIA | (PCI_DEVICE_ID_NVIDIA_CK804_LPC << 16))) && (id != (PCI_VENDOR_ID_NVIDIA | (PCI_DEVICE_ID_NVIDIA_CK804_PRO << 16))) && (id != (PCI_VENDOR_ID_NVIDIA | (PCI_DEVICE_ID_NVIDIA_CK804_SLAVE << 16))) ) { lpc_dev = 0; } } return lpc_dev; } void ck804_enable(device_t dev) { device_t lpc_dev; unsigned index = 0; unsigned index2 = 0; uint32_t reg_old, reg; uint8_t byte; unsigned deviceid; unsigned vendorid; struct southbridge_nvidia_ck804_config *conf; conf = dev->chip_info; unsigned devfn; if(dev->device==0x0000) { vendorid = pci_read_config32(dev, PCI_VENDOR_ID); deviceid = (vendorid>>16) & 0xffff; // vendorid &= 0xffff; } else { // vendorid = dev->vendor; deviceid = dev->device; } devfn = (dev->path.u.pci.devfn) & ~7; switch(deviceid) { case PCI_DEVICE_ID_NVIDIA_CK804_SM: index = 16; break; case PCI_DEVICE_ID_NVIDIA_CK804_USB: devfn -= (1<<3); index = 8; break; case PCI_DEVICE_ID_NVIDIA_CK804_USB2: devfn -= (1<<3); index = 20; break; case PCI_DEVICE_ID_NVIDIA_CK804_NIC: devfn -= (9<<3); index = 10; dev->rom_address = conf->nic_rom_address; break; case PCI_DEVICE_ID_NVIDIA_CK804_NIC_BRIDGE: devfn -= (9<<3); index = 10; dev->rom_address = conf->nic_rom_address; break; case PCI_DEVICE_ID_NVIDIA_CK804_ACI: devfn -= (3<<3); index = 12; break; case PCI_DEVICE_ID_NVIDIA_CK804_MCI: devfn -= (3<<3); index = 13; break; case PCI_DEVICE_ID_NVIDIA_CK804_IDE: devfn -= (5<<3); index = 14; dev->rom_address = conf->raid_rom_address; break; case PCI_DEVICE_ID_NVIDIA_CK804_SATA0: devfn -= (6<<3); index = 22; break; case PCI_DEVICE_ID_NVIDIA_CK804_SATA1: devfn -= (7<<3); index = 18; break; case PCI_DEVICE_ID_NVIDIA_CK804_PCI: devfn -= (8<<3); index = 15; break; case PCI_DEVICE_ID_NVIDIA_CK804_PCI_E: devfn -= (0xa<<3); index2 = 19; break; default: index = 0; } if(index2!=0) { int i; for(i=0;i<4;i++) { lpc_dev = find_lpc_dev(dev, devfn - (i<<3)); if(!lpc_dev) continue; index2 -= i; break; } if ( lpc_dev ) { reg_old = reg = pci_read_config32(lpc_dev, 0xe4); if (!dev->enabled) { reg |= (1<<index2); } if (reg != reg_old) { pci_write_config32(lpc_dev, 0xe4, reg); } } index2 = 0; return; } lpc_dev = find_lpc_dev(dev, devfn); if ( !lpc_dev ) return; if ( index == 0) { final_reg = pci_read_config32(lpc_dev, 0xe8); final_reg &= ~((1<<16)|(1<<8)|(1<<20)|(1<<10)|(1<<12)|(1<<13)|(1<<14)|(1<<22)|(1<<18)|(1<<15)); pci_write_config32(lpc_dev, 0xe8, final_reg); #if 1 reg_old = reg = pci_read_config32(lpc_dev, 0xe4); reg |= (1<<20); if (reg != reg_old) { pci_write_config32(lpc_dev, 0xe4, reg); } #endif byte = pci_read_config8(lpc_dev, 0x74); byte |= ((1<<1)); pci_write_config8(dev, 0x74, byte); byte = pci_read_config8(lpc_dev, 0xdd); byte |= ((1<<0)|(1<<3)); pci_write_config8(dev, 0xdd, byte); return; } if (!dev->enabled) { final_reg |= (1 << index); } if(index == 10 ) { reg_old = pci_read_config32(lpc_dev, 0xe8); if (final_reg != reg_old) { pci_write_config32(lpc_dev, 0xe8, final_reg); } } } struct chip_operations southbridge_nvidia_ck804_ops = { CHIP_NAME("Nvidia ck804") .enable_dev = ck804_enable, };