blob: 6f03716283153734f06f350adb2233c1ad2bd0a7 [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
Duncan Laurie5cc51c02013-03-07 14:06:43 -08005 * Copyright 2013 Google Inc.
Aaron Durbin76c37002012-10-30 09:03:43 -05006 *
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>
Duncan Laurie5cc51c02013-03-07 14:06:43 -080024#ifdef __SMM__
25#include <arch/io.h>
26#include <arch/romcc_io.h>
27#include <device/pci_def.h>
28#else /* !__SMM__ */
Aaron Durbin76c37002012-10-30 09:03:43 -050029#include <device/device.h>
30#include <device/pci.h>
Duncan Laurie5cc51c02013-03-07 14:06:43 -080031#endif
Aaron Durbin76c37002012-10-30 09:03:43 -050032#include "pch.h"
33
Duncan Laurie5cc51c02013-03-07 14:06:43 -080034static device_t pch_get_lpc_device(void)
35{
36#ifdef __SMM__
37 return PCI_DEV(0, 0x1f, 0);
38#else
39 return dev_find_slot(0, PCI_DEVFN(0x1f, 0));
40#endif
41}
Aaron Durbin76c37002012-10-30 09:03:43 -050042
43int pch_silicon_revision(void)
44{
Duncan Laurie5cc51c02013-03-07 14:06:43 -080045 static int pch_revision_id = -1;
46
Aaron Durbin76c37002012-10-30 09:03:43 -050047 if (pch_revision_id < 0)
Duncan Laurie5cc51c02013-03-07 14:06:43 -080048 pch_revision_id = pci_read_config8(pch_get_lpc_device(),
49 PCI_REVISION_ID);
Aaron Durbin76c37002012-10-30 09:03:43 -050050 return pch_revision_id;
51}
52
53int pch_silicon_type(void)
54{
Duncan Laurie5cc51c02013-03-07 14:06:43 -080055 static int pch_type = -1;
56
Aaron Durbin76c37002012-10-30 09:03:43 -050057 if (pch_type < 0)
Duncan Laurie5cc51c02013-03-07 14:06:43 -080058 pch_type = pci_read_config8(pch_get_lpc_device(),
59 PCI_DEVICE_ID + 1);
Aaron Durbin76c37002012-10-30 09:03:43 -050060 return pch_type;
61}
62
Duncan Laurie5cc51c02013-03-07 14:06:43 -080063int pch_is_lp(void)
Aaron Durbin76c37002012-10-30 09:03:43 -050064{
Duncan Laurie5cc51c02013-03-07 14:06:43 -080065 return pch_silicon_type() == PCH_TYPE_LPT_LP;
Aaron Durbin76c37002012-10-30 09:03:43 -050066}
67
Duncan Laurie5cc51c02013-03-07 14:06:43 -080068#ifndef __SMM__
69
Aaron Durbin76c37002012-10-30 09:03:43 -050070/* Set bit in Function Disble register to hide this device */
71static void pch_hide_devfn(unsigned devfn)
72{
73 switch (devfn) {
Duncan Laurie26e7dd72012-12-19 09:12:31 -080074 case PCI_DEVFN(19, 0): /* Audio DSP */
75 RCBA32_OR(FD, PCH_DISABLE_ADSPD);
76 break;
77 case PCI_DEVFN(20, 0): /* XHCI */
78 RCBA32_OR(FD, PCH_DISABLE_XHCI);
79 break;
Duncan Laurie71346c02013-01-10 13:20:40 -080080 case PCI_DEVFN(21, 0): /* DMA */
81 pch_iobp_update(SIO_IOBP_FUNCDIS0, ~0UL, SIO_IOBP_FUNCDIS_DIS);
82 break;
83 case PCI_DEVFN(21, 1): /* I2C0 */
84 pch_iobp_update(SIO_IOBP_FUNCDIS1, ~0UL, SIO_IOBP_FUNCDIS_DIS);
85 break;
86 case PCI_DEVFN(21, 2): /* I2C1 */
87 pch_iobp_update(SIO_IOBP_FUNCDIS2, ~0UL, SIO_IOBP_FUNCDIS_DIS);
88 break;
89 case PCI_DEVFN(21, 3): /* SPI0 */
90 pch_iobp_update(SIO_IOBP_FUNCDIS3, ~0UL, SIO_IOBP_FUNCDIS_DIS);
91 break;
92 case PCI_DEVFN(21, 4): /* SPI1 */
93 pch_iobp_update(SIO_IOBP_FUNCDIS4, ~0UL, SIO_IOBP_FUNCDIS_DIS);
94 break;
95 case PCI_DEVFN(21, 5): /* UART0 */
96 pch_iobp_update(SIO_IOBP_FUNCDIS5, ~0UL, SIO_IOBP_FUNCDIS_DIS);
97 break;
98 case PCI_DEVFN(21, 6): /* UART1 */
99 pch_iobp_update(SIO_IOBP_FUNCDIS6, ~0UL, SIO_IOBP_FUNCDIS_DIS);
100 break;
Aaron Durbin76c37002012-10-30 09:03:43 -0500101 case PCI_DEVFN(22, 0): /* MEI #1 */
102 RCBA32_OR(FD2, PCH_DISABLE_MEI1);
103 break;
104 case PCI_DEVFN(22, 1): /* MEI #2 */
105 RCBA32_OR(FD2, PCH_DISABLE_MEI2);
106 break;
107 case PCI_DEVFN(22, 2): /* IDE-R */
108 RCBA32_OR(FD2, PCH_DISABLE_IDER);
109 break;
110 case PCI_DEVFN(22, 3): /* KT */
111 RCBA32_OR(FD2, PCH_DISABLE_KT);
112 break;
Duncan Laurie71346c02013-01-10 13:20:40 -0800113 case PCI_DEVFN(23, 0): /* SDIO */
114 pch_iobp_update(SIO_IOBP_FUNCDIS7, ~0UL, SIO_IOBP_FUNCDIS_DIS);
115 break;
Aaron Durbin76c37002012-10-30 09:03:43 -0500116 case PCI_DEVFN(25, 0): /* Gigabit Ethernet */
117 RCBA32_OR(BUC, PCH_DISABLE_GBE);
118 break;
119 case PCI_DEVFN(26, 0): /* EHCI #2 */
120 RCBA32_OR(FD, PCH_DISABLE_EHCI2);
121 break;
122 case PCI_DEVFN(27, 0): /* HD Audio Controller */
123 RCBA32_OR(FD, PCH_DISABLE_HD_AUDIO);
124 break;
125 case PCI_DEVFN(28, 0): /* PCI Express Root Port 1 */
126 case PCI_DEVFN(28, 1): /* PCI Express Root Port 2 */
127 case PCI_DEVFN(28, 2): /* PCI Express Root Port 3 */
128 case PCI_DEVFN(28, 3): /* PCI Express Root Port 4 */
129 case PCI_DEVFN(28, 4): /* PCI Express Root Port 5 */
130 case PCI_DEVFN(28, 5): /* PCI Express Root Port 6 */
131 case PCI_DEVFN(28, 6): /* PCI Express Root Port 7 */
132 case PCI_DEVFN(28, 7): /* PCI Express Root Port 8 */
133 RCBA32_OR(FD, PCH_DISABLE_PCIE(PCI_FUNC(devfn)));
134 break;
135 case PCI_DEVFN(29, 0): /* EHCI #1 */
136 RCBA32_OR(FD, PCH_DISABLE_EHCI1);
137 break;
Aaron Durbin76c37002012-10-30 09:03:43 -0500138 case PCI_DEVFN(31, 0): /* LPC */
139 RCBA32_OR(FD, PCH_DISABLE_LPC);
140 break;
141 case PCI_DEVFN(31, 2): /* SATA #1 */
142 RCBA32_OR(FD, PCH_DISABLE_SATA1);
143 break;
144 case PCI_DEVFN(31, 3): /* SMBUS */
145 RCBA32_OR(FD, PCH_DISABLE_SMBUS);
146 break;
Duncan Laurie26e7dd72012-12-19 09:12:31 -0800147 case PCI_DEVFN(31, 5): /* SATA #2 */
Aaron Durbin76c37002012-10-30 09:03:43 -0500148 RCBA32_OR(FD, PCH_DISABLE_SATA2);
149 break;
150 case PCI_DEVFN(31, 6): /* Thermal Subsystem */
151 RCBA32_OR(FD, PCH_DISABLE_THERMAL);
152 break;
153 }
154}
155
156#define IOBP_RETRY 1000
157static inline int iobp_poll(void)
158{
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800159 unsigned try;
Aaron Durbin76c37002012-10-30 09:03:43 -0500160
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800161 for (try = IOBP_RETRY; try > 0; try--) {
162 u16 status = RCBA16(IOBPS);
163 if ((status & IOBPS_READY) == 0)
Aaron Durbin76c37002012-10-30 09:03:43 -0500164 return 1;
165 udelay(10);
166 }
167
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800168 printk(BIOS_ERR, "IOBP: timeout waiting for transaction to complete\n");
Aaron Durbin76c37002012-10-30 09:03:43 -0500169 return 0;
170}
171
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800172static u32 pch_iobp_read(u32 address)
Aaron Durbin76c37002012-10-30 09:03:43 -0500173{
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800174 u16 status;
175
176 if (!iobp_poll())
177 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500178
179 /* Set the address */
180 RCBA32(IOBPIRI) = address;
181
182 /* READ OPCODE */
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800183 status = RCBA16(IOBPS);
184 status &= ~IOBPS_MASK;
185 status |= IOBPS_READ;
186 RCBA16(IOBPS) = status;
Aaron Durbin76c37002012-10-30 09:03:43 -0500187
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800188 /* Undocumented magic */
189 RCBA16(IOBPU) = IOBPU_MAGIC;
190
191 /* Set ready bit */
192 status = RCBA16(IOBPS);
193 status |= IOBPS_READY;
194 RCBA16(IOBPS) = status;
195
Aaron Durbin76c37002012-10-30 09:03:43 -0500196 if (!iobp_poll())
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800197 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500198
199 /* Check for successful transaction */
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800200 status = RCBA16(IOBPS);
201 if (status & IOBPS_TX_MASK) {
202 printk(BIOS_ERR, "IOBP: read 0x%08x failed\n", address);
203 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500204 }
205
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800206 /* Read IOBP data */
207 return RCBA32(IOBPD);
208}
209
210void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue)
211{
212 u16 status;
213 u32 data = pch_iobp_read(address);
214
215 /* WRITE OPCODE */
216 status = RCBA16(IOBPS);
217 status &= ~IOBPS_MASK;
218 status |= IOBPS_WRITE;
219 RCBA16(IOBPS) = status;
220
Aaron Durbin76c37002012-10-30 09:03:43 -0500221 /* Update the data */
222 data &= andvalue;
223 data |= orvalue;
Aaron Durbin76c37002012-10-30 09:03:43 -0500224 RCBA32(IOBPD) = data;
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800225
226 /* Undocumented magic */
227 RCBA16(IOBPU) = IOBPU_MAGIC;
228
229 /* Set ready bit */
230 status = RCBA16(IOBPS);
231 status |= IOBPS_READY;
232 RCBA16(IOBPS) = status;
233
Aaron Durbin76c37002012-10-30 09:03:43 -0500234 if (!iobp_poll())
235 return;
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800236
237 /* Check for successful transaction */
238 status = RCBA16(IOBPS);
239 if (status & IOBPS_TX_MASK) {
240 printk(BIOS_ERR, "IOBP: write 0x%08x failed\n", address);
241 return;
242 }
243
244 printk(BIOS_INFO, "IOBP: set 0x%08x to 0x%08x\n", address, data);
Aaron Durbin76c37002012-10-30 09:03:43 -0500245}
246
247/* Check if any port in set X to X+3 is enabled */
248static int pch_pcie_check_set_enabled(device_t dev)
249{
250 device_t port;
251 int port_func;
252 int dev_func = PCI_FUNC(dev->path.pci.devfn);
253
254 printk(BIOS_DEBUG, "%s: check set enabled\n", dev_path(dev));
255
256 /* Go through static device tree list of devices
257 * because enumeration is still in progress */
258 for (port = all_devices; port; port = port->next) {
259 /* Only care about PCIe root ports */
260 if (PCI_SLOT(port->path.pci.devfn) !=
261 PCI_SLOT(dev->path.pci.devfn))
262 continue;
263
264 /* Check if port is in range and enabled */
265 port_func = PCI_FUNC(port->path.pci.devfn);
266 if (port_func >= dev_func &&
267 port_func < (dev_func + 4) &&
268 port->enabled)
269 return 1;
270 }
271
272 /* None of the ports in this set are enabled */
273 return 0;
274}
275
276/* RPFN is a write-once register so keep a copy until it is written */
277static u32 new_rpfn;
278
279/* Swap function numbers assigned to two PCIe Root Ports */
280static void pch_pcie_function_swap(u8 old_fn, u8 new_fn)
281{
282 u32 old_rpfn = new_rpfn;
283
284 printk(BIOS_DEBUG, "PCH: Remap PCIe function %d to %d\n",
285 old_fn, new_fn);
286
287 new_rpfn &= ~(RPFN_FNMASK(old_fn) | RPFN_FNMASK(new_fn));
288
289 /* Old function set to new function and disabled */
290 new_rpfn |= RPFN_FNSET(old_fn, RPFN_FNGET(old_rpfn, new_fn));
291 new_rpfn |= RPFN_FNSET(new_fn, RPFN_FNGET(old_rpfn, old_fn));
292}
293
294/* Update devicetree with new Root Port function number assignment */
295static void pch_pcie_devicetree_update(void)
296{
297 device_t dev;
298
299 /* Update the function numbers in the static devicetree */
300 for (dev = all_devices; dev; dev = dev->next) {
301 u8 new_devfn;
302
303 /* Only care about PCH PCIe root ports */
304 if (PCI_SLOT(dev->path.pci.devfn) !=
305 PCH_PCIE_DEV_SLOT)
306 continue;
307
308 /* Determine the new devfn for this port */
309 new_devfn = PCI_DEVFN(PCH_PCIE_DEV_SLOT,
310 RPFN_FNGET(new_rpfn,
311 PCI_FUNC(dev->path.pci.devfn)));
312
313 if (dev->path.pci.devfn != new_devfn) {
314 printk(BIOS_DEBUG,
315 "PCH: PCIe map %02x.%1x -> %02x.%1x\n",
316 PCI_SLOT(dev->path.pci.devfn),
317 PCI_FUNC(dev->path.pci.devfn),
318 PCI_SLOT(new_devfn), PCI_FUNC(new_devfn));
319
320 dev->path.pci.devfn = new_devfn;
321 }
322 }
323}
324
325/* Special handling for PCIe Root Port devices */
326static void pch_pcie_enable(device_t dev)
327{
328 struct southbridge_intel_lynxpoint_config *config = dev->chip_info;
329 u32 reg32;
330
331 /*
332 * Save a copy of the Root Port Function Number map when
333 * starting to walk the list of PCIe Root Ports so it can
334 * be updated locally and written out when the last port
335 * has been processed.
336 */
337 if (PCI_FUNC(dev->path.pci.devfn) == 0) {
338 new_rpfn = RCBA32(RPFN);
339
340 /*
341 * Enable Root Port coalescing if the first port is disabled
342 * or the other devices will not be enumerated by the OS.
343 */
344 if (!dev->enabled)
345 config->pcie_port_coalesce = 1;
346
347 if (config->pcie_port_coalesce)
348 printk(BIOS_INFO,
349 "PCH: PCIe Root Port coalescing is enabled\n");
350 }
351
352 if (!dev->enabled) {
353 printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
354
355 /*
356 * PCIE Power Savings for PantherPoint and CougarPoint/B1+
357 *
358 * If PCIe 0-3 disabled set Function 0 0xE2[0] = 1
359 * If PCIe 4-7 disabled set Function 4 0xE2[0] = 1
360 *
361 * This check is done here instead of pcie driver
362 * because the pcie driver enable() handler is not
363 * called unless the device is enabled.
364 */
365 if ((PCI_FUNC(dev->path.pci.devfn) == 0 ||
366 PCI_FUNC(dev->path.pci.devfn) == 4)) {
367 /* Handle workaround for PPT and CPT/B1+ */
368 if (!pch_pcie_check_set_enabled(dev)) {
369 u8 reg8 = pci_read_config8(dev, 0xe2);
370 reg8 |= 1;
371 pci_write_config8(dev, 0xe2, reg8);
372 }
373
374 /*
375 * Enable Clock Gating for shared PCIe resources
376 * before disabling this particular port.
377 */
378 pci_write_config8(dev, 0xe1, 0x3c);
379 }
380
381 /* Ensure memory, io, and bus master are all disabled */
382 reg32 = pci_read_config32(dev, PCI_COMMAND);
383 reg32 &= ~(PCI_COMMAND_MASTER |
384 PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
385 pci_write_config32(dev, PCI_COMMAND, reg32);
386
387 /* Do not claim downstream transactions for PCIe ports */
388 new_rpfn |= RPFN_HIDE(PCI_FUNC(dev->path.pci.devfn));
389
390 /* Hide this device if possible */
391 pch_hide_devfn(dev->path.pci.devfn);
392 } else {
393 int fn;
394
395 /*
396 * Check if there is a lower disabled port to swap with this
397 * port in order to maintain linear order starting at zero.
398 */
399 if (config->pcie_port_coalesce) {
400 for (fn=0; fn < PCI_FUNC(dev->path.pci.devfn); fn++) {
401 if (!(new_rpfn & RPFN_HIDE(fn)))
402 continue;
403
404 /* Swap places with this function */
405 pch_pcie_function_swap(
406 PCI_FUNC(dev->path.pci.devfn), fn);
407 break;
408 }
409 }
410
411 /* Enable SERR */
412 reg32 = pci_read_config32(dev, PCI_COMMAND);
413 reg32 |= PCI_COMMAND_SERR;
414 pci_write_config32(dev, PCI_COMMAND, reg32);
415 }
416
417 /*
418 * When processing the last PCIe root port we can now
419 * update the Root Port Function Number and Hide register.
420 */
421 if (PCI_FUNC(dev->path.pci.devfn) == 7) {
422 printk(BIOS_SPEW, "PCH: RPFN 0x%08x -> 0x%08x\n",
423 RCBA32(RPFN), new_rpfn);
424 RCBA32(RPFN) = new_rpfn;
425
426 /* Update static devictree with new function numbers */
427 if (config->pcie_port_coalesce)
428 pch_pcie_devicetree_update();
429 }
430}
431
432void pch_enable(device_t dev)
433{
434 u32 reg32;
435
436 /* PCH PCIe Root Ports get special handling */
437 if (PCI_SLOT(dev->path.pci.devfn) == PCH_PCIE_DEV_SLOT)
438 return pch_pcie_enable(dev);
439
440 if (!dev->enabled) {
441 printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
442
443 /* Ensure memory, io, and bus master are all disabled */
444 reg32 = pci_read_config32(dev, PCI_COMMAND);
445 reg32 &= ~(PCI_COMMAND_MASTER |
446 PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
447 pci_write_config32(dev, PCI_COMMAND, reg32);
448
449 /* Hide this device if possible */
450 pch_hide_devfn(dev->path.pci.devfn);
451 } else {
452 /* Enable SERR */
453 reg32 = pci_read_config32(dev, PCI_COMMAND);
454 reg32 |= PCI_COMMAND_SERR;
455 pci_write_config32(dev, PCI_COMMAND, reg32);
456 }
457}
458
459struct chip_operations southbridge_intel_lynxpoint_ops = {
460 CHIP_NAME("Intel Series 8 (Lynx Point) Southbridge")
461 .enable_dev = pch_enable,
462};
Duncan Laurie5cc51c02013-03-07 14:06:43 -0800463
464#endif /* __SMM__ */