blob: de23f3eb64d36fdc56ec74f8847ebe8a2b4d041a [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>
27#include <broadwell/gpio.h>
28#include <broadwell/lpc.h>
29#include <broadwell/iobp.h>
30#include <broadwell/pch.h>
31#include <broadwell/pci_devs.h>
32#include <broadwell/rcba.h>
33#include <chip.h>
Kane Chen4fef5a22014-08-27 15:21:32 -070034#include <broadwell/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;
126
127 if (root_port_is_first(dev)) {
128 rpc.orig_rpfn = RCBA32(RPFN);
129 rpc.new_rpfn = rpc.orig_rpfn;
130 rpc.num_ports = NUM_ROOT_PORTS;
131 rpc.gbe_port = -1;
Kenji Chen87d4a202014-09-24 01:18:26 +0800132 /* RP0 f5[3:0] = 0101b*/
133 pcie_update_cfg8(dev, 0xf5, ~0xa, 0x5);
134
135 pcie_iosf_port_grant_count(dev);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700136
137 rpc.pin_ownership = pci_read_config32(dev, 0x410);
138 root_port_config_update_gbe_port();
139
Kane Chen642e5982014-09-09 15:53:09 -0700140 pcie_update_cfg8(dev, 0xe2, ~(3 << 4), (3 << 4));
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700141 if (dev->chip_info != NULL) {
142 config_t *config = dev->chip_info;
143 rpc.coalesce = config->pcie_port_coalesce;
144 }
145 }
146
147 rp = root_port_number(dev);
148 if (rp > rpc.num_ports) {
149 printk(BIOS_ERR, "Found Root Port %d, expecting %d\n",
150 rp, rpc.num_ports);
151 return;
152 }
153
154 /* Read the fuse configuration and pin ownership. */
155 switch (rp) {
156 case 1:
157 rpc.strpfusecfg1 = pci_read_config32(dev, 0xfc);
158 rpc.b0d28f0_32c = pci_read_config32(dev, 0x32c);
159 break;
160 case 5:
161 rpc.strpfusecfg2 = pci_read_config32(dev, 0xfc);
162 rpc.b0d28f4_32c = pci_read_config32(dev, 0x32c);
163 break;
164 case 6:
165 rpc.b0d28f5_32c = pci_read_config32(dev, 0x32c);
166 rpc.strpfusecfg3 = pci_read_config32(dev, 0xfc);
167 break;
168 default:
169 break;
170 }
171
Kane Chen46134722014-08-28 17:05:06 -0700172 pcie_update_cfg(dev, 0x418, 0, 0x02000430);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700173 /* Cache pci device. */
174 rpc.ports[rp - 1] = dev;
175}
176
177/* Update devicetree with new Root Port function number assignment */
178static void pch_pcie_device_set_func(int index, int pci_func)
179{
180 device_t dev;
181 unsigned new_devfn;
182
183 dev = rpc.ports[index];
184
185 /* Set the new PCI function field for this Root Port. */
186 rpc.new_rpfn &= ~RPFN_FNMASK(index);
187 rpc.new_rpfn |= RPFN_FNSET(index, pci_func);
188
189 /* Determine the new devfn for this port */
190 new_devfn = PCI_DEVFN(PCH_DEV_SLOT_PCIE, pci_func);
191
192 if (dev->path.pci.devfn != new_devfn) {
193 printk(BIOS_DEBUG,
194 "PCH: PCIe map %02x.%1x -> %02x.%1x\n",
195 PCI_SLOT(dev->path.pci.devfn),
196 PCI_FUNC(dev->path.pci.devfn),
197 PCI_SLOT(new_devfn), PCI_FUNC(new_devfn));
198
199 dev->path.pci.devfn = new_devfn;
200 }
201}
202
203static void pcie_enable_clock_gating(void)
204{
205 int i;
206 int enabled_ports = 0;
Kane Chen4fef5a22014-08-27 15:21:32 -0700207 int is_broadwell = !!(cpu_family_model() == BROADWELL_FAMILY_ULT);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700208
209 for (i = 0; i < rpc.num_ports; i++) {
210 device_t dev;
211 int rp;
212
213 dev = rpc.ports[i];
214 rp = root_port_number(dev);
215
216 if (!dev->enabled) {
217 /* Configure shared resource clock gating. */
218 if (rp == 1 || rp == 5 || rp == 6)
219 pcie_update_cfg8(dev, 0xe1, 0xc3, 0x3c);
220
221 pcie_update_cfg8(dev, 0xe2, ~(3 << 4), (3 << 4));
222 pcie_update_cfg(dev, 0x420, ~(1 << 31), (1 << 31));
223
224 /* Per-Port CLKREQ# handling. */
225 if (gpio_is_native(18 + rp - 1))
226 pcie_update_cfg(dev, 0x420, ~0, (3 << 29));
227
228 /* Enable static clock gating. */
229 if (rp == 1 && !rpc.ports[1]->enabled &&
230 !rpc.ports[2]->enabled && !rpc.ports[3]->enabled) {
231 pcie_update_cfg8(dev, 0xe2, ~1, 1);
232 pcie_update_cfg8(dev, 0xe1, 0x7f, 0x80);
233 } else if (rp == 5 || rp == 6) {
234 pcie_update_cfg8(dev, 0xe2, ~1, 1);
235 pcie_update_cfg8(dev, 0xe1, 0x7f, 0x80);
236 }
237 continue;
238 }
239
240 enabled_ports++;
241
242 /* Enable dynamic clock gating. */
243 pcie_update_cfg8(dev, 0xe1, 0xfc, 0x03);
244 pcie_update_cfg8(dev, 0xe2, ~(1 << 6), (1 << 6));
245 pcie_update_cfg8(dev, 0xe8, ~(3 << 2), (2 << 2));
246
247 /* Update PECR1 register. */
Kane Chen4fef5a22014-08-27 15:21:32 -0700248 pcie_update_cfg8(dev, 0xe8, ~0, 3);
249 if (is_broadwell) {
250 pcie_update_cfg(dev, 0x324, ~((1 << 5) | (1 << 14)),
251 ((1 << 5) | (1 << 14)));
252 } else {
253 pcie_update_cfg(dev, 0x324, ~(1 << 5), (1 << 5));
254 }
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700255 /* Per-Port CLKREQ# handling. */
256 if (gpio_is_native(18 + rp - 1))
257 pcie_update_cfg(dev, 0x420, ~0, (3 << 29));
258
259 /* Configure shared resource clock gating. */
260 if (rp == 1 || rp == 5 || rp == 6)
261 pcie_update_cfg8(dev, 0xe1, 0xc3, 0x3c);
Duncan Laurie446fb8e2014-08-08 09:59:43 -0700262
263 /* CLKREQ# VR Idle Enable */
264 RCBA32_OR(0x2b1c, (1 << (16 + i)));
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700265 }
266
267 if (!enabled_ports)
268 pcie_update_cfg8(rpc.ports[0], 0xe1, ~(1 << 6), (1 << 6));
269}
270
271static void root_port_commit_config(void)
272{
273 int i;
274
275 /* If the first root port is disabled the coalesce ports. */
276 if (!rpc.ports[0]->enabled)
277 rpc.coalesce = 1;
278
279 /* Perform clock gating configuration. */
280 pcie_enable_clock_gating();
281
282 for (i = 0; i < rpc.num_ports; i++) {
283 device_t dev;
284 u32 reg32;
285
286 dev = rpc.ports[i];
287
288 if (dev == NULL) {
289 printk(BIOS_ERR, "Root Port %d device is NULL?\n", i+1);
290 continue;
291 }
292
293 if (dev->enabled)
294 continue;
295
296 printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
297
298 /* Ensure memory, io, and bus master are all disabled */
299 reg32 = pci_read_config32(dev, PCI_COMMAND);
300 reg32 &= ~(PCI_COMMAND_MASTER |
301 PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
302 pci_write_config32(dev, PCI_COMMAND, reg32);
303
304 /* Disable this device if possible */
305 pch_disable_devfn(dev);
306 }
307
308 if (rpc.coalesce) {
309 int current_func;
310
311 /* For all Root Ports N enabled ports get assigned the lower
312 * PCI function number. The disabled ones get upper PCI
313 * function numbers. */
314 current_func = 0;
315 for (i = 0; i < rpc.num_ports; i++) {
316 if (!rpc.ports[i]->enabled)
317 continue;
318 pch_pcie_device_set_func(i, current_func);
319 current_func++;
320 }
321
322 /* Allocate the disabled devices' PCI function number. */
323 for (i = 0; i < rpc.num_ports; i++) {
324 if (rpc.ports[i]->enabled)
325 continue;
326 pch_pcie_device_set_func(i, current_func);
327 current_func++;
328 }
329 }
330
331 printk(BIOS_SPEW, "PCH: RPFN 0x%08x -> 0x%08x\n",
332 rpc.orig_rpfn, rpc.new_rpfn);
333 RCBA32(RPFN) = rpc.new_rpfn;
334}
335
336static void root_port_mark_disable(device_t dev)
337{
338 /* Mark device as disabled. */
339 dev->enabled = 0;
340 /* Mark device to be hidden. */
341 rpc.new_rpfn |= RPFN_HIDE(PCI_FUNC(dev->path.pci.devfn));
342}
343
344static void root_port_check_disable(device_t dev)
345{
346 int rp;
347
348 /* Device already disabled. */
349 if (!dev->enabled) {
350 root_port_mark_disable(dev);
351 return;
352 }
353
354 rp = root_port_number(dev);
355
356 /* Is the GbE port mapped to this Root Port? */
357 if (rp == rpc.gbe_port) {
358 root_port_mark_disable(dev);
359 return;
360 }
361
362 /* Check Root Port Configuration. */
363 switch (rp) {
364 case 2:
365 /* Root Port 2 is disabled for all lane configurations
366 * but config 00b (4x1 links). */
367 if ((rpc.strpfusecfg1 >> 14) & 0x3) {
368 root_port_mark_disable(dev);
369 return;
370 }
371 break;
372 case 3:
373 /* Root Port 3 is disabled in config 11b (1x4 links). */
374 if (((rpc.strpfusecfg1 >> 14) & 0x3) == 0x3) {
375 root_port_mark_disable(dev);
376 return;
377 }
378 break;
379 case 4:
380 /* Root Port 4 is disabled in configs 11b (1x4 links)
381 * and 10b (2x2 links). */
382 if ((rpc.strpfusecfg1 >> 14) & 0x2) {
383 root_port_mark_disable(dev);
384 return;
385 }
386 break;
387 }
388
389 /* Check Pin Ownership. */
390 switch (rp) {
391 case 1:
392 /* Bit 0 is Root Port 1 ownership. */
393 if ((rpc.pin_ownership & 0x1) == 0) {
394 root_port_mark_disable(dev);
395 return;
396 }
397 break;
398 case 2:
399 /* Bit 2 is Root Port 2 ownership. */
400 if ((rpc.pin_ownership & 0x4) == 0) {
401 root_port_mark_disable(dev);
402 return;
403 }
404 break;
405 case 6:
406 /* Bits 7:4 are Root Port 6 pin-lane ownership. */
407 if ((rpc.pin_ownership & 0xf0) == 0) {
408 root_port_mark_disable(dev);
409 return;
410 }
411 break;
412 }
413}
414
415static void pcie_update_cfg8(device_t dev, int reg, u8 mask, u8 or)
416{
417 u8 reg8;
418
419 reg8 = pci_read_config8(dev, reg);
420 reg8 &= mask;
421 reg8 |= or;
422 pci_write_config8(dev, reg, reg8);
423}
424
425static void pcie_update_cfg(device_t dev, int reg, u32 mask, u32 or)
426{
427 u32 reg32;
428
429 reg32 = pci_read_config32(dev, reg);
430 reg32 &= mask;
431 reg32 |= or;
432 pci_write_config32(dev, reg, reg32);
433}
434
435static void pcie_add_0x0202000_iobp(u32 reg)
436{
437 u32 reg32;
438
439 reg32 = pch_iobp_read(reg);
440 reg32 += (0x2 << 16) | (0x2 << 8);
441 pch_iobp_write(reg, reg32);
442}
443
444static void pch_pcie_early(struct device *dev)
445{
446 config_t *config = dev->chip_info;
447 int do_aspm = 0;
448 int rp = root_port_number(dev);
449
450 switch (rp) {
451 case 1:
452 case 2:
453 case 3:
454 case 4:
455 /*
Martin Rothde7ed6f2014-12-07 14:58:18 -0700456 * Bits 31:28 of b0d28f0 0x32c register correspond to
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700457 * Root Ports 4:1.
458 */
459 do_aspm = !!(rpc.b0d28f0_32c & (1 << (28 + rp - 1)));
460 break;
461 case 5:
462 /*
Martin Rothde7ed6f2014-12-07 14:58:18 -0700463 * Bit 28 of b0d28f4 0x32c register correspond to
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700464 * Root Ports 4:1.
465 */
466 do_aspm = !!(rpc.b0d28f4_32c & (1 << 28));
467 break;
468 case 6:
469 /*
Martin Rothde7ed6f2014-12-07 14:58:18 -0700470 * Bit 28 of b0d28f5 0x32c register correspond to
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700471 * Root Ports 4:1.
472 */
473 do_aspm = !!(rpc.b0d28f5_32c & (1 << 28));
474 break;
475 }
476
477 /* Allow ASPM to be forced on in devicetree */
478 if (config && (config->pcie_port_force_aspm & (1 << (rp - 1))))
479 do_aspm = 1;
480
481 printk(BIOS_DEBUG, "PCIe Root Port %d ASPM is %sabled\n",
482 rp, do_aspm ? "en" : "dis");
483
484 if (do_aspm) {
485 /* Set ASPM bits in MPC2 register. */
486 pcie_update_cfg(dev, 0xd4, ~(0x3 << 2), (1 << 4) | (0x2 << 2));
487
488 /* Set unique clock exit latency in MPC register. */
489 pcie_update_cfg(dev, 0xd8, ~(0x7 << 18), (0x7 << 18));
490
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700491 switch (rp) {
492 case 1:
493 pcie_add_0x0202000_iobp(0xe9002440);
494 break;
495 case 2:
496 pcie_add_0x0202000_iobp(0xe9002640);
497 break;
498 case 3:
499 pcie_add_0x0202000_iobp(0xe9000840);
500 break;
501 case 4:
502 pcie_add_0x0202000_iobp(0xe9000a40);
503 break;
504 case 5:
505 pcie_add_0x0202000_iobp(0xe9000c40);
506 pcie_add_0x0202000_iobp(0xe9000e40);
507 pcie_add_0x0202000_iobp(0xe9001040);
508 pcie_add_0x0202000_iobp(0xe9001240);
509 break;
510 case 6:
511 /* Update IOBP based on lane ownership. */
512 if (rpc.pin_ownership & (1 << 4))
513 pcie_add_0x0202000_iobp(0xea002040);
514 if (rpc.pin_ownership & (1 << 5))
515 pcie_add_0x0202000_iobp(0xea002240);
516 if (rpc.pin_ownership & (1 << 6))
517 pcie_add_0x0202000_iobp(0xea002440);
518 if (rpc.pin_ownership & (1 << 7))
519 pcie_add_0x0202000_iobp(0xea002640);
520 break;
521 }
522
523 pcie_update_cfg(dev, 0x338, ~(1 << 26), 0);
524 }
525
526 /* Enable LTR in Root Port. */
527 pcie_update_cfg(dev, 0x64, ~(1 << 11), (1 << 11));
528 pcie_update_cfg(dev, 0x68, ~(1 << 10), (1 << 10));
529
530 pcie_update_cfg(dev, 0x318, ~(0xffff << 16), (0x1414 << 16));
531
532 /* Set L1 exit latency in LCAP register. */
533 if (!do_aspm && (pci_read_config8(dev, 0xf5) & 0x1))
534 pcie_update_cfg(dev, 0x4c, ~(0x7 << 15), (0x4 << 15));
535 else
536 pcie_update_cfg(dev, 0x4c, ~(0x7 << 15), (0x2 << 15));
537
538 pcie_update_cfg(dev, 0x314, 0x0, 0x743a361b);
539
540 /* Set Common Clock Exit Latency in MPC register. */
541 pcie_update_cfg(dev, 0xd8, ~(0x7 << 15), (0x3 << 15));
542
543 pcie_update_cfg(dev, 0x33c, ~0x00ffffff, 0x854c74);
544
Martin Rothde7ed6f2014-12-07 14:58:18 -0700545 /* Set Invalid Receive Range Check Enable in MPC register. */
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700546 pcie_update_cfg(dev, 0xd8, ~0, (1 << 25));
547
Kane Chen4fef5a22014-08-27 15:21:32 -0700548 pcie_update_cfg8(dev, 0xf5, 0x0f, 0);
Duncan Lauriec88c54c2014-04-30 16:36:13 -0700549
550 if (rp == 1 || rp == 5 || rp == 6)
551 pcie_update_cfg8(dev, 0xf7, ~0xc, 0);
552
553 /* Set EOI forwarding disable. */
554 pcie_update_cfg(dev, 0xd4, ~0, (1 << 1));
555
556 /* Set something involving advanced error reporting. */
557 pcie_update_cfg(dev, 0x100, ~((1 << 20) - 1), 0x10001);
558 pcie_update_cfg(dev, 0x100, ~0, (1 << 29));
559
560 /* Read and write back write-once capability registers. */
561 pcie_update_cfg(dev, 0x34, ~0, 0);
562 pcie_update_cfg(dev, 0x40, ~0, 0);
563 pcie_update_cfg(dev, 0x80, ~0, 0);
564 pcie_update_cfg(dev, 0x90, ~0, 0);
565}
566
567static void pch_pcie_init(struct device *dev)
568{
569 u16 reg16;
570 u32 reg32;
571
572 printk(BIOS_DEBUG, "Initializing PCH PCIe bridge.\n");
573
574 /* Enable SERR */
575 reg32 = pci_read_config32(dev, PCI_COMMAND);
576 reg32 |= PCI_COMMAND_SERR;
577 pci_write_config32(dev, PCI_COMMAND, reg32);
578
579 /* Enable Bus Master */
580 reg32 = pci_read_config32(dev, PCI_COMMAND);
581 reg32 |= PCI_COMMAND_MASTER;
582 pci_write_config32(dev, PCI_COMMAND, reg32);
583
584 /* Set Cache Line Size to 0x10 */
585 pci_write_config8(dev, 0x0c, 0x10);
586
587 reg16 = pci_read_config16(dev, 0x3e);
588 reg16 &= ~(1 << 0); /* disable parity error response */
589 reg16 |= (1 << 2); /* ISA enable */
590 pci_write_config16(dev, 0x3e, reg16);
591
592#ifdef EVEN_MORE_DEBUG
593 reg32 = pci_read_config32(dev, 0x20);
594 printk(BIOS_SPEW, " MBL = 0x%08x\n", reg32);
595 reg32 = pci_read_config32(dev, 0x24);
596 printk(BIOS_SPEW, " PMBL = 0x%08x\n", reg32);
597 reg32 = pci_read_config32(dev, 0x28);
598 printk(BIOS_SPEW, " PMBU32 = 0x%08x\n", reg32);
599 reg32 = pci_read_config32(dev, 0x2c);
600 printk(BIOS_SPEW, " PMLU32 = 0x%08x\n", reg32);
601#endif
602
603 /* Clear errors in status registers */
604 reg16 = pci_read_config16(dev, 0x06);
605 pci_write_config16(dev, 0x06, reg16);
606 reg16 = pci_read_config16(dev, 0x1e);
607 pci_write_config16(dev, 0x1e, reg16);
608}
609
610static void pch_pcie_enable(device_t dev)
611{
612 /* Add this device to the root port config structure. */
613 root_port_init_config(dev);
614
615 /* Check to see if this Root Port should be disabled. */
616 root_port_check_disable(dev);
617
618 /* Power Management init before enumeration */
619 if (dev->enabled)
620 pch_pcie_early(dev);
621
622 /*
623 * When processing the last PCIe root port we can now
624 * update the Root Port Function Number and Hide register.
625 */
626 if (root_port_is_last(dev))
627 root_port_commit_config();
628}
629
630static void pcie_set_subsystem(device_t dev, unsigned vendor, unsigned device)
631{
632 /* NOTE: This is not the default position! */
633 if (!vendor || !device)
634 pci_write_config32(dev, 0x94, pci_read_config32(dev, 0));
635 else
636 pci_write_config32(dev, 0x94, (device << 16) | vendor);
637}
638
639static struct pci_operations pcie_ops = {
640 .set_subsystem = pcie_set_subsystem,
641};
642
643static struct device_operations device_ops = {
644 .read_resources = pci_bus_read_resources,
645 .set_resources = pci_dev_set_resources,
646 .enable_resources = pci_bus_enable_resources,
647 .init = pch_pcie_init,
648 .enable = pch_pcie_enable,
649 .scan_bus = pciexp_scan_bridge,
650 .ops_pci = &pcie_ops,
651};
652
653static const unsigned short pcie_device_ids[] = {
654 /* Lynxpoint-LP */
655 0x9c10, 0x9c12, 0x9c14, 0x9c16, 0x9c18, 0x9c1a,
656 /* WildcatPoint */
657 0x9c90, 0x9c92, 0x9c94, 0x9c96, 0x9c98, 0x9c9a, 0x2448,
658 0
659};
660
661static const struct pci_driver pch_pcie __pci_driver = {
662 .ops = &device_ops,
663 .vendor = PCI_VENDOR_ID_INTEL,
664 .devices = pcie_device_ids,
665};