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.
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.
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.
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
24 #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>
34 static device_t find_lpc_dev(device_t dev, unsigned devfn)
38 lpc_dev = dev_find_slot(dev->bus->secondary, devfn);
43 if ((lpc_dev->vendor != PCI_VENDOR_ID_NVIDIA) || (
44 (lpc_dev->device < PCI_DEVICE_ID_NVIDIA_MCP55_LPC) ||
45 (lpc_dev->device > PCI_DEVICE_ID_NVIDIA_MCP55_PRO)))
48 id = pci_read_config32(lpc_dev, PCI_VENDOR_ID);
49 if ((id < (PCI_VENDOR_ID_NVIDIA
50 | (PCI_DEVICE_ID_NVIDIA_MCP55_LPC << 16))) ||
51 (id > (PCI_VENDOR_ID_NVIDIA
52 | (PCI_DEVICE_ID_NVIDIA_MCP55_PRO << 16))))
61 void mcp55_enable(device_t dev)
63 device_t lpc_dev = 0, sm_dev = 0;
64 unsigned index = 0, index2 = 0;
67 unsigned deviceid, vendorid, devfn;
68 struct southbridge_nvidia_mcp55_config *conf;
69 conf = dev->chip_info;
72 if (dev->device == 0x0000) {
73 vendorid = pci_read_config32(dev, PCI_VENDOR_ID);
74 deviceid = (vendorid >> 16) & 0xffff;
75 // vendorid &= 0xffff;
77 // vendorid = dev->vendor;
78 deviceid = dev->device;
81 devfn = (dev->path.pci.devfn) & ~7;
83 case PCI_DEVICE_ID_NVIDIA_MCP55_HT:
85 case PCI_DEVICE_ID_NVIDIA_MCP55_SM2: //?
88 case PCI_DEVICE_ID_NVIDIA_MCP55_USB:
92 case PCI_DEVICE_ID_NVIDIA_MCP55_USB2:
96 case PCI_DEVICE_ID_NVIDIA_MCP55_NIC: // two
97 case PCI_DEVICE_ID_NVIDIA_MCP55_NIC_BRIDGE: // two
100 for (i = 0; i < 2; i++) {
101 lpc_dev = find_lpc_dev(dev, devfn - (i << 3));
109 case PCI_DEVICE_ID_NVIDIA_MCP55_AZA:
113 case PCI_DEVICE_ID_NVIDIA_MCP55_IDE:
117 case PCI_DEVICE_ID_NVIDIA_MCP55_SATA0: // three
118 case PCI_DEVICE_ID_NVIDIA_MCP55_SATA1: // three
121 i = (dev->path.pci.devfn) & 7;
125 case PCI_DEVICE_ID_NVIDIA_MCP55_PCI:
129 case PCI_DEVICE_ID_NVIDIA_MCP55_PCIE_A:
130 devfn -= (0x9 << 3); // to LPC
133 case PCI_DEVICE_ID_NVIDIA_MCP55_PCIE_B_C: // two
134 devfn -= (0xa << 3); // to LPC
136 for (i = 0; i < 2; i++) {
137 lpc_dev = find_lpc_dev(dev, devfn - (i << 3));
145 case PCI_DEVICE_ID_NVIDIA_MCP55_PCIE_D:
146 devfn -= (0xc << 3); // to LPC
149 case PCI_DEVICE_ID_NVIDIA_MCP55_PCIE_E:
150 devfn -= (0xd << 3); // to LPC
153 case PCI_DEVICE_ID_NVIDIA_MCP55_PCIE_F:
154 devfn -= (0xe << 3); // to LPC
162 lpc_dev = find_lpc_dev(dev, devfn);
168 sm_dev = dev_find_slot(dev->bus->secondary, devfn + 1);
172 reg_old = reg = pci_read_config32(sm_dev, 0xe4);
174 reg |= (1<<index2); /* Disable it. */
176 pci_write_config32(sm_dev, 0xe4, reg);
182 if (index == 0) { // for LPC
183 /* Expose IOAPIC base. */
184 byte = pci_read_config8(lpc_dev, 0x74);
185 byte |= (1 << 1); /* Expose the BAR. */
186 pci_write_config8(dev, 0x74, byte);
188 /* Expose trap base. */
189 byte = pci_read_config8(lpc_dev, 0xdd);
190 byte |= (1 << 0) | (1 << 3); /* Expose BAR and enable write. */
191 pci_write_config8(dev, 0xdd, byte);
197 sm_dev = dev_find_slot(dev->bus->secondary, devfn + 1);
201 final_reg = pci_read_config32(sm_dev, 0xe8);
202 final_reg &= ~((1 << 16) | (1 << 8) | (1 << 20) | (1 << 14)
203 | (1 << 22) | (1 << 18) | (1 << 17) | (1 << 15)
204 | (1 << 11) | (1 << 10) | (1 << 9));
205 pci_write_config32(sm_dev, 0xe8, final_reg); /* Enable all at first. */
208 reg_old = reg = pci_read_config32(sm_dev, 0xe4);
211 if (reg != reg_old) {
212 printk(BIOS_DEBUG, "mcp55.c pcie enabled\n");
213 pci_write_config32(sm_dev, 0xe4, reg);
219 final_reg |= (1 << index); /* Disable it. */
221 * The reason for using final_reg, if diable func 1,
222 * the func 2 will be func 1, so we need disable them one time.
226 /* NIC1 is the final, we need update final reg to 0xe8. */
228 sm_dev = dev_find_slot(dev->bus->secondary, devfn + 1);
231 reg_old = pci_read_config32(sm_dev, 0xe8);
232 if (final_reg != reg_old)
233 pci_write_config32(sm_dev, 0xe8, final_reg);
237 static void mcp55_set_subsystem(device_t dev, unsigned vendor, unsigned device)
239 pci_write_config32(dev, 0x40,
240 ((device & 0xffff) << 16) | (vendor & 0xffff));
243 struct pci_operations mcp55_pci_ops = {
244 .set_subsystem = mcp55_set_subsystem,
247 struct chip_operations southbridge_nvidia_mcp55_ops = {
248 CHIP_NAME("NVIDIA MCP55 Southbridge")
249 .enable_dev = mcp55_enable,