blob: b2ce8966994b2920ad09b57d5078399bcde8a331 [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);
52 if ( (id < (PCI_VENDOR_ID_SIS | (PCI_DEVICE_ID_SIS_SIS966_LPC << 16)))
53 ) {
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;
65 unsigned index = 0;
66 unsigned index2 = 0;
67 uint32_t reg_old, reg;
68 uint8_t byte;
69 unsigned deviceid;
70 unsigned vendorid;
71
72 struct southbridge_sis_sis966_config *conf;
73 conf = dev->chip_info;
74 int i;
75
76 unsigned devfn;
77
78 if(dev->device==0x0000) {
79 vendorid = pci_read_config32(dev, PCI_VENDOR_ID);
80 deviceid = (vendorid>>16) & 0xffff;
81// vendorid &= 0xffff;
82 } else {
83// vendorid = dev->vendor;
84 deviceid = dev->device;
85 }
86
87 devfn = (dev->path.u.pci.devfn) & ~7;
88 switch(deviceid) {
89 case PCI_DEVICE_ID_SIS_SIS966_HT:
90 return;
91
92 case PCI_DEVICE_ID_SIS_SIS966_SM2://?
93 index = 16;
94 break;
95 case PCI_DEVICE_ID_SIS_SIS966_USB:
96 devfn -= (1<<3);
97 index = 8;
98 break;
99 case PCI_DEVICE_ID_SIS_SIS966_EHCI:
100 devfn -= (1<<3);
101 index = 20;
102 break;
103/* case PCI_DEVICE_ID_SIS_SIS966_USB3:
104 devfn -= (1<<3);
105 index = 20;
106 break;
107*/
108 case PCI_DEVICE_ID_SIS_SIS966_NIC1: //two
109 case PCI_DEVICE_ID_SIS_SIS966_NIC_BRIDGE://two
110 devfn -= (7<<3);
111 index = 10;
112 for(i=0;i<2;i++) {
113 lpc_dev = find_lpc_dev(dev, devfn - (i<<3));
114 if(!lpc_dev) continue;
115 index -= i;
116 devfn -= (i<<3);
117 break;
118 }
119 break;
120 case PCI_DEVICE_ID_SIS_SIS966_AZA:
121 devfn -= (5<<3);
122 index = 11;
123 break;
124 case PCI_DEVICE_ID_SIS_SIS966_IDE:
125 devfn -= (3<<3);
126 index = 14;
127 break;
128 case PCI_DEVICE_ID_SIS_SIS966_SATA0: //three
129 case PCI_DEVICE_ID_SIS_SIS966_SATA1: //three
130 devfn -= (4<<3);
131 index = 22;
132 i = (dev->path.u.pci.devfn) & 7;
133 if(i>0) {
134 index -= (i+3);
135 }
136 break;
137 case PCI_DEVICE_ID_SIS_SIS966_PCI:
138 devfn -= (5<<3);
139 index = 15;
140 break;
141// case PCI_DEVICE_ID_SIS_SIS966_PCIE_A:
142// devfn -= (0x9<<3); // to LPC
143// index2 = 9;
144// break;
145 case PCI_DEVICE_ID_SIS_SIS966_PCIE_B_C: //two
146 devfn -= (0xa<<3); // to LPC
147 index2 = 8;
148 for(i=0;i<2;i++) {
149 lpc_dev = find_lpc_dev(dev, devfn - (i<<3));
150 if(!lpc_dev) continue;
151 index2 -= i;
152 devfn -= (i<<3);
153 break;
154 }
155 break;
156 case PCI_DEVICE_ID_SIS_SIS966_PCIE_D:
157 devfn -= (0xc<<3); // to LPC
158 index2 = 6;
159 break;
160 case PCI_DEVICE_ID_SIS_SIS966_PCIE_E:
161 devfn -= (0xd<<3); // to LPC
162 index2 = 5;
163 break;
164 case PCI_DEVICE_ID_SIS_SIS966_PCIE_F:
165 devfn -= (0xe<<3); // to LPC
166 index2 = 4;
167 break;
168 default:
169 index = 0;
170 }
171
172 if(!lpc_dev)
173 lpc_dev = find_lpc_dev(dev, devfn);
174
175 if ( !lpc_dev ) return;
176
177 if(index2!=0) {
178 sm_dev = dev_find_slot(dev->bus->secondary, devfn + 1);
179 if(!sm_dev) return;
180
181 if ( sm_dev ) {
182 reg_old = reg = pci_read_config32(sm_dev, 0xe4);
183
184 if (!dev->enabled) { //disable it
185 reg |= (1<<index2);
186 }
187
188 if (reg != reg_old) {
189 pci_write_config32(sm_dev, 0xe4, reg);
190 }
191 }
192
193 index2 = 0;
194 return;
195 }
196
197
198 if ( index == 0) { // for LPC
199
200 // expose ioapic base
201 byte = pci_read_config8(lpc_dev, 0x74);
202 byte |= ((1<<1)); // expose the BAR
203 pci_write_config8(dev, 0x74, byte);
204
205 // expose trap base
206 byte = pci_read_config8(lpc_dev, 0xdd);
207 byte |= ((1<<0)|(1<<3)); // expose the BAR and enable write
208 pci_write_config8(dev, 0xdd, byte);
209
210 return;
211
212 }
213
214 if( index == 16) {
215 sm_dev = dev_find_slot(dev->bus->secondary, devfn + 1);
216 if(!sm_dev) return;
217
218 final_reg = pci_read_config32(sm_dev, 0xe8);
219 final_reg &= ~((1<<16)|(1<<8)|(1<<20)|(1<<14)|(1<<22)|(1<<18)|(1<<17)|(1<<15)|(1<<11)|(1<<10)|(1<<9));
220 pci_write_config32(sm_dev, 0xe8, final_reg); //enable all at first
221#if 0
222 reg_old = reg = pci_read_config32(sm_dev, 0xe4);
223// reg |= (1<<0);
224 reg &= ~(0x3f<<4);
225 if (reg != reg_old) {
226 printk_debug("sis966.c pcie enabled\n");
227 pci_write_config32(sm_dev, 0xe4, reg);
228 }
229#endif
230 }
231
232 if (!dev->enabled) {
233 final_reg |= (1 << index);// disable it
234 //The reason for using final_reg, if diable func 1, the func 2 will be func 1 so We need disable them one time.
235 }
236
237 if(index == 9 ) { //NIC1 is the final, We need update final reg to 0xe8
238 sm_dev = dev_find_slot(dev->bus->secondary, devfn + 1);
239 if(!sm_dev) return;
240 reg_old = pci_read_config32(sm_dev, 0xe8);
241 if (final_reg != reg_old) {
242 pci_write_config32(sm_dev, 0xe8, final_reg);
243 }
244
245 }
246
247
248}
249
250struct chip_operations southbridge_sis_sis966_ops = {
251 CHIP_NAME("SiS SiS966 Southbridge")
252 .enable_dev = sis966_enable,
253};