11dc5b2cd24120f57a4254272a034ff9a6ad08d1
[coreboot.git] / src / southbridge / nvidia / mcp55 / mcp55.c
1 /*
2  * This file is part of the coreboot 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  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
22  */
23
24 #include <console/console.h>
25
26 #include <arch/io.h>
27
28 #include <device/device.h>
29 #include <device/pci.h>
30 #include <device/pci_ids.h>
31 #include <device/pci_ops.h>
32 #include "mcp55.h"
33
34 static uint32_t final_reg;
35
36 static device_t find_lpc_dev( device_t dev,  unsigned devfn)
37 {
38
39         device_t lpc_dev;
40
41         lpc_dev = dev_find_slot(dev->bus->secondary, devfn);
42
43         if ( !lpc_dev ) return lpc_dev;
44
45         if ((lpc_dev->vendor != PCI_VENDOR_ID_NVIDIA) || (
46                 (lpc_dev->device < PCI_DEVICE_ID_NVIDIA_MCP55_LPC) ||
47                 (lpc_dev->device > PCI_DEVICE_ID_NVIDIA_MCP55_PRO)
48                 ) ) {
49                         uint32_t id;
50                         id = pci_read_config32(lpc_dev, PCI_VENDOR_ID);
51                         if ( (id < (PCI_VENDOR_ID_NVIDIA | (PCI_DEVICE_ID_NVIDIA_MCP55_LPC << 16))) ||
52                                 (id > (PCI_VENDOR_ID_NVIDIA | (PCI_DEVICE_ID_NVIDIA_MCP55_PRO << 16)))
53                                 ) {
54                                 lpc_dev = 0;
55                         }
56         }
57
58         return lpc_dev;
59 }
60
61 void mcp55_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_nvidia_mcp55_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.pci.devfn) & ~7;
88         switch(deviceid) {
89                 case PCI_DEVICE_ID_NVIDIA_MCP55_HT:
90                         return;
91
92                 case PCI_DEVICE_ID_NVIDIA_MCP55_SM2://?
93                         index = 16;
94                         break;
95                 case PCI_DEVICE_ID_NVIDIA_MCP55_USB:
96                         devfn -= (1<<3);
97                         index = 8;
98                         break;
99                 case PCI_DEVICE_ID_NVIDIA_MCP55_USB2:
100                         devfn -= (1<<3);
101                         index = 20;
102                         break;
103                 case PCI_DEVICE_ID_NVIDIA_MCP55_NIC: //two
104                 case PCI_DEVICE_ID_NVIDIA_MCP55_NIC_BRIDGE://two
105                         devfn -= (7<<3);
106                         index = 10;
107                         for(i=0;i<2;i++) {
108                                 lpc_dev = find_lpc_dev(dev, devfn - (i<<3));
109                                 if(!lpc_dev) continue;
110                                 index -= i;
111                                 devfn -= (i<<3);
112                                 break;
113                         }
114                         break;
115                 case PCI_DEVICE_ID_NVIDIA_MCP55_AZA:
116                         devfn -= (5<<3);
117                         index = 11;
118                         break;
119                 case PCI_DEVICE_ID_NVIDIA_MCP55_IDE:
120                         devfn -= (3<<3);
121                         index = 14;
122                         break;
123                 case PCI_DEVICE_ID_NVIDIA_MCP55_SATA0: //three
124                 case PCI_DEVICE_ID_NVIDIA_MCP55_SATA1: //three
125                         devfn -= (4<<3);
126                         index = 22;
127                         i = (dev->path.pci.devfn) & 7;
128                         if(i>0) {
129                                 index -= (i+3);
130                         }
131                         break;
132                 case PCI_DEVICE_ID_NVIDIA_MCP55_PCI:
133                         devfn -= (5<<3);
134                         index = 15;
135                         break;
136                 case PCI_DEVICE_ID_NVIDIA_MCP55_PCIE_A:
137                         devfn -= (0x9<<3);  // to LPC
138                         index2 = 9;
139                         break;
140                 case PCI_DEVICE_ID_NVIDIA_MCP55_PCIE_B_C: //two
141                         devfn -= (0xa<<3);  // to LPC
142                         index2 = 8;
143                         for(i=0;i<2;i++) {
144                                 lpc_dev = find_lpc_dev(dev, devfn - (i<<3));
145                                 if(!lpc_dev) continue;
146                                 index2 -= i;
147                                 devfn -= (i<<3);
148                                 break;
149                         }
150                         break;
151                 case PCI_DEVICE_ID_NVIDIA_MCP55_PCIE_D:
152                         devfn -= (0xc<<3);  // to LPC
153                         index2 = 6;
154                         break;
155                 case PCI_DEVICE_ID_NVIDIA_MCP55_PCIE_E:
156                         devfn -= (0xd<<3);  // to LPC
157                         index2 = 5;
158                         break;
159                 case PCI_DEVICE_ID_NVIDIA_MCP55_PCIE_F:
160                         devfn -= (0xe<<3);  // to LPC
161                         index2 = 4;
162                         break;
163                 default:
164                         index = 0;
165         }
166
167         if(!lpc_dev)
168                 lpc_dev = find_lpc_dev(dev, devfn);
169
170         if ( !lpc_dev ) return;
171
172         if(index2!=0) {
173                 sm_dev = dev_find_slot(dev->bus->secondary, devfn + 1);
174                 if(!sm_dev) return;
175
176                 if ( sm_dev ) {
177                         reg_old = reg =  pci_read_config32(sm_dev, 0xe4);
178
179                         if (!dev->enabled) { //disable it
180                                 reg |= (1<<index2);
181                         }
182
183                         if (reg != reg_old) {
184                                 pci_write_config32(sm_dev, 0xe4, reg);
185                         }
186                 }
187
188                 index2 = 0;
189                 return;
190         }
191
192
193         if ( index == 0) {  // for LPC
194
195                 // expose ioapic base
196                 byte = pci_read_config8(lpc_dev, 0x74);
197                 byte |= ((1<<1)); // expose the BAR
198                 pci_write_config8(dev, 0x74, byte);
199
200                 // expose trap base
201                 byte = pci_read_config8(lpc_dev, 0xdd);
202                 byte |= ((1<<0)|(1<<3)); // expose the BAR and enable write
203                 pci_write_config8(dev, 0xdd, byte);
204
205                 return;
206
207         }
208
209         if( index == 16) {
210                 sm_dev = dev_find_slot(dev->bus->secondary, devfn + 1);
211                 if(!sm_dev) return;
212
213                 final_reg = pci_read_config32(sm_dev, 0xe8);
214                 final_reg &= ~((1<<16)|(1<<8)|(1<<20)|(1<<14)|(1<<22)|(1<<18)|(1<<17)|(1<<15)|(1<<11)|(1<<10)|(1<<9));
215                 pci_write_config32(sm_dev, 0xe8, final_reg); //enable all at first
216 #if 0
217                 reg_old = reg = pci_read_config32(sm_dev, 0xe4);
218 //              reg |= (1<<0);
219                 reg &= ~(0x3f<<4);
220                 if (reg != reg_old) {
221                         printk(BIOS_DEBUG, "mcp55.c pcie enabled\n");
222                         pci_write_config32(sm_dev, 0xe4, reg);
223                 }
224 #endif
225         }
226
227         if (!dev->enabled) {
228                 final_reg |= (1 << index);// disable it
229                 //The reason for using final_reg, if diable func 1, the func 2 will be func 1 so We need disable them one time.
230         }
231
232         if(index == 9 ) { //NIC1 is the final, We need update final reg to 0xe8
233                 sm_dev = dev_find_slot(dev->bus->secondary, devfn + 1);
234                 if(!sm_dev) return;
235                 reg_old = pci_read_config32(sm_dev, 0xe8);
236                 if (final_reg != reg_old) {
237                         pci_write_config32(sm_dev, 0xe8, final_reg);
238                 }
239
240         }
241
242
243 }
244
245 static void mcp55_set_subsystem(device_t dev, unsigned vendor, unsigned device)
246 {
247         pci_write_config32(dev, 0x40,
248                            ((device & 0xffff) << 16) | (vendor & 0xffff));
249 }
250
251 struct pci_operations mcp55_pci_ops = {
252         .set_subsystem = mcp55_set_subsystem,
253 }; 
254
255 struct chip_operations southbridge_nvidia_mcp55_ops = {
256         CHIP_NAME("NVIDIA MCP55 Southbridge")
257         .enable_dev     = mcp55_enable,
258 };