blob: e83c2e64787277cf6ade1626590194daa771cee8 [file] [log] [blame]
Stefan Reinauer8e073822012-04-04 00:07:22 +02001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2008-2009 coresystems GmbH
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; version 2 of
9 * the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include <console/console.h>
22#include <delay.h>
23#include <device/device.h>
24#include <device/pci.h>
25#include "pch.h"
26
27static int pch_revision_id = -1;
28
29int pch_silicon_revision(void)
30{
31 if (pch_revision_id < 0)
32 pch_revision_id = pci_read_config8(
33 dev_find_slot(0, PCI_DEVFN(0x1f, 0)),
34 PCI_REVISION_ID);
35 return pch_revision_id;
36}
37
38/* Set bit in Function Disble register to hide this device */
39static void pch_hide_devfn(unsigned devfn)
40{
41 switch (devfn) {
42 case PCI_DEVFN(22, 0): /* MEI #1 */
43 RCBA32_OR(FD2, PCH_DISABLE_MEI1);
44 break;
45 case PCI_DEVFN(22, 1): /* MEI #2 */
46 RCBA32_OR(FD2, PCH_DISABLE_MEI2);
47 break;
48 case PCI_DEVFN(22, 2): /* IDE-R */
49 RCBA32_OR(FD2, PCH_DISABLE_IDER);
50 break;
51 case PCI_DEVFN(22, 3): /* KT */
52 RCBA32_OR(FD2, PCH_DISABLE_KT);
53 break;
54 case PCI_DEVFN(25, 0): /* Gigabit Ethernet */
55 RCBA32_OR(BUC, PCH_DISABLE_GBE);
56 break;
57 case PCI_DEVFN(26, 0): /* EHCI #2 */
58 RCBA32_OR(FD, PCH_DISABLE_EHCI2);
59 break;
60 case PCI_DEVFN(27, 0): /* HD Audio Controller */
61 RCBA32_OR(FD, PCH_DISABLE_HD_AUDIO);
62 break;
63 case PCI_DEVFN(28, 0): /* PCI Express Root Port 1 */
64 case PCI_DEVFN(28, 1): /* PCI Express Root Port 2 */
65 case PCI_DEVFN(28, 2): /* PCI Express Root Port 3 */
66 case PCI_DEVFN(28, 3): /* PCI Express Root Port 4 */
67 case PCI_DEVFN(28, 4): /* PCI Express Root Port 5 */
68 case PCI_DEVFN(28, 5): /* PCI Express Root Port 6 */
69 case PCI_DEVFN(28, 6): /* PCI Express Root Port 7 */
70 case PCI_DEVFN(28, 7): /* PCI Express Root Port 8 */
71 RCBA32_OR(FD, PCH_DISABLE_PCIE(PCI_FUNC(devfn)));
72 break;
73 case PCI_DEVFN(29, 0): /* EHCI #1 */
74 RCBA32_OR(FD, PCH_DISABLE_EHCI1);
75 break;
76 case PCI_DEVFN(30, 0): /* PCI-to-PCI Bridge */
77 RCBA32_OR(FD, PCH_DISABLE_P2P);
78 break;
79 case PCI_DEVFN(31, 0): /* LPC */
80 RCBA32_OR(FD, PCH_DISABLE_LPC);
81 break;
82 case PCI_DEVFN(31, 2): /* SATA #1 */
83 RCBA32_OR(FD, PCH_DISABLE_SATA1);
84 break;
85 case PCI_DEVFN(31, 3): /* SMBUS */
86 RCBA32_OR(FD, PCH_DISABLE_SMBUS);
87 break;
88 case PCI_DEVFN(31, 5): /* SATA #22 */
89 RCBA32_OR(FD, PCH_DISABLE_SATA2);
90 break;
91 case PCI_DEVFN(31, 6): /* Thermal Subsystem */
92 RCBA32_OR(FD, PCH_DISABLE_THERMAL);
93 break;
94 }
95}
96
97#define IOBP_RETRY 1000
98static inline int iobp_poll(void)
99{
100 unsigned try = IOBP_RETRY;
101 u32 data;
102
103 while (try--) {
104 data = RCBA32(IOBPS);
105 if ((data & 1) == 0)
106 return 1;
107 udelay(10);
108 }
109
110 printk(BIOS_ERR, "IOBP timeout\n");
111 return 0;
112}
113
114void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue)
115{
116 u32 data;
117
118 /* Set the address */
119 RCBA32(IOBPIRI) = address;
120
121 /* READ OPCODE */
122 if (pch_silicon_revision() >= PCH_STEP_B0)
123 RCBA32(IOBPS) = IOBPS_RW_BX;
124 else
125 RCBA32(IOBPS) = IOBPS_READ_AX;
126 if (!iobp_poll())
127 return;
128
129 /* Read IOBP data */
130 data = RCBA32(IOBPD);
131 if (!iobp_poll())
132 return;
133
134 /* Check for successful transaction */
135 if ((RCBA32(IOBPS) & 0x6) != 0) {
136 printk(BIOS_ERR, "IOBP read 0x%08x failed\n", address);
137 return;
138 }
139
140 /* Update the data */
141 data &= andvalue;
142 data |= orvalue;
143
144 /* WRITE OPCODE */
145 if (pch_silicon_revision() >= PCH_STEP_B0)
146 RCBA32(IOBPS) = IOBPS_RW_BX;
147 else
148 RCBA32(IOBPS) = IOBPS_WRITE_AX;
149 if (!iobp_poll())
150 return;
151
152 /* Write IOBP data */
153 RCBA32(IOBPD) = data;
154 if (!iobp_poll())
155 return;
156}
157
158/* Check if any port in set X to X+3 is enabled */
159static int pch_pcie_check_set_enabled(device_t dev)
160{
161 device_t port;
162 int port_func;
163 int dev_func = PCI_FUNC(dev->path.pci.devfn);
164
165 printk(BIOS_DEBUG, "%s: check set enabled\n", dev_path(dev));
166
167 /* Go through static device tree list of devices
168 * because enumeration is still in progress */
169 for (port = all_devices; port; port = port->next) {
170 /* Only care about PCIe root ports */
171 if (PCI_SLOT(port->path.pci.devfn) !=
172 PCI_SLOT(dev->path.pci.devfn))
173 continue;
174
175 /* Check if port is in range and enabled */
176 port_func = PCI_FUNC(port->path.pci.devfn);
177 if (port_func >= dev_func &&
178 port_func < (dev_func + 4) &&
179 port->enabled)
180 return 1;
181 }
182
183 /* None of the ports in this set are enabled */
184 return 0;
185}
186
187void pch_enable(device_t dev)
188{
189 u32 reg32;
190
191 if (!dev->enabled) {
192 printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
193
194 /*
195 * PCIE Power Savings for stepping B1+:
196 *
197 * If PCIe 0-3 disabled set Function 0 0xE2[0] = 1
198 * If PCIe 4-7 disabled set Function 4 0xE2[0] = 1
199 *
200 * This check is done here instead of pcie driver
201 * because the pcie driver enable() handler is not
202 * called unless the device is enabled.
203 */
204 if (pch_silicon_revision() >= PCH_STEP_B1 &&
205 PCI_SLOT(dev->path.pci.devfn) == PCH_PCIE_DEV_SLOT &&
206 (PCI_FUNC(dev->path.pci.devfn) == 0 ||
207 PCI_FUNC(dev->path.pci.devfn) == 4)) {
208 if (!pch_pcie_check_set_enabled(dev)) {
209 u8 reg8 = pci_read_config8(dev, 0xe2);
210 reg8 |= 1;
211 pci_write_config8(dev, 0xe2, reg8);
212 }
213 }
214
215 /* Ensure memory, io, and bus master are all disabled */
216 reg32 = pci_read_config32(dev, PCI_COMMAND);
217 reg32 &= ~(PCI_COMMAND_MASTER |
218 PCI_COMMAND_MEMORY | PCI_COMMAND_IO );
219 pci_write_config32(dev, PCI_COMMAND, reg32);
220
221 /* Hide this device if possible */
222 pch_hide_devfn(dev->path.pci.devfn);
223 } else {
224 /* Enable SERR */
225 reg32 = pci_read_config32(dev, PCI_COMMAND);
226 reg32 |= PCI_COMMAND_SERR;
227 pci_write_config32(dev, PCI_COMMAND, reg32);
228 }
229}
230
231struct chip_operations southbridge_intel_bd82x6x_ops = {
232 CHIP_NAME("Intel Series 6 (" CONFIG_PCH_CHIP_NAME ") Southbridge")
233 .enable_dev = pch_enable,
234};