blob: 86033fe3bf277620d10d36d8cda7bba9a843e551 [file] [log] [blame]
Morgan Tsai1602dd52007-10-29 21:00:14 +00001/*
2 * This file is part of the LinuxBIOS project.
3 *
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.
10 *
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.
15 *
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.
20 *
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
24 */
25
26#include <console/console.h>
27
28#include <arch/io.h>
29
30#include <device/device.h>
31#include <device/pci.h>
32#include <device/pci_ids.h>
33#include <device/pci_ops.h>
34#include "sis966.h"
35
36static uint32_t final_reg;
37
38static device_t find_lpc_dev( device_t dev, unsigned devfn)
39{
40
41 device_t lpc_dev;
42
43 lpc_dev = dev_find_slot(dev->bus->secondary, devfn);
44
45 if ( !lpc_dev ) return lpc_dev;
46
47if ((lpc_dev->vendor != PCI_VENDOR_ID_SIS) || (
48 (lpc_dev->device != PCI_DEVICE_ID_SIS_SIS966_LPC)
49 ) ) {
50 uint32_t id;
51 id = pci_read_config32(lpc_dev, PCI_VENDOR_ID);
Morgan Tsai218c2652007-11-02 16:09:58 +000052 if ( (id < (PCI_VENDOR_ID_SIS | (PCI_DEVICE_ID_SIS_SIS966_LPC << 16)))
Morgan Tsai1602dd52007-10-29 21:00:14 +000053 ) {
54 lpc_dev = 0;
55 }
56 }
57
58 return lpc_dev;
59}
60
61void sis966_enable(device_t dev)
62{
63 device_t lpc_dev = 0;
64 device_t sm_dev = 0;
Morgan Tsai218c2652007-11-02 16:09:58 +000065 uint16_t index = 0;
66 uint16_t index2 = 0;
Morgan Tsai1602dd52007-10-29 21:00:14 +000067 uint32_t reg_old, reg;
68 uint8_t byte;
Morgan Tsai218c2652007-11-02 16:09:58 +000069 uint16_t deviceid;
70 uint16_t vendorid;
71 uint16_t devfn;
Morgan Tsai1602dd52007-10-29 21:00:14 +000072
73 struct southbridge_sis_sis966_config *conf;
74 conf = dev->chip_info;
75 int i;
76
Morgan Tsai1602dd52007-10-29 21:00:14 +000077 if(dev->device==0x0000) {
78 vendorid = pci_read_config32(dev, PCI_VENDOR_ID);
79 deviceid = (vendorid>>16) & 0xffff;
80// vendorid &= 0xffff;
81 } else {
82// vendorid = dev->vendor;
83 deviceid = dev->device;
84 }
85
86 devfn = (dev->path.u.pci.devfn) & ~7;
87 switch(deviceid) {
88 case PCI_DEVICE_ID_SIS_SIS966_HT:
89 return;
Morgan Tsai1602dd52007-10-29 21:00:14 +000090 break;
91 case PCI_DEVICE_ID_SIS_SIS966_USB:
92 devfn -= (1<<3);
93 index = 8;
94 break;
Morgan Tsai218c2652007-11-02 16:09:58 +000095 case PCI_DEVICE_ID_SIS_SIS966_USB2:
Morgan Tsai1602dd52007-10-29 21:00:14 +000096 devfn -= (1<<3);
97 index = 20;
98 break;
Morgan Tsai218c2652007-11-02 16:09:58 +000099 case PCI_DEVICE_ID_SIS_SIS966_NIC1:
Morgan Tsai1602dd52007-10-29 21:00:14 +0000100 devfn -= (7<<3);
101 index = 10;
102 for(i=0;i<2;i++) {
103 lpc_dev = find_lpc_dev(dev, devfn - (i<<3));
104 if(!lpc_dev) continue;
105 index -= i;
106 devfn -= (i<<3);
107 break;
108 }
109 break;
110 case PCI_DEVICE_ID_SIS_SIS966_AZA:
111 devfn -= (5<<3);
112 index = 11;
113 break;
114 case PCI_DEVICE_ID_SIS_SIS966_IDE:
115 devfn -= (3<<3);
116 index = 14;
117 break;
Morgan Tsai218c2652007-11-02 16:09:58 +0000118 case PCI_DEVICE_ID_SIS_SIS966_SATA0:
Morgan Tsai1602dd52007-10-29 21:00:14 +0000119 devfn -= (4<<3);
120 index = 22;
121 i = (dev->path.u.pci.devfn) & 7;
122 if(i>0) {
123 index -= (i+3);
124 }
125 break;
126 case PCI_DEVICE_ID_SIS_SIS966_PCI:
127 devfn -= (5<<3);
128 index = 15;
129 break;
Morgan Tsai218c2652007-11-02 16:09:58 +0000130 case PCI_DEVICE_ID_SIS_SIS966_PCIE_B_C:
Morgan Tsai1602dd52007-10-29 21:00:14 +0000131 devfn -= (0xa<<3); // to LPC
132 index2 = 8;
133 for(i=0;i<2;i++) {
134 lpc_dev = find_lpc_dev(dev, devfn - (i<<3));
135 if(!lpc_dev) continue;
136 index2 -= i;
137 devfn -= (i<<3);
138 break;
139 }
140 break;
141 case PCI_DEVICE_ID_SIS_SIS966_PCIE_D:
142 devfn -= (0xc<<3); // to LPC
143 index2 = 6;
144 break;
145 case PCI_DEVICE_ID_SIS_SIS966_PCIE_E:
146 devfn -= (0xd<<3); // to LPC
147 index2 = 5;
148 break;
149 case PCI_DEVICE_ID_SIS_SIS966_PCIE_F:
150 devfn -= (0xe<<3); // to LPC
151 index2 = 4;
152 break;
153 default:
154 index = 0;
155 }
156
157 if(!lpc_dev)
158 lpc_dev = find_lpc_dev(dev, devfn);
159
160 if ( !lpc_dev ) return;
161
162 if(index2!=0) {
163 sm_dev = dev_find_slot(dev->bus->secondary, devfn + 1);
164 if(!sm_dev) return;
165
166 if ( sm_dev ) {
167 reg_old = reg = pci_read_config32(sm_dev, 0xe4);
168
169 if (!dev->enabled) { //disable it
170 reg |= (1<<index2);
171 }
172
173 if (reg != reg_old) {
174 pci_write_config32(sm_dev, 0xe4, reg);
175 }
176 }
177
178 index2 = 0;
179 return;
180 }
181
182
183 if ( index == 0) { // for LPC
184
185 // expose ioapic base
186 byte = pci_read_config8(lpc_dev, 0x74);
187 byte |= ((1<<1)); // expose the BAR
188 pci_write_config8(dev, 0x74, byte);
189
190 // expose trap base
191 byte = pci_read_config8(lpc_dev, 0xdd);
192 byte |= ((1<<0)|(1<<3)); // expose the BAR and enable write
193 pci_write_config8(dev, 0xdd, byte);
194
195 return;
196
197 }
198
199 if( index == 16) {
200 sm_dev = dev_find_slot(dev->bus->secondary, devfn + 1);
201 if(!sm_dev) return;
202
203 final_reg = pci_read_config32(sm_dev, 0xe8);
Morgan Tsai218c2652007-11-02 16:09:58 +0000204 final_reg &= ~0x0057cf00;
Morgan Tsai1602dd52007-10-29 21:00:14 +0000205 pci_write_config32(sm_dev, 0xe8, final_reg); //enable all at first
Morgan Tsai1602dd52007-10-29 21:00:14 +0000206 }
207
208 if (!dev->enabled) {
209 final_reg |= (1 << index);// disable it
210 //The reason for using final_reg, if diable func 1, the func 2 will be func 1 so We need disable them one time.
211 }
212
213 if(index == 9 ) { //NIC1 is the final, We need update final reg to 0xe8
214 sm_dev = dev_find_slot(dev->bus->secondary, devfn + 1);
215 if(!sm_dev) return;
216 reg_old = pci_read_config32(sm_dev, 0xe8);
217 if (final_reg != reg_old) {
218 pci_write_config32(sm_dev, 0xe8, final_reg);
219 }
220
221 }
222
223
224}
225
226struct chip_operations southbridge_sis_sis966_ops = {
227 CHIP_NAME("SiS SiS966 Southbridge")
228 .enable_dev = sis966_enable,
229};