2 * This file is part of the coreboot 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.
22 #include <console/console.h>
26 #include <device/device.h>
27 #include <device/pci.h>
28 #include <device/pci_ids.h>
29 #include <device/pci_ops.h>
32 static uint32_t final_reg
;
34 static device_t
find_lpc_dev( device_t dev
, unsigned devfn
)
39 lpc_dev
= dev_find_slot(dev
->bus
->secondary
, devfn
);
41 if ( !lpc_dev
) return lpc_dev
;
43 if ((lpc_dev
->vendor
!= PCI_VENDOR_ID_SIS
) || (
44 (lpc_dev
->device
!= PCI_DEVICE_ID_SIS_SIS966_LPC
)
47 id
= pci_read_config32(lpc_dev
, PCI_VENDOR_ID
);
48 if ( (id
< (PCI_VENDOR_ID_SIS
| (PCI_DEVICE_ID_SIS_SIS966_LPC
<< 16)))
57 void sis966_enable(device_t dev
)
63 uint32_t reg_old
, reg
;
69 struct southbridge_sis_sis966_config
*conf
;
70 conf
= dev
->chip_info
;
73 if(dev
->device
==0x0000) {
74 vendorid
= pci_read_config32(dev
, PCI_VENDOR_ID
);
75 deviceid
= (vendorid
>>16) & 0xffff;
76 // vendorid &= 0xffff;
78 // vendorid = dev->vendor;
79 deviceid
= dev
->device
;
82 devfn
= (dev
->path
.pci
.devfn
) & ~7;
84 case PCI_DEVICE_ID_SIS_SIS966_USB
:
88 case PCI_DEVICE_ID_SIS_SIS966_USB2
:
92 case PCI_DEVICE_ID_SIS_SIS966_NIC
:
96 lpc_dev
= find_lpc_dev(dev
, devfn
- (i
<<3));
97 if(!lpc_dev
) continue;
103 case PCI_DEVICE_ID_SIS_SIS966_HD_AUDIO
:
107 case PCI_DEVICE_ID_SIS_SIS966_IDE
:
111 case PCI_DEVICE_ID_SIS_SIS966_SATA
:
114 i
= (dev
->path
.pci
.devfn
) & 7;
119 case PCI_DEVICE_ID_SIS_SIS966_PCIE
:
120 devfn
-= (0x9<<3); // to LPC
128 lpc_dev
= find_lpc_dev(dev
, devfn
);
130 if ( !lpc_dev
) return;
133 sm_dev
= dev_find_slot(dev
->bus
->secondary
, devfn
+ 1);
137 reg_old
= reg
= pci_read_config32(sm_dev
, 0xe4);
139 if (!dev
->enabled
) { //disable it
143 if (reg
!= reg_old
) {
144 pci_write_config32(sm_dev
, 0xe4, reg
);
153 if ( index
== 0) { // for LPC
155 // expose ioapic base
156 byte
= pci_read_config8(lpc_dev
, 0x74);
157 byte
|= ((1<<1)); // expose the BAR
158 pci_write_config8(dev
, 0x74, byte
);
161 byte
= pci_read_config8(lpc_dev
, 0xdd);
162 byte
|= ((1<<0)|(1<<3)); // expose the BAR and enable write
163 pci_write_config8(dev
, 0xdd, byte
);
169 sm_dev
= dev_find_slot(dev
->bus
->secondary
, devfn
+ 1);
172 final_reg
= pci_read_config32(sm_dev
, 0xe8);
173 final_reg
&= ~0x0057cf00;
174 pci_write_config32(sm_dev
, 0xe8, final_reg
); //enable all at first
178 final_reg
|= (1 << index
);// disable it
180 * The reason for using final_reg is that if func 1 is disabled,
181 * then func 2 will become func 1.
182 * Because of this, we need loop through disabling them all at
187 if(index
== 9 ) { //NIC1 is the final, We need update final reg to 0xe8
188 sm_dev
= dev_find_slot(dev
->bus
->secondary
, devfn
+ 1);
190 reg_old
= pci_read_config32(sm_dev
, 0xe8);
191 if (final_reg
!= reg_old
) {
192 pci_write_config32(sm_dev
, 0xe8, final_reg
);
198 struct chip_operations southbridge_sis_sis966_ops
= {
199 CHIP_NAME("SiS SiS966 Southbridge")
200 .enable_dev
= sis966_enable
,