blob: c1aa9103c8669b2d280fcbbcd478f1bd242680a8 [file] [log] [blame]
Duncan Lauriec88c54c2014-04-30 16:36:13 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2008-2009 coresystems GmbH
5 * Copyright (C) 2014 Google Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of 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 <device/device.h>
23#include <device/pci.h>
24#include <device/pciexp.h>
25#include <device/pci_def.h>
26#include <device/pci_ids.h>
Julius Werner4ee4bd52014-10-20 13:46:39 -070027#include <soc/gpio.h>
28#include <soc/lpc.h>
29#include <soc/iobp.h>
30#include <soc/pch.h>
31#include <soc/pci_devs.h>
32#include <soc/rcba.h>
33#include <soc/intel/broadwell/chip.h>
34#include <soc/cpu.h>
Duncan Lauriec88c54c2014-04-30 16:36:13 -070035
36static void pcie_update_cfg8(device_t dev, int reg, u8 mask, u8 or);
37static void pcie_update_cfg(device_t dev, int reg, u32 mask, u32 or);
38
39/* Low Power variant has 6 root ports. */
40#define NUM_ROOT_PORTS 6
41
42struct root_port_config {
43 /* RPFN is a write-once register so keep a copy until it is written */
44 u32 orig_rpfn;
45 u32 new_rpfn;
46 u32 pin_ownership;
47 u32 strpfusecfg1;
48 u32 strpfusecfg2;
49 u32 strpfusecfg3;
50 u32 b0d28f0_32c;
51 u32 b0d28f4_32c;
52 u32 b0d28f5_32c;
53 int coalesce;
54 int gbe_port;
55 int num_ports;
56 device_t ports[NUM_ROOT_PORTS];
57};
58
59static struct root_port_config rpc;
60
61static inline int root_port_is_first(device_t dev)
62{
63 return PCI_FUNC(dev->path.pci.devfn) == 0;
64}
65
66static inline int root_port_is_last(device_t dev)
67{
68 return PCI_FUNC(dev->path.pci.devfn) == (rpc.num_ports - 1);
69}
70
71/* Root ports are numbered 1..N in the documentation. */
72static inline int root_port_number(device_t dev)
73{
74 return PCI_FUNC(dev->path.pci.devfn) + 1;
75}
76
77static void root_port_config_update_gbe_port(void)
78{
79 /* Is the Gbe Port enabled? */
80 if (!((rpc.strpfusecfg1 >> 19) & 1))
81 return;
82
83 switch ((rpc.strpfusecfg1 >> 16) & 0x7) {
84 case 0:
85 rpc.gbe_port = 3;
86 break;
87 case 1:
88 rpc.gbe_port = 4;
89 break;
90 case 2:
91 case 3:
92 case 4:
93 case 5:
94 /* Lanes 0-4 of Root Port 5. */
95 rpc.gbe_port = 5;
96 break;
97 default:
98 printk(BIOS_DEBUG, "Invalid GbE Port Selection.\n");
99 }
100}
101
Kenji Chen87d4a202014-09-24 01:18:26 +0800102static void pcie_iosf_port_grant_count(device_t dev)
103{
104 u8 update_val;
105 u32 rpcd = (pci_read_config32(dev, 0xfc) > 14) & 0x3;
106
107 switch (rpcd) {
108 case 1:
109 case 3:
110 update_val = 0x02;
111 break;
112 case 2:
113 update_val = 0x22;
114 break;
115 default:
116 update_val = 0x00;
117 break;
118 }
119
120 RCBA32(0x103C) = (RCBA32(0x103C) & (~0xff)) | update_val;
121}
122
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700123static void root_port_init_config(device_t dev)
124{
125 int rp;
Kenji Chene383feb2014-09-26 03:14:57 +0800126 u32 data;
127 u8 resp, id;
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700128
129 if (root_port_is_first(dev)) {
130 rpc.orig_rpfn = RCBA32(RPFN);
131 rpc.new_rpfn = rpc.orig_rpfn;
132 rpc.num_ports = NUM_ROOT_PORTS;
133 rpc.gbe_port = -1;
Kenji Chen87d4a202014-09-24 01:18:26 +0800134 /* RP0 f5[3:0] = 0101b*/
135 pcie_update_cfg8(dev, 0xf5, ~0xa, 0x5);
136
137 pcie_iosf_port_grant_count(dev);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700138
139 rpc.pin_ownership = pci_read_config32(dev, 0x410);
140 root_port_config_update_gbe_port();
141
Kane Chen642e5982014-09-09 15:53:09 -0700142 pcie_update_cfg8(dev, 0xe2, ~(3 << 4), (3 << 4));
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700143 if (dev->chip_info != NULL) {
144 config_t *config = dev->chip_info;
145 rpc.coalesce = config->pcie_port_coalesce;
146 }
147 }
148
149 rp = root_port_number(dev);
150 if (rp > rpc.num_ports) {
151 printk(BIOS_ERR, "Found Root Port %d, expecting %d\n",
152 rp, rpc.num_ports);
153 return;
154 }
155
156 /* Read the fuse configuration and pin ownership. */
157 switch (rp) {
158 case 1:
159 rpc.strpfusecfg1 = pci_read_config32(dev, 0xfc);
160 rpc.b0d28f0_32c = pci_read_config32(dev, 0x32c);
161 break;
162 case 5:
163 rpc.strpfusecfg2 = pci_read_config32(dev, 0xfc);
164 rpc.b0d28f4_32c = pci_read_config32(dev, 0x32c);
165 break;
166 case 6:
167 rpc.b0d28f5_32c = pci_read_config32(dev, 0x32c);
168 rpc.strpfusecfg3 = pci_read_config32(dev, 0xfc);
169 break;
170 default:
171 break;
172 }
173
Kane Chen46134722014-08-28 17:05:06 -0700174 pcie_update_cfg(dev, 0x418, 0, 0x02000430);
Kenji Chene383feb2014-09-26 03:14:57 +0800175
176 /* set RP0 PCICFG E2h[5:4] = 11b before configuring ASPM */
177 if (root_port_is_first(dev)) {
178 id = 0xe0 + (u8)(RCBA32(RPFN) & 0x07);
179 pch_iobp_exec(0xE00000E0, IOBP_PCICFG_READ, id, &data, &resp);
180 data |= (0x30 << 16);
181 pch_iobp_exec(0xE00000E0, IOBP_PCICFG_WRITE, id, &data, &resp);
182 }
183
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700184 /* Cache pci device. */
185 rpc.ports[rp - 1] = dev;
186}
187
188/* Update devicetree with new Root Port function number assignment */
189static void pch_pcie_device_set_func(int index, int pci_func)
190{
191 device_t dev;
192 unsigned new_devfn;
193
194 dev = rpc.ports[index];
195
196 /* Set the new PCI function field for this Root Port. */
197 rpc.new_rpfn &= ~RPFN_FNMASK(index);
198 rpc.new_rpfn |= RPFN_FNSET(index, pci_func);
199
200 /* Determine the new devfn for this port */
201 new_devfn = PCI_DEVFN(PCH_DEV_SLOT_PCIE, pci_func);
202
203 if (dev->path.pci.devfn != new_devfn) {
204 printk(BIOS_DEBUG,
205 "PCH: PCIe map %02x.%1x -> %02x.%1x\n",
206 PCI_SLOT(dev->path.pci.devfn),
207 PCI_FUNC(dev->path.pci.devfn),
208 PCI_SLOT(new_devfn), PCI_FUNC(new_devfn));
209
210 dev->path.pci.devfn = new_devfn;
211 }
212}
213
214static void pcie_enable_clock_gating(void)
215{
216 int i;
217 int enabled_ports = 0;
Kane Chen4fef5a22014-08-27 15:21:32 -0700218 int is_broadwell = !!(cpu_family_model() == BROADWELL_FAMILY_ULT);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700219
220 for (i = 0; i < rpc.num_ports; i++) {
221 device_t dev;
222 int rp;
223
224 dev = rpc.ports[i];
225 rp = root_port_number(dev);
226
227 if (!dev->enabled) {
228 /* Configure shared resource clock gating. */
229 if (rp == 1 || rp == 5 || rp == 6)
230 pcie_update_cfg8(dev, 0xe1, 0xc3, 0x3c);
231
232 pcie_update_cfg8(dev, 0xe2, ~(3 << 4), (3 << 4));
233 pcie_update_cfg(dev, 0x420, ~(1 << 31), (1 << 31));
234
235 /* Per-Port CLKREQ# handling. */
236 if (gpio_is_native(18 + rp - 1))
237 pcie_update_cfg(dev, 0x420, ~0, (3 << 29));
238
239 /* Enable static clock gating. */
240 if (rp == 1 && !rpc.ports[1]->enabled &&
241 !rpc.ports[2]->enabled && !rpc.ports[3]->enabled) {
242 pcie_update_cfg8(dev, 0xe2, ~1, 1);
243 pcie_update_cfg8(dev, 0xe1, 0x7f, 0x80);
244 } else if (rp == 5 || rp == 6) {
245 pcie_update_cfg8(dev, 0xe2, ~1, 1);
246 pcie_update_cfg8(dev, 0xe1, 0x7f, 0x80);
247 }
248 continue;
249 }
250
251 enabled_ports++;
252
253 /* Enable dynamic clock gating. */
254 pcie_update_cfg8(dev, 0xe1, 0xfc, 0x03);
255 pcie_update_cfg8(dev, 0xe2, ~(1 << 6), (1 << 6));
256 pcie_update_cfg8(dev, 0xe8, ~(3 << 2), (2 << 2));
257
258 /* Update PECR1 register. */
Kane Chen4fef5a22014-08-27 15:21:32 -0700259 pcie_update_cfg8(dev, 0xe8, ~0, 3);
260 if (is_broadwell) {
261 pcie_update_cfg(dev, 0x324, ~((1 << 5) | (1 << 14)),
262 ((1 << 5) | (1 << 14)));
263 } else {
264 pcie_update_cfg(dev, 0x324, ~(1 << 5), (1 << 5));
265 }
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700266 /* Per-Port CLKREQ# handling. */
267 if (gpio_is_native(18 + rp - 1))
268 pcie_update_cfg(dev, 0x420, ~0, (3 << 29));
269
270 /* Configure shared resource clock gating. */
271 if (rp == 1 || rp == 5 || rp == 6)
272 pcie_update_cfg8(dev, 0xe1, 0xc3, 0x3c);
Duncan Laurie446fb8e2014-08-08 09:59:43 -0700273
274 /* CLKREQ# VR Idle Enable */
275 RCBA32_OR(0x2b1c, (1 << (16 + i)));
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700276 }
277
278 if (!enabled_ports)
279 pcie_update_cfg8(rpc.ports[0], 0xe1, ~(1 << 6), (1 << 6));
280}
281
282static void root_port_commit_config(void)
283{
284 int i;
285
286 /* If the first root port is disabled the coalesce ports. */
287 if (!rpc.ports[0]->enabled)
288 rpc.coalesce = 1;
289
290 /* Perform clock gating configuration. */
291 pcie_enable_clock_gating();
292
293 for (i = 0; i < rpc.num_ports; i++) {
294 device_t dev;
295 u32 reg32;
296
297 dev = rpc.ports[i];
298
299 if (dev == NULL) {
300 printk(BIOS_ERR, "Root Port %d device is NULL?\n", i+1);
301 continue;
302 }
303
304 if (dev->enabled)
305 continue;
306
307 printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
308
309 /* Ensure memory, io, and bus master are all disabled */
310 reg32 = pci_read_config32(dev, PCI_COMMAND);
311 reg32 &= ~(PCI_COMMAND_MASTER |
312 PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
313 pci_write_config32(dev, PCI_COMMAND, reg32);
314
315 /* Disable this device if possible */
316 pch_disable_devfn(dev);
317 }
318
319 if (rpc.coalesce) {
320 int current_func;
321
322 /* For all Root Ports N enabled ports get assigned the lower
323 * PCI function number. The disabled ones get upper PCI
324 * function numbers. */
325 current_func = 0;
326 for (i = 0; i < rpc.num_ports; i++) {
327 if (!rpc.ports[i]->enabled)
328 continue;
329 pch_pcie_device_set_func(i, current_func);
330 current_func++;
331 }
332
333 /* Allocate the disabled devices' PCI function number. */
334 for (i = 0; i < rpc.num_ports; i++) {
335 if (rpc.ports[i]->enabled)
336 continue;
337 pch_pcie_device_set_func(i, current_func);
338 current_func++;
339 }
340 }
341
342 printk(BIOS_SPEW, "PCH: RPFN 0x%08x -> 0x%08x\n",
343 rpc.orig_rpfn, rpc.new_rpfn);
344 RCBA32(RPFN) = rpc.new_rpfn;
345}
346
347static void root_port_mark_disable(device_t dev)
348{
349 /* Mark device as disabled. */
350 dev->enabled = 0;
351 /* Mark device to be hidden. */
352 rpc.new_rpfn |= RPFN_HIDE(PCI_FUNC(dev->path.pci.devfn));
353}
354
355static void root_port_check_disable(device_t dev)
356{
357 int rp;
358
359 /* Device already disabled. */
360 if (!dev->enabled) {
361 root_port_mark_disable(dev);
362 return;
363 }
364
365 rp = root_port_number(dev);
366
367 /* Is the GbE port mapped to this Root Port? */
368 if (rp == rpc.gbe_port) {
369 root_port_mark_disable(dev);
370 return;
371 }
372
373 /* Check Root Port Configuration. */
374 switch (rp) {
375 case 2:
376 /* Root Port 2 is disabled for all lane configurations
377 * but config 00b (4x1 links). */
378 if ((rpc.strpfusecfg1 >> 14) & 0x3) {
379 root_port_mark_disable(dev);
380 return;
381 }
382 break;
383 case 3:
384 /* Root Port 3 is disabled in config 11b (1x4 links). */
385 if (((rpc.strpfusecfg1 >> 14) & 0x3) == 0x3) {
386 root_port_mark_disable(dev);
387 return;
388 }
389 break;
390 case 4:
391 /* Root Port 4 is disabled in configs 11b (1x4 links)
392 * and 10b (2x2 links). */
393 if ((rpc.strpfusecfg1 >> 14) & 0x2) {
394 root_port_mark_disable(dev);
395 return;
396 }
397 break;
398 }
399
400 /* Check Pin Ownership. */
401 switch (rp) {
402 case 1:
403 /* Bit 0 is Root Port 1 ownership. */
404 if ((rpc.pin_ownership & 0x1) == 0) {
405 root_port_mark_disable(dev);
406 return;
407 }
408 break;
409 case 2:
410 /* Bit 2 is Root Port 2 ownership. */
411 if ((rpc.pin_ownership & 0x4) == 0) {
412 root_port_mark_disable(dev);
413 return;
414 }
415 break;
416 case 6:
417 /* Bits 7:4 are Root Port 6 pin-lane ownership. */
418 if ((rpc.pin_ownership & 0xf0) == 0) {
419 root_port_mark_disable(dev);
420 return;
421 }
422 break;
423 }
424}
425
426static void pcie_update_cfg8(device_t dev, int reg, u8 mask, u8 or)
427{
428 u8 reg8;
429
430 reg8 = pci_read_config8(dev, reg);
431 reg8 &= mask;
432 reg8 |= or;
433 pci_write_config8(dev, reg, reg8);
434}
435
436static void pcie_update_cfg(device_t dev, int reg, u32 mask, u32 or)
437{
438 u32 reg32;
439
440 reg32 = pci_read_config32(dev, reg);
441 reg32 &= mask;
442 reg32 |= or;
443 pci_write_config32(dev, reg, reg32);
444}
445
446static void pcie_add_0x0202000_iobp(u32 reg)
447{
448 u32 reg32;
449
450 reg32 = pch_iobp_read(reg);
451 reg32 += (0x2 << 16) | (0x2 << 8);
452 pch_iobp_write(reg, reg32);
453}
454
455static void pch_pcie_early(struct device *dev)
456{
457 config_t *config = dev->chip_info;
458 int do_aspm = 0;
459 int rp = root_port_number(dev);
460
461 switch (rp) {
462 case 1:
463 case 2:
464 case 3:
465 case 4:
466 /*
Martin Rothde7ed6f2014-12-07 14:58:18 -0700467 * Bits 31:28 of b0d28f0 0x32c register correspond to
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700468 * Root Ports 4:1.
469 */
470 do_aspm = !!(rpc.b0d28f0_32c & (1 << (28 + rp - 1)));
471 break;
472 case 5:
473 /*
Martin Rothde7ed6f2014-12-07 14:58:18 -0700474 * Bit 28 of b0d28f4 0x32c register correspond to
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700475 * Root Ports 4:1.
476 */
477 do_aspm = !!(rpc.b0d28f4_32c & (1 << 28));
478 break;
479 case 6:
480 /*
Martin Rothde7ed6f2014-12-07 14:58:18 -0700481 * Bit 28 of b0d28f5 0x32c register correspond to
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700482 * Root Ports 4:1.
483 */
484 do_aspm = !!(rpc.b0d28f5_32c & (1 << 28));
485 break;
486 }
487
488 /* Allow ASPM to be forced on in devicetree */
489 if (config && (config->pcie_port_force_aspm & (1 << (rp - 1))))
490 do_aspm = 1;
491
492 printk(BIOS_DEBUG, "PCIe Root Port %d ASPM is %sabled\n",
493 rp, do_aspm ? "en" : "dis");
494
495 if (do_aspm) {
496 /* Set ASPM bits in MPC2 register. */
497 pcie_update_cfg(dev, 0xd4, ~(0x3 << 2), (1 << 4) | (0x2 << 2));
498
499 /* Set unique clock exit latency in MPC register. */
500 pcie_update_cfg(dev, 0xd8, ~(0x7 << 18), (0x7 << 18));
501
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700502 switch (rp) {
503 case 1:
504 pcie_add_0x0202000_iobp(0xe9002440);
505 break;
506 case 2:
507 pcie_add_0x0202000_iobp(0xe9002640);
508 break;
509 case 3:
510 pcie_add_0x0202000_iobp(0xe9000840);
511 break;
512 case 4:
513 pcie_add_0x0202000_iobp(0xe9000a40);
514 break;
515 case 5:
516 pcie_add_0x0202000_iobp(0xe9000c40);
517 pcie_add_0x0202000_iobp(0xe9000e40);
518 pcie_add_0x0202000_iobp(0xe9001040);
519 pcie_add_0x0202000_iobp(0xe9001240);
520 break;
521 case 6:
522 /* Update IOBP based on lane ownership. */
523 if (rpc.pin_ownership & (1 << 4))
524 pcie_add_0x0202000_iobp(0xea002040);
525 if (rpc.pin_ownership & (1 << 5))
526 pcie_add_0x0202000_iobp(0xea002240);
527 if (rpc.pin_ownership & (1 << 6))
528 pcie_add_0x0202000_iobp(0xea002440);
529 if (rpc.pin_ownership & (1 << 7))
530 pcie_add_0x0202000_iobp(0xea002640);
531 break;
532 }
533
534 pcie_update_cfg(dev, 0x338, ~(1 << 26), 0);
535 }
536
Kenji Chenc373f502014-09-26 02:48:16 +0800537 /* Enable LTR in Root Port. Disable OBFF. */
538 pcie_update_cfg(dev, 0x64, ~(1 << 11) & ~(3 << 18), (1 << 11));
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700539 pcie_update_cfg(dev, 0x68, ~(1 << 10), (1 << 10));
540
541 pcie_update_cfg(dev, 0x318, ~(0xffff << 16), (0x1414 << 16));
542
543 /* Set L1 exit latency in LCAP register. */
544 if (!do_aspm && (pci_read_config8(dev, 0xf5) & 0x1))
545 pcie_update_cfg(dev, 0x4c, ~(0x7 << 15), (0x4 << 15));
546 else
547 pcie_update_cfg(dev, 0x4c, ~(0x7 << 15), (0x2 << 15));
548
549 pcie_update_cfg(dev, 0x314, 0x0, 0x743a361b);
550
551 /* Set Common Clock Exit Latency in MPC register. */
552 pcie_update_cfg(dev, 0xd8, ~(0x7 << 15), (0x3 << 15));
553
554 pcie_update_cfg(dev, 0x33c, ~0x00ffffff, 0x854c74);
555
Martin Rothde7ed6f2014-12-07 14:58:18 -0700556 /* Set Invalid Receive Range Check Enable in MPC register. */
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700557 pcie_update_cfg(dev, 0xd8, ~0, (1 << 25));
558
Kane Chen4fef5a22014-08-27 15:21:32 -0700559 pcie_update_cfg8(dev, 0xf5, 0x0f, 0);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700560
Kenji Chen94fea492014-09-30 14:17:35 +0800561 /* Set AER Extended Cap ID to 01h and Next Cap Pointer to 200h. */
Kenji Chen8ef55ee2014-09-25 21:34:42 +0800562 pcie_update_cfg(dev, 0x100, ~(1 << 29) & ~0xfffff, (1 << 29) | 0x10001);
563
Kenji Chen94fea492014-09-30 14:17:35 +0800564 /* Set L1 Sub-State Cap ID to 1Eh and Next Cap Pointer to None. */
565 pcie_update_cfg(dev, 0x200, ~0xffff, 0x001e);
566
Kenji Chenc373f502014-09-26 02:48:16 +0800567 pcie_update_cfg(dev, 0x320, ~(3 << 20) & ~(7 << 6),
568 (1 << 20) | (3 << 6));
569 /* Enable Relaxed Order from Root Port. */
570 pcie_update_cfg(dev, 0x320, ~(3 << 23), (3 << 23));
571
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700572 if (rp == 1 || rp == 5 || rp == 6)
573 pcie_update_cfg8(dev, 0xf7, ~0xc, 0);
574
575 /* Set EOI forwarding disable. */
576 pcie_update_cfg(dev, 0xd4, ~0, (1 << 1));
577
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700578 /* Read and write back write-once capability registers. */
579 pcie_update_cfg(dev, 0x34, ~0, 0);
580 pcie_update_cfg(dev, 0x40, ~0, 0);
581 pcie_update_cfg(dev, 0x80, ~0, 0);
582 pcie_update_cfg(dev, 0x90, ~0, 0);
583}
584
585static void pch_pcie_init(struct device *dev)
586{
587 u16 reg16;
588 u32 reg32;
589
590 printk(BIOS_DEBUG, "Initializing PCH PCIe bridge.\n");
591
592 /* Enable SERR */
593 reg32 = pci_read_config32(dev, PCI_COMMAND);
594 reg32 |= PCI_COMMAND_SERR;
595 pci_write_config32(dev, PCI_COMMAND, reg32);
596
597 /* Enable Bus Master */
598 reg32 = pci_read_config32(dev, PCI_COMMAND);
599 reg32 |= PCI_COMMAND_MASTER;
600 pci_write_config32(dev, PCI_COMMAND, reg32);
601
602 /* Set Cache Line Size to 0x10 */
603 pci_write_config8(dev, 0x0c, 0x10);
604
605 reg16 = pci_read_config16(dev, 0x3e);
606 reg16 &= ~(1 << 0); /* disable parity error response */
607 reg16 |= (1 << 2); /* ISA enable */
608 pci_write_config16(dev, 0x3e, reg16);
609
610#ifdef EVEN_MORE_DEBUG
611 reg32 = pci_read_config32(dev, 0x20);
612 printk(BIOS_SPEW, " MBL = 0x%08x\n", reg32);
613 reg32 = pci_read_config32(dev, 0x24);
614 printk(BIOS_SPEW, " PMBL = 0x%08x\n", reg32);
615 reg32 = pci_read_config32(dev, 0x28);
616 printk(BIOS_SPEW, " PMBU32 = 0x%08x\n", reg32);
617 reg32 = pci_read_config32(dev, 0x2c);
618 printk(BIOS_SPEW, " PMLU32 = 0x%08x\n", reg32);
619#endif
620
621 /* Clear errors in status registers */
622 reg16 = pci_read_config16(dev, 0x06);
623 pci_write_config16(dev, 0x06, reg16);
624 reg16 = pci_read_config16(dev, 0x1e);
625 pci_write_config16(dev, 0x1e, reg16);
626}
627
628static void pch_pcie_enable(device_t dev)
629{
630 /* Add this device to the root port config structure. */
631 root_port_init_config(dev);
632
633 /* Check to see if this Root Port should be disabled. */
634 root_port_check_disable(dev);
635
636 /* Power Management init before enumeration */
637 if (dev->enabled)
638 pch_pcie_early(dev);
639
640 /*
641 * When processing the last PCIe root port we can now
642 * update the Root Port Function Number and Hide register.
643 */
644 if (root_port_is_last(dev))
645 root_port_commit_config();
646}
647
648static void pcie_set_subsystem(device_t dev, unsigned vendor, unsigned device)
649{
650 /* NOTE: This is not the default position! */
651 if (!vendor || !device)
652 pci_write_config32(dev, 0x94, pci_read_config32(dev, 0));
653 else
654 pci_write_config32(dev, 0x94, (device << 16) | vendor);
655}
656
Kenji Chenb71d9b82014-10-10 03:08:15 +0800657static void pcie_set_L1_ss_max_latency(device_t dev, unsigned int off)
658{
659 /* Set max snoop and non-snoop latency for Broadwell */
660 pci_mmio_write_config32(dev, off, 0x10031003);
661}
662
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700663static struct pci_operations pcie_ops = {
664 .set_subsystem = pcie_set_subsystem,
Kenji Chenb71d9b82014-10-10 03:08:15 +0800665 .set_L1_ss_latency = pcie_set_L1_ss_max_latency,
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700666};
667
668static struct device_operations device_ops = {
669 .read_resources = pci_bus_read_resources,
670 .set_resources = pci_dev_set_resources,
671 .enable_resources = pci_bus_enable_resources,
672 .init = pch_pcie_init,
673 .enable = pch_pcie_enable,
674 .scan_bus = pciexp_scan_bridge,
675 .ops_pci = &pcie_ops,
676};
677
678static const unsigned short pcie_device_ids[] = {
679 /* Lynxpoint-LP */
680 0x9c10, 0x9c12, 0x9c14, 0x9c16, 0x9c18, 0x9c1a,
681 /* WildcatPoint */
682 0x9c90, 0x9c92, 0x9c94, 0x9c96, 0x9c98, 0x9c9a, 0x2448,
683 0
684};
685
686static const struct pci_driver pch_pcie __pci_driver = {
687 .ops = &device_ops,
688 .vendor = PCI_VENDOR_ID_INTEL,
689 .devices = pcie_device_ids,
690};