blob: c2765e91ebb7aa2da3f07adaa783eaa90d4519f6 [file] [log] [blame]
Aaron Durbin76c37002012-10-30 09:03:43 -05001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2008-2009 coresystems GmbH
5 * Copyright (C) 2012 The Chromium OS Authors. All rights reserved.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; version 2 of
10 * the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include <console/console.h>
23#include <delay.h>
24#include <device/device.h>
25#include <device/pci.h>
26#include "pch.h"
27
28static int pch_revision_id = -1;
29static int pch_type = -1;
30
31int pch_silicon_revision(void)
32{
33 if (pch_revision_id < 0)
34 pch_revision_id = pci_read_config8(
35 dev_find_slot(0, PCI_DEVFN(0x1f, 0)),
36 PCI_REVISION_ID);
37 return pch_revision_id;
38}
39
40int pch_silicon_type(void)
41{
42 if (pch_type < 0)
43 pch_type = pci_read_config8(
44 dev_find_slot(0, PCI_DEVFN(0x1f, 0)),
45 PCI_DEVICE_ID + 1);
46 return pch_type;
47}
48
49int pch_silicon_supported(int type, int rev)
50{
51 return 1;
52}
53
54/* Set bit in Function Disble register to hide this device */
55static void pch_hide_devfn(unsigned devfn)
56{
57 switch (devfn) {
58 case PCI_DEVFN(22, 0): /* MEI #1 */
59 RCBA32_OR(FD2, PCH_DISABLE_MEI1);
60 break;
61 case PCI_DEVFN(22, 1): /* MEI #2 */
62 RCBA32_OR(FD2, PCH_DISABLE_MEI2);
63 break;
64 case PCI_DEVFN(22, 2): /* IDE-R */
65 RCBA32_OR(FD2, PCH_DISABLE_IDER);
66 break;
67 case PCI_DEVFN(22, 3): /* KT */
68 RCBA32_OR(FD2, PCH_DISABLE_KT);
69 break;
70 case PCI_DEVFN(25, 0): /* Gigabit Ethernet */
71 RCBA32_OR(BUC, PCH_DISABLE_GBE);
72 break;
73 case PCI_DEVFN(26, 0): /* EHCI #2 */
74 RCBA32_OR(FD, PCH_DISABLE_EHCI2);
75 break;
76 case PCI_DEVFN(27, 0): /* HD Audio Controller */
77 RCBA32_OR(FD, PCH_DISABLE_HD_AUDIO);
78 break;
79 case PCI_DEVFN(28, 0): /* PCI Express Root Port 1 */
80 case PCI_DEVFN(28, 1): /* PCI Express Root Port 2 */
81 case PCI_DEVFN(28, 2): /* PCI Express Root Port 3 */
82 case PCI_DEVFN(28, 3): /* PCI Express Root Port 4 */
83 case PCI_DEVFN(28, 4): /* PCI Express Root Port 5 */
84 case PCI_DEVFN(28, 5): /* PCI Express Root Port 6 */
85 case PCI_DEVFN(28, 6): /* PCI Express Root Port 7 */
86 case PCI_DEVFN(28, 7): /* PCI Express Root Port 8 */
87 RCBA32_OR(FD, PCH_DISABLE_PCIE(PCI_FUNC(devfn)));
88 break;
89 case PCI_DEVFN(29, 0): /* EHCI #1 */
90 RCBA32_OR(FD, PCH_DISABLE_EHCI1);
91 break;
92 case PCI_DEVFN(30, 0): /* PCI-to-PCI Bridge */
93 RCBA32_OR(FD, PCH_DISABLE_P2P);
94 break;
95 case PCI_DEVFN(31, 0): /* LPC */
96 RCBA32_OR(FD, PCH_DISABLE_LPC);
97 break;
98 case PCI_DEVFN(31, 2): /* SATA #1 */
99 RCBA32_OR(FD, PCH_DISABLE_SATA1);
100 break;
101 case PCI_DEVFN(31, 3): /* SMBUS */
102 RCBA32_OR(FD, PCH_DISABLE_SMBUS);
103 break;
104 case PCI_DEVFN(31, 5): /* SATA #22 */
105 RCBA32_OR(FD, PCH_DISABLE_SATA2);
106 break;
107 case PCI_DEVFN(31, 6): /* Thermal Subsystem */
108 RCBA32_OR(FD, PCH_DISABLE_THERMAL);
109 break;
110 }
111}
112
113#define IOBP_RETRY 1000
114static inline int iobp_poll(void)
115{
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800116 unsigned try;
Aaron Durbin76c37002012-10-30 09:03:43 -0500117
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800118 for (try = IOBP_RETRY; try > 0; try--) {
119 u16 status = RCBA16(IOBPS);
120 if ((status & IOBPS_READY) == 0)
Aaron Durbin76c37002012-10-30 09:03:43 -0500121 return 1;
122 udelay(10);
123 }
124
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800125 printk(BIOS_ERR, "IOBP: timeout waiting for transaction to complete\n");
Aaron Durbin76c37002012-10-30 09:03:43 -0500126 return 0;
127}
128
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800129static u32 pch_iobp_read(u32 address)
Aaron Durbin76c37002012-10-30 09:03:43 -0500130{
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800131 u16 status;
132
133 if (!iobp_poll())
134 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500135
136 /* Set the address */
137 RCBA32(IOBPIRI) = address;
138
139 /* READ OPCODE */
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800140 status = RCBA16(IOBPS);
141 status &= ~IOBPS_MASK;
142 status |= IOBPS_READ;
143 RCBA16(IOBPS) = status;
Aaron Durbin76c37002012-10-30 09:03:43 -0500144
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800145 /* Undocumented magic */
146 RCBA16(IOBPU) = IOBPU_MAGIC;
147
148 /* Set ready bit */
149 status = RCBA16(IOBPS);
150 status |= IOBPS_READY;
151 RCBA16(IOBPS) = status;
152
Aaron Durbin76c37002012-10-30 09:03:43 -0500153 if (!iobp_poll())
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800154 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500155
156 /* Check for successful transaction */
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800157 status = RCBA16(IOBPS);
158 if (status & IOBPS_TX_MASK) {
159 printk(BIOS_ERR, "IOBP: read 0x%08x failed\n", address);
160 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500161 }
162
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800163 /* Read IOBP data */
164 return RCBA32(IOBPD);
165}
166
167void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue)
168{
169 u16 status;
170 u32 data = pch_iobp_read(address);
171
172 /* WRITE OPCODE */
173 status = RCBA16(IOBPS);
174 status &= ~IOBPS_MASK;
175 status |= IOBPS_WRITE;
176 RCBA16(IOBPS) = status;
177
Aaron Durbin76c37002012-10-30 09:03:43 -0500178 /* Update the data */
179 data &= andvalue;
180 data |= orvalue;
Aaron Durbin76c37002012-10-30 09:03:43 -0500181 RCBA32(IOBPD) = data;
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800182
183 /* Undocumented magic */
184 RCBA16(IOBPU) = IOBPU_MAGIC;
185
186 /* Set ready bit */
187 status = RCBA16(IOBPS);
188 status |= IOBPS_READY;
189 RCBA16(IOBPS) = status;
190
Aaron Durbin76c37002012-10-30 09:03:43 -0500191 if (!iobp_poll())
192 return;
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800193
194 /* Check for successful transaction */
195 status = RCBA16(IOBPS);
196 if (status & IOBPS_TX_MASK) {
197 printk(BIOS_ERR, "IOBP: write 0x%08x failed\n", address);
198 return;
199 }
200
201 printk(BIOS_INFO, "IOBP: set 0x%08x to 0x%08x\n", address, data);
Aaron Durbin76c37002012-10-30 09:03:43 -0500202}
203
204/* Check if any port in set X to X+3 is enabled */
205static int pch_pcie_check_set_enabled(device_t dev)
206{
207 device_t port;
208 int port_func;
209 int dev_func = PCI_FUNC(dev->path.pci.devfn);
210
211 printk(BIOS_DEBUG, "%s: check set enabled\n", dev_path(dev));
212
213 /* Go through static device tree list of devices
214 * because enumeration is still in progress */
215 for (port = all_devices; port; port = port->next) {
216 /* Only care about PCIe root ports */
217 if (PCI_SLOT(port->path.pci.devfn) !=
218 PCI_SLOT(dev->path.pci.devfn))
219 continue;
220
221 /* Check if port is in range and enabled */
222 port_func = PCI_FUNC(port->path.pci.devfn);
223 if (port_func >= dev_func &&
224 port_func < (dev_func + 4) &&
225 port->enabled)
226 return 1;
227 }
228
229 /* None of the ports in this set are enabled */
230 return 0;
231}
232
233/* RPFN is a write-once register so keep a copy until it is written */
234static u32 new_rpfn;
235
236/* Swap function numbers assigned to two PCIe Root Ports */
237static void pch_pcie_function_swap(u8 old_fn, u8 new_fn)
238{
239 u32 old_rpfn = new_rpfn;
240
241 printk(BIOS_DEBUG, "PCH: Remap PCIe function %d to %d\n",
242 old_fn, new_fn);
243
244 new_rpfn &= ~(RPFN_FNMASK(old_fn) | RPFN_FNMASK(new_fn));
245
246 /* Old function set to new function and disabled */
247 new_rpfn |= RPFN_FNSET(old_fn, RPFN_FNGET(old_rpfn, new_fn));
248 new_rpfn |= RPFN_FNSET(new_fn, RPFN_FNGET(old_rpfn, old_fn));
249}
250
251/* Update devicetree with new Root Port function number assignment */
252static void pch_pcie_devicetree_update(void)
253{
254 device_t dev;
255
256 /* Update the function numbers in the static devicetree */
257 for (dev = all_devices; dev; dev = dev->next) {
258 u8 new_devfn;
259
260 /* Only care about PCH PCIe root ports */
261 if (PCI_SLOT(dev->path.pci.devfn) !=
262 PCH_PCIE_DEV_SLOT)
263 continue;
264
265 /* Determine the new devfn for this port */
266 new_devfn = PCI_DEVFN(PCH_PCIE_DEV_SLOT,
267 RPFN_FNGET(new_rpfn,
268 PCI_FUNC(dev->path.pci.devfn)));
269
270 if (dev->path.pci.devfn != new_devfn) {
271 printk(BIOS_DEBUG,
272 "PCH: PCIe map %02x.%1x -> %02x.%1x\n",
273 PCI_SLOT(dev->path.pci.devfn),
274 PCI_FUNC(dev->path.pci.devfn),
275 PCI_SLOT(new_devfn), PCI_FUNC(new_devfn));
276
277 dev->path.pci.devfn = new_devfn;
278 }
279 }
280}
281
282/* Special handling for PCIe Root Port devices */
283static void pch_pcie_enable(device_t dev)
284{
285 struct southbridge_intel_lynxpoint_config *config = dev->chip_info;
286 u32 reg32;
287
288 /*
289 * Save a copy of the Root Port Function Number map when
290 * starting to walk the list of PCIe Root Ports so it can
291 * be updated locally and written out when the last port
292 * has been processed.
293 */
294 if (PCI_FUNC(dev->path.pci.devfn) == 0) {
295 new_rpfn = RCBA32(RPFN);
296
297 /*
298 * Enable Root Port coalescing if the first port is disabled
299 * or the other devices will not be enumerated by the OS.
300 */
301 if (!dev->enabled)
302 config->pcie_port_coalesce = 1;
303
304 if (config->pcie_port_coalesce)
305 printk(BIOS_INFO,
306 "PCH: PCIe Root Port coalescing is enabled\n");
307 }
308
309 if (!dev->enabled) {
310 printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
311
312 /*
313 * PCIE Power Savings for PantherPoint and CougarPoint/B1+
314 *
315 * If PCIe 0-3 disabled set Function 0 0xE2[0] = 1
316 * If PCIe 4-7 disabled set Function 4 0xE2[0] = 1
317 *
318 * This check is done here instead of pcie driver
319 * because the pcie driver enable() handler is not
320 * called unless the device is enabled.
321 */
322 if ((PCI_FUNC(dev->path.pci.devfn) == 0 ||
323 PCI_FUNC(dev->path.pci.devfn) == 4)) {
324 /* Handle workaround for PPT and CPT/B1+ */
325 if (!pch_pcie_check_set_enabled(dev)) {
326 u8 reg8 = pci_read_config8(dev, 0xe2);
327 reg8 |= 1;
328 pci_write_config8(dev, 0xe2, reg8);
329 }
330
331 /*
332 * Enable Clock Gating for shared PCIe resources
333 * before disabling this particular port.
334 */
335 pci_write_config8(dev, 0xe1, 0x3c);
336 }
337
338 /* Ensure memory, io, and bus master are all disabled */
339 reg32 = pci_read_config32(dev, PCI_COMMAND);
340 reg32 &= ~(PCI_COMMAND_MASTER |
341 PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
342 pci_write_config32(dev, PCI_COMMAND, reg32);
343
344 /* Do not claim downstream transactions for PCIe ports */
345 new_rpfn |= RPFN_HIDE(PCI_FUNC(dev->path.pci.devfn));
346
347 /* Hide this device if possible */
348 pch_hide_devfn(dev->path.pci.devfn);
349 } else {
350 int fn;
351
352 /*
353 * Check if there is a lower disabled port to swap with this
354 * port in order to maintain linear order starting at zero.
355 */
356 if (config->pcie_port_coalesce) {
357 for (fn=0; fn < PCI_FUNC(dev->path.pci.devfn); fn++) {
358 if (!(new_rpfn & RPFN_HIDE(fn)))
359 continue;
360
361 /* Swap places with this function */
362 pch_pcie_function_swap(
363 PCI_FUNC(dev->path.pci.devfn), fn);
364 break;
365 }
366 }
367
368 /* Enable SERR */
369 reg32 = pci_read_config32(dev, PCI_COMMAND);
370 reg32 |= PCI_COMMAND_SERR;
371 pci_write_config32(dev, PCI_COMMAND, reg32);
372 }
373
374 /*
375 * When processing the last PCIe root port we can now
376 * update the Root Port Function Number and Hide register.
377 */
378 if (PCI_FUNC(dev->path.pci.devfn) == 7) {
379 printk(BIOS_SPEW, "PCH: RPFN 0x%08x -> 0x%08x\n",
380 RCBA32(RPFN), new_rpfn);
381 RCBA32(RPFN) = new_rpfn;
382
383 /* Update static devictree with new function numbers */
384 if (config->pcie_port_coalesce)
385 pch_pcie_devicetree_update();
386 }
387}
388
389void pch_enable(device_t dev)
390{
391 u32 reg32;
392
393 /* PCH PCIe Root Ports get special handling */
394 if (PCI_SLOT(dev->path.pci.devfn) == PCH_PCIE_DEV_SLOT)
395 return pch_pcie_enable(dev);
396
397 if (!dev->enabled) {
398 printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
399
400 /* Ensure memory, io, and bus master are all disabled */
401 reg32 = pci_read_config32(dev, PCI_COMMAND);
402 reg32 &= ~(PCI_COMMAND_MASTER |
403 PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
404 pci_write_config32(dev, PCI_COMMAND, reg32);
405
406 /* Hide this device if possible */
407 pch_hide_devfn(dev->path.pci.devfn);
408 } else {
409 /* Enable SERR */
410 reg32 = pci_read_config32(dev, PCI_COMMAND);
411 reg32 |= PCI_COMMAND_SERR;
412 pci_write_config32(dev, PCI_COMMAND, reg32);
413 }
414}
415
416struct chip_operations southbridge_intel_lynxpoint_ops = {
417 CHIP_NAME("Intel Series 8 (Lynx Point) Southbridge")
418 .enable_dev = pch_enable,
419};