2 * This file is part of the LinuxBIOS project.
4 * Copyright (C) 2004 Tyan Computer
5 * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer.
6 * Copyright (C) 2006,2007 AMD
7 * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD.
8 * Copyright (C) 2007 Silicon Integrated Systems Corp. (SiS)
9 * Written by Morgan Tsai <my_tsai@sis.com> for SiS.
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 #include <console/console.h>
30 #include <device/device.h>
31 #include <device/pci.h>
32 #include <device/pci_ids.h>
33 #include <device/pci_ops.h>
36 static uint32_t final_reg;
38 static device_t find_lpc_dev( device_t dev, unsigned devfn)
43 lpc_dev = dev_find_slot(dev->bus->secondary, devfn);
45 if ( !lpc_dev ) return lpc_dev;
47 if ((lpc_dev->vendor != PCI_VENDOR_ID_SIS) || (
48 (lpc_dev->device != PCI_DEVICE_ID_SIS_SIS966_LPC)
51 id = pci_read_config32(lpc_dev, PCI_VENDOR_ID);
52 if ( (id < (PCI_VENDOR_ID_SIS | (PCI_DEVICE_ID_SIS_SIS966_LPC << 16)))
61 void sis966_enable(device_t dev)
67 uint32_t reg_old, reg;
73 struct southbridge_sis_sis966_config *conf;
74 conf = dev->chip_info;
77 if(dev->device==0x0000) {
78 vendorid = pci_read_config32(dev, PCI_VENDOR_ID);
79 deviceid = (vendorid>>16) & 0xffff;
80 // vendorid &= 0xffff;
82 // vendorid = dev->vendor;
83 deviceid = dev->device;
86 devfn = (dev->path.u.pci.devfn) & ~7;
88 case PCI_DEVICE_ID_SIS_SIS966_USB:
92 case PCI_DEVICE_ID_SIS_SIS966_USB2:
96 case PCI_DEVICE_ID_SIS_SIS966_NIC:
100 lpc_dev = find_lpc_dev(dev, devfn - (i<<3));
101 if(!lpc_dev) continue;
107 case PCI_DEVICE_ID_SIS_SIS966_HD_AUDIO:
111 case PCI_DEVICE_ID_SIS_SIS966_IDE:
115 case PCI_DEVICE_ID_SIS_SIS966_SATA:
118 i = (dev->path.u.pci.devfn) & 7;
123 case PCI_DEVICE_ID_SIS_SIS966_PCIE:
124 devfn -= (0x9<<3); // to LPC
132 lpc_dev = find_lpc_dev(dev, devfn);
134 if ( !lpc_dev ) return;
137 sm_dev = dev_find_slot(dev->bus->secondary, devfn + 1);
141 reg_old = reg = pci_read_config32(sm_dev, 0xe4);
143 if (!dev->enabled) { //disable it
147 if (reg != reg_old) {
148 pci_write_config32(sm_dev, 0xe4, reg);
157 if ( index == 0) { // for LPC
159 // expose ioapic base
160 byte = pci_read_config8(lpc_dev, 0x74);
161 byte |= ((1<<1)); // expose the BAR
162 pci_write_config8(dev, 0x74, byte);
165 byte = pci_read_config8(lpc_dev, 0xdd);
166 byte |= ((1<<0)|(1<<3)); // expose the BAR and enable write
167 pci_write_config8(dev, 0xdd, byte);
173 sm_dev = dev_find_slot(dev->bus->secondary, devfn + 1);
176 final_reg = pci_read_config32(sm_dev, 0xe8);
177 final_reg &= ~0x0057cf00;
178 pci_write_config32(sm_dev, 0xe8, final_reg); //enable all at first
182 final_reg |= (1 << index);// disable it
183 //The reason for using final_reg, if diable func 1, the func 2 will be func 1 so We need disable them one time.
186 if(index == 9 ) { //NIC1 is the final, We need update final reg to 0xe8
187 sm_dev = dev_find_slot(dev->bus->secondary, devfn + 1);
189 reg_old = pci_read_config32(sm_dev, 0xe8);
190 if (final_reg != reg_old) {
191 pci_write_config32(sm_dev, 0xe8, final_reg);
197 struct chip_operations southbridge_sis_sis966_ops = {
198 CHIP_NAME("SiS SiS966 Southbridge")
199 .enable_dev = sis966_enable,