blob: 41c596c43ab2585e49e40ac82917b4241acc78ab [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) {
Duncan Laurie26e7dd72012-12-19 09:12:31 -080058 case PCI_DEVFN(19, 0): /* Audio DSP */
59 RCBA32_OR(FD, PCH_DISABLE_ADSPD);
60 break;
61 case PCI_DEVFN(20, 0): /* XHCI */
62 RCBA32_OR(FD, PCH_DISABLE_XHCI);
63 break;
Duncan Laurie71346c02013-01-10 13:20:40 -080064 case PCI_DEVFN(21, 0): /* DMA */
65 pch_iobp_update(SIO_IOBP_FUNCDIS0, ~0UL, SIO_IOBP_FUNCDIS_DIS);
66 break;
67 case PCI_DEVFN(21, 1): /* I2C0 */
68 pch_iobp_update(SIO_IOBP_FUNCDIS1, ~0UL, SIO_IOBP_FUNCDIS_DIS);
69 break;
70 case PCI_DEVFN(21, 2): /* I2C1 */
71 pch_iobp_update(SIO_IOBP_FUNCDIS2, ~0UL, SIO_IOBP_FUNCDIS_DIS);
72 break;
73 case PCI_DEVFN(21, 3): /* SPI0 */
74 pch_iobp_update(SIO_IOBP_FUNCDIS3, ~0UL, SIO_IOBP_FUNCDIS_DIS);
75 break;
76 case PCI_DEVFN(21, 4): /* SPI1 */
77 pch_iobp_update(SIO_IOBP_FUNCDIS4, ~0UL, SIO_IOBP_FUNCDIS_DIS);
78 break;
79 case PCI_DEVFN(21, 5): /* UART0 */
80 pch_iobp_update(SIO_IOBP_FUNCDIS5, ~0UL, SIO_IOBP_FUNCDIS_DIS);
81 break;
82 case PCI_DEVFN(21, 6): /* UART1 */
83 pch_iobp_update(SIO_IOBP_FUNCDIS6, ~0UL, SIO_IOBP_FUNCDIS_DIS);
84 break;
Aaron Durbin76c37002012-10-30 09:03:43 -050085 case PCI_DEVFN(22, 0): /* MEI #1 */
86 RCBA32_OR(FD2, PCH_DISABLE_MEI1);
87 break;
88 case PCI_DEVFN(22, 1): /* MEI #2 */
89 RCBA32_OR(FD2, PCH_DISABLE_MEI2);
90 break;
91 case PCI_DEVFN(22, 2): /* IDE-R */
92 RCBA32_OR(FD2, PCH_DISABLE_IDER);
93 break;
94 case PCI_DEVFN(22, 3): /* KT */
95 RCBA32_OR(FD2, PCH_DISABLE_KT);
96 break;
Duncan Laurie71346c02013-01-10 13:20:40 -080097 case PCI_DEVFN(23, 0): /* SDIO */
98 pch_iobp_update(SIO_IOBP_FUNCDIS7, ~0UL, SIO_IOBP_FUNCDIS_DIS);
99 break;
Aaron Durbin76c37002012-10-30 09:03:43 -0500100 case PCI_DEVFN(25, 0): /* Gigabit Ethernet */
101 RCBA32_OR(BUC, PCH_DISABLE_GBE);
102 break;
103 case PCI_DEVFN(26, 0): /* EHCI #2 */
104 RCBA32_OR(FD, PCH_DISABLE_EHCI2);
105 break;
106 case PCI_DEVFN(27, 0): /* HD Audio Controller */
107 RCBA32_OR(FD, PCH_DISABLE_HD_AUDIO);
108 break;
109 case PCI_DEVFN(28, 0): /* PCI Express Root Port 1 */
110 case PCI_DEVFN(28, 1): /* PCI Express Root Port 2 */
111 case PCI_DEVFN(28, 2): /* PCI Express Root Port 3 */
112 case PCI_DEVFN(28, 3): /* PCI Express Root Port 4 */
113 case PCI_DEVFN(28, 4): /* PCI Express Root Port 5 */
114 case PCI_DEVFN(28, 5): /* PCI Express Root Port 6 */
115 case PCI_DEVFN(28, 6): /* PCI Express Root Port 7 */
116 case PCI_DEVFN(28, 7): /* PCI Express Root Port 8 */
117 RCBA32_OR(FD, PCH_DISABLE_PCIE(PCI_FUNC(devfn)));
118 break;
119 case PCI_DEVFN(29, 0): /* EHCI #1 */
120 RCBA32_OR(FD, PCH_DISABLE_EHCI1);
121 break;
Aaron Durbin76c37002012-10-30 09:03:43 -0500122 case PCI_DEVFN(31, 0): /* LPC */
123 RCBA32_OR(FD, PCH_DISABLE_LPC);
124 break;
125 case PCI_DEVFN(31, 2): /* SATA #1 */
126 RCBA32_OR(FD, PCH_DISABLE_SATA1);
127 break;
128 case PCI_DEVFN(31, 3): /* SMBUS */
129 RCBA32_OR(FD, PCH_DISABLE_SMBUS);
130 break;
Duncan Laurie26e7dd72012-12-19 09:12:31 -0800131 case PCI_DEVFN(31, 5): /* SATA #2 */
Aaron Durbin76c37002012-10-30 09:03:43 -0500132 RCBA32_OR(FD, PCH_DISABLE_SATA2);
133 break;
134 case PCI_DEVFN(31, 6): /* Thermal Subsystem */
135 RCBA32_OR(FD, PCH_DISABLE_THERMAL);
136 break;
137 }
138}
139
140#define IOBP_RETRY 1000
141static inline int iobp_poll(void)
142{
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800143 unsigned try;
Aaron Durbin76c37002012-10-30 09:03:43 -0500144
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800145 for (try = IOBP_RETRY; try > 0; try--) {
146 u16 status = RCBA16(IOBPS);
147 if ((status & IOBPS_READY) == 0)
Aaron Durbin76c37002012-10-30 09:03:43 -0500148 return 1;
149 udelay(10);
150 }
151
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800152 printk(BIOS_ERR, "IOBP: timeout waiting for transaction to complete\n");
Aaron Durbin76c37002012-10-30 09:03:43 -0500153 return 0;
154}
155
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800156static u32 pch_iobp_read(u32 address)
Aaron Durbin76c37002012-10-30 09:03:43 -0500157{
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800158 u16 status;
159
160 if (!iobp_poll())
161 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500162
163 /* Set the address */
164 RCBA32(IOBPIRI) = address;
165
166 /* READ OPCODE */
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800167 status = RCBA16(IOBPS);
168 status &= ~IOBPS_MASK;
169 status |= IOBPS_READ;
170 RCBA16(IOBPS) = status;
Aaron Durbin76c37002012-10-30 09:03:43 -0500171
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800172 /* Undocumented magic */
173 RCBA16(IOBPU) = IOBPU_MAGIC;
174
175 /* Set ready bit */
176 status = RCBA16(IOBPS);
177 status |= IOBPS_READY;
178 RCBA16(IOBPS) = status;
179
Aaron Durbin76c37002012-10-30 09:03:43 -0500180 if (!iobp_poll())
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800181 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500182
183 /* Check for successful transaction */
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800184 status = RCBA16(IOBPS);
185 if (status & IOBPS_TX_MASK) {
186 printk(BIOS_ERR, "IOBP: read 0x%08x failed\n", address);
187 return 0;
Aaron Durbin76c37002012-10-30 09:03:43 -0500188 }
189
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800190 /* Read IOBP data */
191 return RCBA32(IOBPD);
192}
193
194void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue)
195{
196 u16 status;
197 u32 data = pch_iobp_read(address);
198
199 /* WRITE OPCODE */
200 status = RCBA16(IOBPS);
201 status &= ~IOBPS_MASK;
202 status |= IOBPS_WRITE;
203 RCBA16(IOBPS) = status;
204
Aaron Durbin76c37002012-10-30 09:03:43 -0500205 /* Update the data */
206 data &= andvalue;
207 data |= orvalue;
Aaron Durbin76c37002012-10-30 09:03:43 -0500208 RCBA32(IOBPD) = data;
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800209
210 /* Undocumented magic */
211 RCBA16(IOBPU) = IOBPU_MAGIC;
212
213 /* Set ready bit */
214 status = RCBA16(IOBPS);
215 status |= IOBPS_READY;
216 RCBA16(IOBPS) = status;
217
Aaron Durbin76c37002012-10-30 09:03:43 -0500218 if (!iobp_poll())
219 return;
Duncan Laurie7302d1e2013-01-10 13:19:23 -0800220
221 /* Check for successful transaction */
222 status = RCBA16(IOBPS);
223 if (status & IOBPS_TX_MASK) {
224 printk(BIOS_ERR, "IOBP: write 0x%08x failed\n", address);
225 return;
226 }
227
228 printk(BIOS_INFO, "IOBP: set 0x%08x to 0x%08x\n", address, data);
Aaron Durbin76c37002012-10-30 09:03:43 -0500229}
230
231/* Check if any port in set X to X+3 is enabled */
232static int pch_pcie_check_set_enabled(device_t dev)
233{
234 device_t port;
235 int port_func;
236 int dev_func = PCI_FUNC(dev->path.pci.devfn);
237
238 printk(BIOS_DEBUG, "%s: check set enabled\n", dev_path(dev));
239
240 /* Go through static device tree list of devices
241 * because enumeration is still in progress */
242 for (port = all_devices; port; port = port->next) {
243 /* Only care about PCIe root ports */
244 if (PCI_SLOT(port->path.pci.devfn) !=
245 PCI_SLOT(dev->path.pci.devfn))
246 continue;
247
248 /* Check if port is in range and enabled */
249 port_func = PCI_FUNC(port->path.pci.devfn);
250 if (port_func >= dev_func &&
251 port_func < (dev_func + 4) &&
252 port->enabled)
253 return 1;
254 }
255
256 /* None of the ports in this set are enabled */
257 return 0;
258}
259
260/* RPFN is a write-once register so keep a copy until it is written */
261static u32 new_rpfn;
262
263/* Swap function numbers assigned to two PCIe Root Ports */
264static void pch_pcie_function_swap(u8 old_fn, u8 new_fn)
265{
266 u32 old_rpfn = new_rpfn;
267
268 printk(BIOS_DEBUG, "PCH: Remap PCIe function %d to %d\n",
269 old_fn, new_fn);
270
271 new_rpfn &= ~(RPFN_FNMASK(old_fn) | RPFN_FNMASK(new_fn));
272
273 /* Old function set to new function and disabled */
274 new_rpfn |= RPFN_FNSET(old_fn, RPFN_FNGET(old_rpfn, new_fn));
275 new_rpfn |= RPFN_FNSET(new_fn, RPFN_FNGET(old_rpfn, old_fn));
276}
277
278/* Update devicetree with new Root Port function number assignment */
279static void pch_pcie_devicetree_update(void)
280{
281 device_t dev;
282
283 /* Update the function numbers in the static devicetree */
284 for (dev = all_devices; dev; dev = dev->next) {
285 u8 new_devfn;
286
287 /* Only care about PCH PCIe root ports */
288 if (PCI_SLOT(dev->path.pci.devfn) !=
289 PCH_PCIE_DEV_SLOT)
290 continue;
291
292 /* Determine the new devfn for this port */
293 new_devfn = PCI_DEVFN(PCH_PCIE_DEV_SLOT,
294 RPFN_FNGET(new_rpfn,
295 PCI_FUNC(dev->path.pci.devfn)));
296
297 if (dev->path.pci.devfn != new_devfn) {
298 printk(BIOS_DEBUG,
299 "PCH: PCIe map %02x.%1x -> %02x.%1x\n",
300 PCI_SLOT(dev->path.pci.devfn),
301 PCI_FUNC(dev->path.pci.devfn),
302 PCI_SLOT(new_devfn), PCI_FUNC(new_devfn));
303
304 dev->path.pci.devfn = new_devfn;
305 }
306 }
307}
308
309/* Special handling for PCIe Root Port devices */
310static void pch_pcie_enable(device_t dev)
311{
312 struct southbridge_intel_lynxpoint_config *config = dev->chip_info;
313 u32 reg32;
314
315 /*
316 * Save a copy of the Root Port Function Number map when
317 * starting to walk the list of PCIe Root Ports so it can
318 * be updated locally and written out when the last port
319 * has been processed.
320 */
321 if (PCI_FUNC(dev->path.pci.devfn) == 0) {
322 new_rpfn = RCBA32(RPFN);
323
324 /*
325 * Enable Root Port coalescing if the first port is disabled
326 * or the other devices will not be enumerated by the OS.
327 */
328 if (!dev->enabled)
329 config->pcie_port_coalesce = 1;
330
331 if (config->pcie_port_coalesce)
332 printk(BIOS_INFO,
333 "PCH: PCIe Root Port coalescing is enabled\n");
334 }
335
336 if (!dev->enabled) {
337 printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
338
339 /*
340 * PCIE Power Savings for PantherPoint and CougarPoint/B1+
341 *
342 * If PCIe 0-3 disabled set Function 0 0xE2[0] = 1
343 * If PCIe 4-7 disabled set Function 4 0xE2[0] = 1
344 *
345 * This check is done here instead of pcie driver
346 * because the pcie driver enable() handler is not
347 * called unless the device is enabled.
348 */
349 if ((PCI_FUNC(dev->path.pci.devfn) == 0 ||
350 PCI_FUNC(dev->path.pci.devfn) == 4)) {
351 /* Handle workaround for PPT and CPT/B1+ */
352 if (!pch_pcie_check_set_enabled(dev)) {
353 u8 reg8 = pci_read_config8(dev, 0xe2);
354 reg8 |= 1;
355 pci_write_config8(dev, 0xe2, reg8);
356 }
357
358 /*
359 * Enable Clock Gating for shared PCIe resources
360 * before disabling this particular port.
361 */
362 pci_write_config8(dev, 0xe1, 0x3c);
363 }
364
365 /* Ensure memory, io, and bus master are all disabled */
366 reg32 = pci_read_config32(dev, PCI_COMMAND);
367 reg32 &= ~(PCI_COMMAND_MASTER |
368 PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
369 pci_write_config32(dev, PCI_COMMAND, reg32);
370
371 /* Do not claim downstream transactions for PCIe ports */
372 new_rpfn |= RPFN_HIDE(PCI_FUNC(dev->path.pci.devfn));
373
374 /* Hide this device if possible */
375 pch_hide_devfn(dev->path.pci.devfn);
376 } else {
377 int fn;
378
379 /*
380 * Check if there is a lower disabled port to swap with this
381 * port in order to maintain linear order starting at zero.
382 */
383 if (config->pcie_port_coalesce) {
384 for (fn=0; fn < PCI_FUNC(dev->path.pci.devfn); fn++) {
385 if (!(new_rpfn & RPFN_HIDE(fn)))
386 continue;
387
388 /* Swap places with this function */
389 pch_pcie_function_swap(
390 PCI_FUNC(dev->path.pci.devfn), fn);
391 break;
392 }
393 }
394
395 /* Enable SERR */
396 reg32 = pci_read_config32(dev, PCI_COMMAND);
397 reg32 |= PCI_COMMAND_SERR;
398 pci_write_config32(dev, PCI_COMMAND, reg32);
399 }
400
401 /*
402 * When processing the last PCIe root port we can now
403 * update the Root Port Function Number and Hide register.
404 */
405 if (PCI_FUNC(dev->path.pci.devfn) == 7) {
406 printk(BIOS_SPEW, "PCH: RPFN 0x%08x -> 0x%08x\n",
407 RCBA32(RPFN), new_rpfn);
408 RCBA32(RPFN) = new_rpfn;
409
410 /* Update static devictree with new function numbers */
411 if (config->pcie_port_coalesce)
412 pch_pcie_devicetree_update();
413 }
414}
415
416void pch_enable(device_t dev)
417{
418 u32 reg32;
419
420 /* PCH PCIe Root Ports get special handling */
421 if (PCI_SLOT(dev->path.pci.devfn) == PCH_PCIE_DEV_SLOT)
422 return pch_pcie_enable(dev);
423
424 if (!dev->enabled) {
425 printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
426
427 /* Ensure memory, io, and bus master are all disabled */
428 reg32 = pci_read_config32(dev, PCI_COMMAND);
429 reg32 &= ~(PCI_COMMAND_MASTER |
430 PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
431 pci_write_config32(dev, PCI_COMMAND, reg32);
432
433 /* Hide this device if possible */
434 pch_hide_devfn(dev->path.pci.devfn);
435 } else {
436 /* Enable SERR */
437 reg32 = pci_read_config32(dev, PCI_COMMAND);
438 reg32 |= PCI_COMMAND_SERR;
439 pci_write_config32(dev, PCI_COMMAND, reg32);
440 }
441}
442
443struct chip_operations southbridge_intel_lynxpoint_ops = {
444 CHIP_NAME("Intel Series 8 (Lynx Point) Southbridge")
445 .enable_dev = pch_enable,
446};