blob: cc3718d444ec86cb3797da312dc0c2c96c557e71 [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#include <arch/io.h>
Aaron Durbin76c37002012-10-30 09:03:43 -050025#include <device/device.h>
26#include <device/pci.h>
Stefan Reinauer5605f1b2013-03-21 18:43:51 -070027#include <device/pci_def.h>
Aaron Durbin76c37002012-10-30 09:03:43 -050028#include "pch.h"
29
Duncan Laurie5cc51c02013-03-07 14:06:43 -080030static device_t pch_get_lpc_device(void)
31{
32#ifdef __SMM__
33 return PCI_DEV(0, 0x1f, 0);
34#else
35 return dev_find_slot(0, PCI_DEVFN(0x1f, 0));
36#endif
37}
Aaron Durbin76c37002012-10-30 09:03:43 -050038
39int pch_silicon_revision(void)
40{
Duncan Laurie5cc51c02013-03-07 14:06:43 -080041 static int pch_revision_id = -1;
42
Aaron Durbin76c37002012-10-30 09:03:43 -050043 if (pch_revision_id < 0)
Duncan Laurie5cc51c02013-03-07 14:06:43 -080044 pch_revision_id = pci_read_config8(pch_get_lpc_device(),
45 PCI_REVISION_ID);
Aaron Durbin76c37002012-10-30 09:03:43 -050046 return pch_revision_id;
47}
48
49int pch_silicon_type(void)
50{
Duncan Laurie5cc51c02013-03-07 14:06:43 -080051 static int pch_type = -1;
52
Aaron Durbin76c37002012-10-30 09:03:43 -050053 if (pch_type < 0)
Duncan Laurie5cc51c02013-03-07 14:06:43 -080054 pch_type = pci_read_config8(pch_get_lpc_device(),
55 PCI_DEVICE_ID + 1);
Aaron Durbin76c37002012-10-30 09:03:43 -050056 return pch_type;
57}
58
Duncan Laurie5cc51c02013-03-07 14:06:43 -080059int pch_is_lp(void)
Aaron Durbin76c37002012-10-30 09:03:43 -050060{
Duncan Laurie5cc51c02013-03-07 14:06:43 -080061 return pch_silicon_type() == PCH_TYPE_LPT_LP;
Aaron Durbin76c37002012-10-30 09:03:43 -050062}
63
Duncan Laurie1ad55642013-03-07 14:08:04 -080064u16 get_pmbase(void)
65{
66 static u16 pmbase;
67
68 if (!pmbase)
69 pmbase = pci_read_config16(pch_get_lpc_device(),
70 PMBASE) & 0xfffc;
71 return pmbase;
72}
73
74u16 get_gpiobase(void)
75{
76 static u16 gpiobase;
77
78 if (!gpiobase)
79 gpiobase = pci_read_config16(pch_get_lpc_device(),
80 GPIOBASE) & 0xfffc;
81 return gpiobase;
82}
83
Duncan Laurie5cc51c02013-03-07 14:06:43 -080084#ifndef __SMM__
85
Aaron Durbin76c37002012-10-30 09:03:43 -050086/* Set bit in Function Disble register to hide this device */
87static void pch_hide_devfn(unsigned devfn)
88{
89 switch (devfn) {
Duncan Laurie26e7dd72012-12-19 09:12:31 -080090 case PCI_DEVFN(19, 0): /* Audio DSP */
91 RCBA32_OR(FD, PCH_DISABLE_ADSPD);
92 break;
93 case PCI_DEVFN(20, 0): /* XHCI */
94 RCBA32_OR(FD, PCH_DISABLE_XHCI);
95 break;
Duncan Laurie71346c02013-01-10 13:20:40 -080096 case PCI_DEVFN(21, 0): /* DMA */
97 pch_iobp_update(SIO_IOBP_FUNCDIS0, ~0UL, SIO_IOBP_FUNCDIS_DIS);
98 break;
99 case PCI_DEVFN(21, 1): /* I2C0 */
100 pch_iobp_update(SIO_IOBP_FUNCDIS1, ~0UL, SIO_IOBP_FUNCDIS_DIS);
101 break;
102 case PCI_DEVFN(21, 2): /* I2C1 */
103 pch_iobp_update(SIO_IOBP_FUNCDIS2, ~0UL, SIO_IOBP_FUNCDIS_DIS);
104 break;
105 case PCI_DEVFN(21, 3): /* SPI0 */
106 pch_iobp_update(SIO_IOBP_FUNCDIS3, ~0UL, SIO_IOBP_FUNCDIS_DIS);
107 break;
108 case PCI_DEVFN(21, 4): /* SPI1 */
109 pch_iobp_update(SIO_IOBP_FUNCDIS4, ~0UL, SIO_IOBP_FUNCDIS_DIS);
110 break;
111 case PCI_DEVFN(21, 5): /* UART0 */
112 pch_iobp_update(SIO_IOBP_FUNCDIS5, ~0UL, SIO_IOBP_FUNCDIS_DIS);
113 break;
114 case PCI_DEVFN(21, 6): /* UART1 */
115 pch_iobp_update(SIO_IOBP_FUNCDIS6, ~0UL, SIO_IOBP_FUNCDIS_DIS);
116 break;
Aaron Durbin76c37002012-10-30 09:03:43 -0500117 case PCI_DEVFN(22, 0): /* MEI #1 */
118 RCBA32_OR(FD2, PCH_DISABLE_MEI1);
119 break;
120 case PCI_DEVFN(22, 1): /* MEI #2 */
121 RCBA32_OR(FD2, PCH_DISABLE_MEI2);
122 break;
123 case PCI_DEVFN(22, 2): /* IDE-R */
124 RCBA32_OR(FD2, PCH_DISABLE_IDER);
125 break;
126 case PCI_DEVFN(22, 3): /* KT */
127 RCBA32_OR(FD2, PCH_DISABLE_KT);
128 break;
Duncan Laurie71346c02013-01-10 13:20:40 -0800129 case PCI_DEVFN(23, 0): /* SDIO */
130 pch_iobp_update(SIO_IOBP_FUNCDIS7, ~0UL, SIO_IOBP_FUNCDIS_DIS);
131 break;
Aaron Durbin76c37002012-10-30 09:03:43 -0500132 case PCI_DEVFN(25, 0): /* Gigabit Ethernet */
133 RCBA32_OR(BUC, PCH_DISABLE_GBE);
134 break;
135 case PCI_DEVFN(26, 0): /* EHCI #2 */
136 RCBA32_OR(FD, PCH_DISABLE_EHCI2);
137 break;
138 case PCI_DEVFN(27, 0): /* HD Audio Controller */
139 RCBA32_OR(FD, PCH_DISABLE_HD_AUDIO);
140 break;
141 case PCI_DEVFN(28, 0): /* PCI Express Root Port 1 */
142 case PCI_DEVFN(28, 1): /* PCI Express Root Port 2 */
143 case PCI_DEVFN(28, 2): /* PCI Express Root Port 3 */
144 case PCI_DEVFN(28, 3): /* PCI Express Root Port 4 */
145 case PCI_DEVFN(28, 4): /* PCI Express Root Port 5 */
146 case PCI_DEVFN(28, 5): /* PCI Express Root Port 6 */
147 case PCI_DEVFN(28, 6): /* PCI Express Root Port 7 */
148 case PCI_DEVFN(28, 7): /* PCI Express Root Port 8 */
149 RCBA32_OR(FD, PCH_DISABLE_PCIE(PCI_FUNC(devfn)));
150 break;
151 case PCI_DEVFN(29, 0): /* EHCI #1 */
152 RCBA32_OR(FD, PCH_DISABLE_EHCI1);
153 break;
Aaron Durbin76c37002012-10-30 09:03:43 -0500154 case PCI_DEVFN(31, 0): /* LPC */
155 RCBA32_OR(FD, PCH_DISABLE_LPC);
156 break;
157 case PCI_DEVFN(31, 2): /* SATA #1 */
158 RCBA32_OR(FD, PCH_DISABLE_SATA1);
159 break;
160 case PCI_DEVFN(31, 3): /* SMBUS */
161 RCBA32_OR(FD, PCH_DISABLE_SMBUS);
162 break;
Duncan Laurie26e7dd72012-12-19 09:12:31 -0800163 case PCI_DEVFN(31, 5): /* SATA #2 */
Aaron Durbin76c37002012-10-30 09:03:43 -0500164 RCBA32_OR(FD, PCH_DISABLE_SATA2);
165 break;
166 case PCI_DEVFN(31, 6): /* Thermal Subsystem */
167 RCBA32_OR(FD, PCH_DISABLE_THERMAL);
168 break;
169 }
170}
171
172#define IOBP_RETRY 1000
173static inline int iobp_poll(void)
174{
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800175 unsigned try;
Aaron Durbin76c37002012-10-30 09:03:43 -0500176
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800177 for (try = IOBP_RETRY; try > 0; try--) {
178 u16 status = RCBA16(IOBPS);
179 if ((status & IOBPS_READY) == 0)
Aaron Durbin76c37002012-10-30 09:03:43 -0500180 return 1;
181 udelay(10);
182 }
183
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800184 printk(BIOS_ERR, "IOBP: timeout waiting for transaction to complete\n");
Aaron Durbin76c37002012-10-30 09:03:43 -0500185 return 0;
186}
187
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800188static u32 pch_iobp_read(u32 address)
Aaron Durbin76c37002012-10-30 09:03:43 -0500189{
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800190 u16 status;
191
192 if (!iobp_poll())
193 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500194
195 /* Set the address */
196 RCBA32(IOBPIRI) = address;
197
198 /* READ OPCODE */
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800199 status = RCBA16(IOBPS);
200 status &= ~IOBPS_MASK;
201 status |= IOBPS_READ;
202 RCBA16(IOBPS) = status;
Aaron Durbin76c37002012-10-30 09:03:43 -0500203
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800204 /* Undocumented magic */
205 RCBA16(IOBPU) = IOBPU_MAGIC;
206
207 /* Set ready bit */
208 status = RCBA16(IOBPS);
209 status |= IOBPS_READY;
210 RCBA16(IOBPS) = status;
211
Aaron Durbin76c37002012-10-30 09:03:43 -0500212 if (!iobp_poll())
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800213 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500214
215 /* Check for successful transaction */
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800216 status = RCBA16(IOBPS);
217 if (status & IOBPS_TX_MASK) {
218 printk(BIOS_ERR, "IOBP: read 0x%08x failed\n", address);
219 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500220 }
221
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800222 /* Read IOBP data */
223 return RCBA32(IOBPD);
224}
225
226void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue)
227{
228 u16 status;
229 u32 data = pch_iobp_read(address);
230
231 /* WRITE OPCODE */
232 status = RCBA16(IOBPS);
233 status &= ~IOBPS_MASK;
234 status |= IOBPS_WRITE;
235 RCBA16(IOBPS) = status;
236
Aaron Durbin76c37002012-10-30 09:03:43 -0500237 /* Update the data */
238 data &= andvalue;
239 data |= orvalue;
Aaron Durbin76c37002012-10-30 09:03:43 -0500240 RCBA32(IOBPD) = data;
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800241
242 /* Undocumented magic */
243 RCBA16(IOBPU) = IOBPU_MAGIC;
244
245 /* Set ready bit */
246 status = RCBA16(IOBPS);
247 status |= IOBPS_READY;
248 RCBA16(IOBPS) = status;
249
Aaron Durbin76c37002012-10-30 09:03:43 -0500250 if (!iobp_poll())
251 return;
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800252
253 /* Check for successful transaction */
254 status = RCBA16(IOBPS);
255 if (status & IOBPS_TX_MASK) {
256 printk(BIOS_ERR, "IOBP: write 0x%08x failed\n", address);
257 return;
258 }
259
260 printk(BIOS_INFO, "IOBP: set 0x%08x to 0x%08x\n", address, data);
Aaron Durbin76c37002012-10-30 09:03:43 -0500261}
262
263/* Check if any port in set X to X+3 is enabled */
264static int pch_pcie_check_set_enabled(device_t dev)
265{
266 device_t port;
267 int port_func;
268 int dev_func = PCI_FUNC(dev->path.pci.devfn);
269
270 printk(BIOS_DEBUG, "%s: check set enabled\n", dev_path(dev));
271
272 /* Go through static device tree list of devices
273 * because enumeration is still in progress */
274 for (port = all_devices; port; port = port->next) {
275 /* Only care about PCIe root ports */
276 if (PCI_SLOT(port->path.pci.devfn) !=
277 PCI_SLOT(dev->path.pci.devfn))
278 continue;
279
280 /* Check if port is in range and enabled */
281 port_func = PCI_FUNC(port->path.pci.devfn);
282 if (port_func >= dev_func &&
283 port_func < (dev_func + 4) &&
284 port->enabled)
285 return 1;
286 }
287
288 /* None of the ports in this set are enabled */
289 return 0;
290}
291
292/* RPFN is a write-once register so keep a copy until it is written */
293static u32 new_rpfn;
294
295/* Swap function numbers assigned to two PCIe Root Ports */
296static void pch_pcie_function_swap(u8 old_fn, u8 new_fn)
297{
298 u32 old_rpfn = new_rpfn;
299
300 printk(BIOS_DEBUG, "PCH: Remap PCIe function %d to %d\n",
301 old_fn, new_fn);
302
303 new_rpfn &= ~(RPFN_FNMASK(old_fn) | RPFN_FNMASK(new_fn));
304
305 /* Old function set to new function and disabled */
306 new_rpfn |= RPFN_FNSET(old_fn, RPFN_FNGET(old_rpfn, new_fn));
307 new_rpfn |= RPFN_FNSET(new_fn, RPFN_FNGET(old_rpfn, old_fn));
308}
309
310/* Update devicetree with new Root Port function number assignment */
311static void pch_pcie_devicetree_update(void)
312{
313 device_t dev;
314
315 /* Update the function numbers in the static devicetree */
316 for (dev = all_devices; dev; dev = dev->next) {
317 u8 new_devfn;
318
319 /* Only care about PCH PCIe root ports */
320 if (PCI_SLOT(dev->path.pci.devfn) !=
321 PCH_PCIE_DEV_SLOT)
322 continue;
323
324 /* Determine the new devfn for this port */
325 new_devfn = PCI_DEVFN(PCH_PCIE_DEV_SLOT,
326 RPFN_FNGET(new_rpfn,
327 PCI_FUNC(dev->path.pci.devfn)));
328
329 if (dev->path.pci.devfn != new_devfn) {
330 printk(BIOS_DEBUG,
331 "PCH: PCIe map %02x.%1x -> %02x.%1x\n",
332 PCI_SLOT(dev->path.pci.devfn),
333 PCI_FUNC(dev->path.pci.devfn),
334 PCI_SLOT(new_devfn), PCI_FUNC(new_devfn));
335
336 dev->path.pci.devfn = new_devfn;
337 }
338 }
339}
340
341/* Special handling for PCIe Root Port devices */
342static void pch_pcie_enable(device_t dev)
343{
344 struct southbridge_intel_lynxpoint_config *config = dev->chip_info;
345 u32 reg32;
346
347 /*
348 * Save a copy of the Root Port Function Number map when
349 * starting to walk the list of PCIe Root Ports so it can
350 * be updated locally and written out when the last port
351 * has been processed.
352 */
353 if (PCI_FUNC(dev->path.pci.devfn) == 0) {
354 new_rpfn = RCBA32(RPFN);
355
356 /*
357 * Enable Root Port coalescing if the first port is disabled
358 * or the other devices will not be enumerated by the OS.
359 */
360 if (!dev->enabled)
361 config->pcie_port_coalesce = 1;
362
363 if (config->pcie_port_coalesce)
364 printk(BIOS_INFO,
365 "PCH: PCIe Root Port coalescing is enabled\n");
366 }
367
368 if (!dev->enabled) {
369 printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
370
371 /*
372 * PCIE Power Savings for PantherPoint and CougarPoint/B1+
373 *
374 * If PCIe 0-3 disabled set Function 0 0xE2[0] = 1
375 * If PCIe 4-7 disabled set Function 4 0xE2[0] = 1
376 *
377 * This check is done here instead of pcie driver
378 * because the pcie driver enable() handler is not
379 * called unless the device is enabled.
380 */
381 if ((PCI_FUNC(dev->path.pci.devfn) == 0 ||
382 PCI_FUNC(dev->path.pci.devfn) == 4)) {
383 /* Handle workaround for PPT and CPT/B1+ */
384 if (!pch_pcie_check_set_enabled(dev)) {
385 u8 reg8 = pci_read_config8(dev, 0xe2);
386 reg8 |= 1;
387 pci_write_config8(dev, 0xe2, reg8);
388 }
389
390 /*
391 * Enable Clock Gating for shared PCIe resources
392 * before disabling this particular port.
393 */
394 pci_write_config8(dev, 0xe1, 0x3c);
395 }
396
397 /* Ensure memory, io, and bus master are all disabled */
398 reg32 = pci_read_config32(dev, PCI_COMMAND);
399 reg32 &= ~(PCI_COMMAND_MASTER |
400 PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
401 pci_write_config32(dev, PCI_COMMAND, reg32);
402
403 /* Do not claim downstream transactions for PCIe ports */
404 new_rpfn |= RPFN_HIDE(PCI_FUNC(dev->path.pci.devfn));
405
406 /* Hide this device if possible */
407 pch_hide_devfn(dev->path.pci.devfn);
408 } else {
409 int fn;
410
411 /*
412 * Check if there is a lower disabled port to swap with this
413 * port in order to maintain linear order starting at zero.
414 */
415 if (config->pcie_port_coalesce) {
416 for (fn=0; fn < PCI_FUNC(dev->path.pci.devfn); fn++) {
417 if (!(new_rpfn & RPFN_HIDE(fn)))
418 continue;
419
420 /* Swap places with this function */
421 pch_pcie_function_swap(
422 PCI_FUNC(dev->path.pci.devfn), fn);
423 break;
424 }
425 }
426
427 /* Enable SERR */
428 reg32 = pci_read_config32(dev, PCI_COMMAND);
429 reg32 |= PCI_COMMAND_SERR;
430 pci_write_config32(dev, PCI_COMMAND, reg32);
431 }
432
433 /*
434 * When processing the last PCIe root port we can now
435 * update the Root Port Function Number and Hide register.
436 */
437 if (PCI_FUNC(dev->path.pci.devfn) == 7) {
438 printk(BIOS_SPEW, "PCH: RPFN 0x%08x -> 0x%08x\n",
439 RCBA32(RPFN), new_rpfn);
440 RCBA32(RPFN) = new_rpfn;
441
442 /* Update static devictree with new function numbers */
443 if (config->pcie_port_coalesce)
444 pch_pcie_devicetree_update();
445 }
446}
447
448void pch_enable(device_t dev)
449{
450 u32 reg32;
451
452 /* PCH PCIe Root Ports get special handling */
453 if (PCI_SLOT(dev->path.pci.devfn) == PCH_PCIE_DEV_SLOT)
454 return pch_pcie_enable(dev);
455
456 if (!dev->enabled) {
457 printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
458
459 /* Ensure memory, io, and bus master are all disabled */
460 reg32 = pci_read_config32(dev, PCI_COMMAND);
461 reg32 &= ~(PCI_COMMAND_MASTER |
462 PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
463 pci_write_config32(dev, PCI_COMMAND, reg32);
464
465 /* Hide this device if possible */
466 pch_hide_devfn(dev->path.pci.devfn);
467 } else {
468 /* Enable SERR */
469 reg32 = pci_read_config32(dev, PCI_COMMAND);
470 reg32 |= PCI_COMMAND_SERR;
471 pci_write_config32(dev, PCI_COMMAND, reg32);
472 }
473}
474
475struct chip_operations southbridge_intel_lynxpoint_ops = {
476 CHIP_NAME("Intel Series 8 (Lynx Point) Southbridge")
477 .enable_dev = pch_enable,
478};
Duncan Laurie5cc51c02013-03-07 14:06:43 -0800479
480#endif /* __SMM__ */