blob: 3d7b0f7284627bbd16de70f23a9b1295ba832610 [file] [log] [blame]
Morgan Tsai1602dd52007-10-29 21:00:14 +00001/*
Stefan Reinauer7e61e452008-01-18 10:35:56 +00002 * This file is part of the coreboot project.
Morgan Tsai1602dd52007-10-29 21:00:14 +00003 *
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
Stefan Reinauer2b34db82009-02-28 20:10:20 +000086 devfn = (dev->path.pci.devfn) & ~7;
Morgan Tsai1602dd52007-10-29 21:00:14 +000087 switch(deviceid) {
Morgan Tsai1602dd52007-10-29 21:00:14 +000088 case PCI_DEVICE_ID_SIS_SIS966_USB:
89 devfn -= (1<<3);
90 index = 8;
91 break;
Morgan Tsai218c2652007-11-02 16:09:58 +000092 case PCI_DEVICE_ID_SIS_SIS966_USB2:
Morgan Tsai1602dd52007-10-29 21:00:14 +000093 devfn -= (1<<3);
94 index = 20;
95 break;
Morgan Tsai31e805d2007-11-14 01:34:02 +000096 case PCI_DEVICE_ID_SIS_SIS966_NIC:
Morgan Tsai1602dd52007-10-29 21:00:14 +000097 devfn -= (7<<3);
98 index = 10;
99 for(i=0;i<2;i++) {
100 lpc_dev = find_lpc_dev(dev, devfn - (i<<3));
101 if(!lpc_dev) continue;
102 index -= i;
103 devfn -= (i<<3);
104 break;
105 }
106 break;
Morgan Tsai31e805d2007-11-14 01:34:02 +0000107 case PCI_DEVICE_ID_SIS_SIS966_HD_AUDIO:
Morgan Tsai1602dd52007-10-29 21:00:14 +0000108 devfn -= (5<<3);
109 index = 11;
110 break;
111 case PCI_DEVICE_ID_SIS_SIS966_IDE:
112 devfn -= (3<<3);
113 index = 14;
114 break;
Morgan Tsai31e805d2007-11-14 01:34:02 +0000115 case PCI_DEVICE_ID_SIS_SIS966_SATA:
Morgan Tsai1602dd52007-10-29 21:00:14 +0000116 devfn -= (4<<3);
117 index = 22;
Stefan Reinauer2b34db82009-02-28 20:10:20 +0000118 i = (dev->path.pci.devfn) & 7;
Morgan Tsai1602dd52007-10-29 21:00:14 +0000119 if(i>0) {
120 index -= (i+3);
121 }
122 break;
Morgan Tsai31e805d2007-11-14 01:34:02 +0000123 case PCI_DEVICE_ID_SIS_SIS966_PCIE:
124 devfn -= (0x9<<3); // to LPC
125 index2 = 9;
Morgan Tsai1602dd52007-10-29 21:00:14 +0000126 break;
127 default:
128 index = 0;
129 }
130
131 if(!lpc_dev)
132 lpc_dev = find_lpc_dev(dev, devfn);
133
134 if ( !lpc_dev ) return;
135
136 if(index2!=0) {
137 sm_dev = dev_find_slot(dev->bus->secondary, devfn + 1);
138 if(!sm_dev) return;
139
140 if ( sm_dev ) {
141 reg_old = reg = pci_read_config32(sm_dev, 0xe4);
142
143 if (!dev->enabled) { //disable it
144 reg |= (1<<index2);
145 }
146
147 if (reg != reg_old) {
148 pci_write_config32(sm_dev, 0xe4, reg);
149 }
150 }
151
152 index2 = 0;
153 return;
154 }
155
156
157 if ( index == 0) { // for LPC
158
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);
163
164 // expose trap base
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);
Morgan Tsai1602dd52007-10-29 21:00:14 +0000168 return;
169
170 }
171
172 if( index == 16) {
173 sm_dev = dev_find_slot(dev->bus->secondary, devfn + 1);
174 if(!sm_dev) return;
175
176 final_reg = pci_read_config32(sm_dev, 0xe8);
Morgan Tsai218c2652007-11-02 16:09:58 +0000177 final_reg &= ~0x0057cf00;
Morgan Tsai1602dd52007-10-29 21:00:14 +0000178 pci_write_config32(sm_dev, 0xe8, final_reg); //enable all at first
Morgan Tsai1602dd52007-10-29 21:00:14 +0000179 }
180
181 if (!dev->enabled) {
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.
184 }
185
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);
188 if(!sm_dev) return;
189 reg_old = pci_read_config32(sm_dev, 0xe8);
190 if (final_reg != reg_old) {
191 pci_write_config32(sm_dev, 0xe8, final_reg);
192 }
193
194 }
Morgan Tsai1602dd52007-10-29 21:00:14 +0000195}
196
197struct chip_operations southbridge_sis_sis966_ops = {
198 CHIP_NAME("SiS SiS966 Southbridge")
199 .enable_dev = sis966_enable,
200};