blob: 98dfe6170e365f56288c4a797f8b5c4a7abda0b7 [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 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; version 2 of
9 * 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_ids.h>
26#include "pch.h"
27
Aaron Durbinc0254e62013-06-20 01:20:30 -050028/* LynxPoint-LP has 6 root ports while non-LP has 8. */
29#define MAX_NUM_ROOT_PORTS 8
30#define H_NUM_ROOT_PORTS MAX_NUM_ROOT_PORTS
31#define LP_NUM_ROOT_PORTS (MAX_NUM_ROOT_PORTS - 2)
32
33struct root_port_config {
34 /* RPFN is a write-once register so keep a copy until it is written */
35 u32 orig_rpfn;
36 u32 new_rpfn;
37 u32 pin_ownership;
38 u32 strpfusecfg1;
39 u32 strpfusecfg2;
40 u32 strpfusecfg3;
41 int coalesce;
42 int gbe_port;
43 int num_ports;
44 device_t ports[MAX_NUM_ROOT_PORTS];
45};
46
47static struct root_port_config rpc;
48
49static inline int max_root_ports(void)
Aaron Durbin60f82082013-06-19 13:28:04 -050050{
Aaron Durbinc0254e62013-06-20 01:20:30 -050051 if (pch_is_lp())
52 return LP_NUM_ROOT_PORTS;
53 else
54 return H_NUM_ROOT_PORTS;
Aaron Durbin60f82082013-06-19 13:28:04 -050055}
56
Aaron Durbinc0254e62013-06-20 01:20:30 -050057static inline int root_port_is_first(device_t dev)
Aaron Durbin60f82082013-06-19 13:28:04 -050058{
Aaron Durbinc0254e62013-06-20 01:20:30 -050059 return PCI_FUNC(dev->path.pci.devfn) == 0;
60}
Aaron Durbin60f82082013-06-19 13:28:04 -050061
Aaron Durbinc0254e62013-06-20 01:20:30 -050062static inline int root_port_is_last(device_t dev)
63{
64 return PCI_FUNC(dev->path.pci.devfn) == (rpc.num_ports - 1);
65}
Aaron Durbin60f82082013-06-19 13:28:04 -050066
Aaron Durbinc0254e62013-06-20 01:20:30 -050067/* Root ports are numbered 1..N in the documentation. */
68static inline int root_port_number(device_t dev)
69{
70 return PCI_FUNC(dev->path.pci.devfn) + 1;
71}
Aaron Durbin60f82082013-06-19 13:28:04 -050072
Aaron Durbinc0254e62013-06-20 01:20:30 -050073static void root_port_config_update_gbe_port(void)
74{
75 /* Is the Gbe Port enabled? */
76 if (!((rpc.strpfusecfg1 >> 19) & 1))
77 return;
78
79 if (pch_is_lp()) {
80 switch ((rpc.strpfusecfg1 >> 16) & 0x7) {
81 case 0:
82 rpc.gbe_port = 3;
83 break;
84 case 1:
85 rpc.gbe_port = 4;
86 break;
87 case 2:
88 case 3:
89 case 4:
90 case 5:
91 /* Lanes 0-4 of Root Port 5. */
92 rpc.gbe_port = 5;
93 break;
94 default:
95 printk(BIOS_DEBUG, "Invalid GbE Port Selection.\n");
96 }
97 } else {
98 /* Non-LP has 1:1 mapping with root ports. */
99 rpc.gbe_port = ((rpc.strpfusecfg1 >> 16) & 0x7) + 1;
100 }
101}
102
103static void root_port_init_config(device_t dev)
104{
105 int rp;
106
107 if (root_port_is_first(dev)) {
108 rpc.orig_rpfn = RCBA32(RPFN);
109 rpc.new_rpfn = rpc.orig_rpfn;
110 rpc.num_ports = max_root_ports();
111 rpc.gbe_port = -1;
112
113 rpc.pin_ownership = pci_read_config32(dev, 0x410);
114 root_port_config_update_gbe_port();
115
116 if (dev->chip_info != NULL) {
117 struct southbridge_intel_lynxpoint_config *config;
118
119 config = dev->chip_info;
120 rpc.coalesce = config->pcie_port_coalesce;
121 }
122 }
123
124 rp = root_port_number(dev);
125 if (rp > rpc.num_ports) {
126 printk(BIOS_ERR, "Found Root Port %d, expecting %d\n",
127 rp, rpc.num_ports);
128 return;
129 }
130
131 /* Read the fuse configuration and pin ownership. */
132 switch (rp) {
133 case 1:
134 rpc.strpfusecfg1 = pci_read_config32(dev, 0xfc);
135 break;
136 case 5:
137 rpc.strpfusecfg2 = pci_read_config32(dev, 0xfc);
138 break;
139 case 6:
140 rpc.strpfusecfg3 = pci_read_config32(dev, 0xfc);
141 break;
142 default:
143 break;
144 }
145
146 /* Cache pci device. */
147 rpc.ports[rp - 1] = dev;
Aaron Durbin60f82082013-06-19 13:28:04 -0500148}
149
150/* Update devicetree with new Root Port function number assignment */
Aaron Durbinc0254e62013-06-20 01:20:30 -0500151static void pch_pcie_device_set_func(int index, int pci_func)
Aaron Durbin60f82082013-06-19 13:28:04 -0500152{
153 device_t dev;
Aaron Durbinc0254e62013-06-20 01:20:30 -0500154 unsigned new_devfn;
Aaron Durbin60f82082013-06-19 13:28:04 -0500155
Aaron Durbinc0254e62013-06-20 01:20:30 -0500156 dev = rpc.ports[index];
Aaron Durbin60f82082013-06-19 13:28:04 -0500157
Aaron Durbinc0254e62013-06-20 01:20:30 -0500158 /* Set the new PCI function field for this Root Port. */
159 rpc.new_rpfn &= ~RPFN_FNMASK(index);
160 rpc.new_rpfn |= RPFN_FNSET(index, pci_func);
Aaron Durbin60f82082013-06-19 13:28:04 -0500161
Aaron Durbinc0254e62013-06-20 01:20:30 -0500162 /* Determine the new devfn for this port */
163 new_devfn = PCI_DEVFN(PCH_PCIE_DEV_SLOT, pci_func);
Aaron Durbin60f82082013-06-19 13:28:04 -0500164
Aaron Durbinc0254e62013-06-20 01:20:30 -0500165 if (dev->path.pci.devfn != new_devfn) {
166 printk(BIOS_DEBUG,
167 "PCH: PCIe map %02x.%1x -> %02x.%1x\n",
168 PCI_SLOT(dev->path.pci.devfn),
169 PCI_FUNC(dev->path.pci.devfn),
170 PCI_SLOT(new_devfn), PCI_FUNC(new_devfn));
Aaron Durbin60f82082013-06-19 13:28:04 -0500171
Aaron Durbinc0254e62013-06-20 01:20:30 -0500172 dev->path.pci.devfn = new_devfn;
Aaron Durbin60f82082013-06-19 13:28:04 -0500173 }
174}
175
Aaron Durbinc0254e62013-06-20 01:20:30 -0500176static void root_port_commit_config(void)
Aaron Durbin60f82082013-06-19 13:28:04 -0500177{
Aaron Durbinc0254e62013-06-20 01:20:30 -0500178 int i;
Aaron Durbin60f82082013-06-19 13:28:04 -0500179
Aaron Durbinc0254e62013-06-20 01:20:30 -0500180 /* If the first root port is disabled the coalesce ports. */
181 if (!rpc.ports[0]->enabled)
182 rpc.coalesce = 1;
Aaron Durbin60f82082013-06-19 13:28:04 -0500183
Aaron Durbinc0254e62013-06-20 01:20:30 -0500184 for (i = 0; i < rpc.num_ports; i++) {
185 device_t dev;
186 u32 reg32;
Aaron Durbin60f82082013-06-19 13:28:04 -0500187
Aaron Durbinc0254e62013-06-20 01:20:30 -0500188 dev = rpc.ports[i];
Aaron Durbin60f82082013-06-19 13:28:04 -0500189
Aaron Durbinc0254e62013-06-20 01:20:30 -0500190 if (dev == NULL) {
191 printk(BIOS_ERR, "Root Port %d device is NULL?\n", i+1);
192 continue;
Aaron Durbin60f82082013-06-19 13:28:04 -0500193 }
194
Aaron Durbinc0254e62013-06-20 01:20:30 -0500195 if (dev->enabled)
196 continue;
197
198 printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
199
Aaron Durbin60f82082013-06-19 13:28:04 -0500200 /* Ensure memory, io, and bus master are all disabled */
201 reg32 = pci_read_config32(dev, PCI_COMMAND);
202 reg32 &= ~(PCI_COMMAND_MASTER |
203 PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
204 pci_write_config32(dev, PCI_COMMAND, reg32);
205
Aaron Durbin60f82082013-06-19 13:28:04 -0500206 /* Disable this device if possible */
207 pch_disable_devfn(dev);
Aaron Durbin60f82082013-06-19 13:28:04 -0500208 }
209
Aaron Durbinc0254e62013-06-20 01:20:30 -0500210 if (rpc.coalesce) {
211 int current_func;
Aaron Durbin60f82082013-06-19 13:28:04 -0500212
Aaron Durbinc0254e62013-06-20 01:20:30 -0500213 /* For all Root Ports N enabled ports get assigned the lower
214 * PCI function number. The disabled ones get upper PCI
215 * function numbers. */
216 current_func = 0;
217 for (i = 0; i < rpc.num_ports; i++) {
218 if (!rpc.ports[i]->enabled)
219 continue;
220 pch_pcie_device_set_func(i, current_func);
221 current_func++;
222 }
223
224 /* Allocate the disabled devices' PCI function number. */
225 for (i = 0; i < rpc.num_ports; i++) {
226 if (rpc.ports[i]->enabled)
227 continue;
228 pch_pcie_device_set_func(i, current_func);
229 current_func++;
230 }
231 }
232
233 printk(BIOS_SPEW, "PCH: RPFN 0x%08x -> 0x%08x\n",
234 rpc.orig_rpfn, rpc.new_rpfn);
235 RCBA32(RPFN) = rpc.new_rpfn;
236}
237
238static void root_port_mark_disable(device_t dev)
239{
240 /* Mark device as disabled. */
241 dev->enabled = 0;
242 /* Mark device to be hidden. */
243 rpc.new_rpfn |= RPFN_HIDE(PCI_FUNC(dev->path.pci.devfn));
244}
245
246static void root_port_check_disable(device_t dev)
247{
248 int rp;
249 int is_lp;
250
251 /* Device already disabled. */
252 if (!dev->enabled) {
253 root_port_mark_disable(dev);
254 return;
255 }
256
257 rp = root_port_number(dev);
258
259 /* Is the GbE port mapped to this Root Port? */
260 if (rp == rpc.gbe_port) {
261 root_port_mark_disable(dev);
262 return;
263 }
264
265 is_lp = pch_is_lp();
266
267 /* Check Root Port Configuration. */
268 switch (rp) {
269 case 2:
270 /* Root Port 2 is disabled for all lane configurations
271 * but config 00b (4x1 links). */
272 if ((rpc.strpfusecfg1 >> 14) & 0x3) {
273 root_port_mark_disable(dev);
274 return;
275 }
276 break;
277 case 3:
278 /* Root Port 3 is disabled in config 11b (1x4 links). */
279 if (((rpc.strpfusecfg1 >> 14) & 0x3) == 0x3) {
280 root_port_mark_disable(dev);
281 return;
282 }
283 break;
284 case 4:
285 /* Root Port 4 is disabled in configs 11b (1x4 links)
286 * and 10b (2x2 links). */
287 if ((rpc.strpfusecfg1 >> 14) & 0x2) {
288 root_port_mark_disable(dev);
289 return;
290 }
291 break;
292 case 6:
293 if (is_lp)
294 break;
295 /* Root Port 6 is disabled for all lane configurations
296 * but config 00b (4x1 links). */
297 if ((rpc.strpfusecfg2 >> 14) & 0x3) {
298 root_port_mark_disable(dev);
299 return;
300 }
301 break;
302 case 7:
303 if (is_lp)
304 break;
305 /* Root Port 3 is disabled in config 11b (1x4 links). */
306 if (((rpc.strpfusecfg2 >> 14) & 0x3) == 0x3) {
307 root_port_mark_disable(dev);
308 return;
309 }
310 break;
311 case 8:
312 if (is_lp)
313 break;
314 /* Root Port 8 is disabled in configs 11b (1x4 links)
315 * and 10b (2x2 links). */
316 if ((rpc.strpfusecfg2 >> 14) & 0x2) {
317 root_port_mark_disable(dev);
318 return;
319 }
320 break;
321 }
322
323 /* Check Pin Ownership. */
324 if (is_lp) {
325 switch (rp) {
326 case 1:
327 /* Bit 0 is Root Port 1 ownership. */
328 if ((rpc.pin_ownership & 0x1) == 0) {
329 root_port_mark_disable(dev);
330 return;
331 }
332 break;
333 case 2:
334 /* Bit 2 is Root Port 2 ownership. */
335 if ((rpc.pin_ownership & 0x4) == 0) {
336 root_port_mark_disable(dev);
337 return;
338 }
339 break;
340 case 6:
341 /* Bits 7:4 are Root Port 6 pin-lane ownership. */
342 if ((rpc.pin_ownership & 0xf0) == 0) {
343 root_port_mark_disable(dev);
344 return;
345 }
346 break;
347 }
348 } else {
349 switch (rp) {
350 case 1:
351 /* Bits 4 and 0 are Root Port 1 ownership. */
352 if ((rpc.pin_ownership & 0x11) == 0) {
353 root_port_mark_disable(dev);
354 return;
355 }
356 break;
357 case 2:
358 /* Bits 5 and 2 are Root Port 2 ownership. */
359 if ((rpc.pin_ownership & 0x24) == 0) {
360 root_port_mark_disable(dev);
361 return;
362 }
363 break;
364 }
Aaron Durbin60f82082013-06-19 13:28:04 -0500365 }
366}
367
Aaron Durbin76c37002012-10-30 09:03:43 -0500368static void pch_pcie_pm_early(struct device *dev)
369{
370/* RPC has been moved. It is in PCI config space now. */
371#if 0
372 u16 link_width_p0, link_width_p4;
373 u8 slot_power_limit = 10; /* 10W for x1 */
374 u32 reg32;
375 u8 reg8;
376
377 reg32 = RCBA32(RPC);
378
379 /* Port 0-3 link aggregation from PCIEPCS1[1:0] soft strap */
380 switch (reg32 & 3) {
381 case 3:
382 link_width_p0 = 4;
383 break;
384 case 1:
385 case 2:
386 link_width_p0 = 2;
387 break;
388 case 0:
389 default:
390 link_width_p0 = 1;
391 }
392
393 /* Port 4-7 link aggregation from PCIEPCS2[1:0] soft strap */
394 switch ((reg32 >> 2) & 3) {
395 case 3:
396 link_width_p4 = 4;
397 break;
398 case 1:
399 case 2:
400 link_width_p4 = 2;
401 break;
402 case 0:
403 default:
404 link_width_p4 = 1;
405 }
406
407 /* Enable dynamic clock gating where needed */
408 reg8 = pci_read_config8(dev, 0xe1);
409 switch (PCI_FUNC(dev->path.pci.devfn)) {
410 case 0: /* Port 0 */
411 if (link_width_p0 == 4)
412 slot_power_limit = 40; /* 40W for x4 */
413 else if (link_width_p0 == 2)
414 slot_power_limit = 20; /* 20W for x2 */
415 reg8 |= 0x3f;
416 break;
417 case 4: /* Port 4 */
418 if (link_width_p4 == 4)
419 slot_power_limit = 40; /* 40W for x4 */
420 else if (link_width_p4 == 2)
421 slot_power_limit = 20; /* 20W for x2 */
422 reg8 |= 0x3f;
423 break;
424 case 1: /* Port 1 only if Port 0 is x1 */
425 if (link_width_p0 == 1)
426 reg8 |= 0x3;
427 break;
428 case 2: /* Port 2 only if Port 0 is x1 or x2 */
429 case 3: /* Port 3 only if Port 0 is x1 or x2 */
430 if (link_width_p0 <= 2)
431 reg8 |= 0x3;
432 break;
433 case 5: /* Port 5 only if Port 4 is x1 */
434 if (link_width_p4 == 1)
435 reg8 |= 0x3;
436 break;
437 case 6: /* Port 7 only if Port 4 is x1 or x2 */
438 case 7: /* Port 7 only if Port 4 is x1 or x2 */
439 if (link_width_p4 <= 2)
440 reg8 |= 0x3;
441 break;
442 }
443 pci_write_config8(dev, 0xe1, reg8);
444
445 /* Set 0xE8[0] = 1 */
446 reg32 = pci_read_config32(dev, 0xe8);
447 reg32 |= 1;
448 pci_write_config32(dev, 0xe8, reg32);
449
450 /* Adjust Common Clock exit latency */
451 reg32 = pci_read_config32(dev, 0xd8);
452 reg32 &= ~(1 << 17);
453 reg32 |= (1 << 16) | (1 << 15);
454 reg32 &= ~(1 << 31); /* Disable PME# SCI for native PME handling */
455 pci_write_config32(dev, 0xd8, reg32);
456
457 /* Adjust ASPM L1 exit latency */
458 reg32 = pci_read_config32(dev, 0x4c);
459 reg32 &= ~((1 << 17) | (1 << 16) | (1 << 15));
460 if (RCBA32(0x2320) & (1 << 16)) {
461 /* If RCBA+2320[15]=1 set ASPM L1 to 8-16us */
462 reg32 |= (1 << 17);
463 } else {
464 /* Else set ASPM L1 to 2-4us */
465 reg32 |= (1 << 16);
466 }
467 pci_write_config32(dev, 0x4c, reg32);
468
469 /* Set slot power limit as configured above */
470 reg32 = pci_read_config32(dev, 0x54);
471 reg32 &= ~((1 << 15) | (1 << 16)); /* 16:15 = Slot power scale */
472 reg32 &= ~(0xff << 7); /* 14:7 = Slot power limit */
473 reg32 |= (slot_power_limit << 7);
474 pci_write_config32(dev, 0x54, reg32);
475#endif
476}
477
478static void pch_pcie_pm_late(struct device *dev)
479{
480 enum aspm_type apmc;
481 u32 reg32;
482
483 /* Set 0x314 = 0x743a361b */
Kyösti Mälkki386b3e62013-07-26 08:52:49 +0300484 pci_write_config32(dev, 0x314, 0x743a361b);
Aaron Durbin76c37002012-10-30 09:03:43 -0500485
486 /* Set 0x318[31:16] = 0x1414 */
Kyösti Mälkki386b3e62013-07-26 08:52:49 +0300487 reg32 = pci_read_config32(dev, 0x318);
Aaron Durbin76c37002012-10-30 09:03:43 -0500488 reg32 &= 0x0000ffff;
489 reg32 |= 0x14140000;
Kyösti Mälkki386b3e62013-07-26 08:52:49 +0300490 pci_write_config32(dev, 0x318, reg32);
Aaron Durbin76c37002012-10-30 09:03:43 -0500491
492 /* Set 0x324[5] = 1 */
Kyösti Mälkki386b3e62013-07-26 08:52:49 +0300493 reg32 = pci_read_config32(dev, 0x324);
Aaron Durbin76c37002012-10-30 09:03:43 -0500494 reg32 |= (1 << 5);
Kyösti Mälkki386b3e62013-07-26 08:52:49 +0300495 pci_write_config32(dev, 0x324, reg32);
Aaron Durbin76c37002012-10-30 09:03:43 -0500496
497 /* Set 0x330[7:0] = 0x40 */
Kyösti Mälkki386b3e62013-07-26 08:52:49 +0300498 reg32 = pci_read_config32(dev, 0x330);
Aaron Durbin76c37002012-10-30 09:03:43 -0500499 reg32 &= ~(0xff);
500 reg32 |= 0x40;
Kyösti Mälkki386b3e62013-07-26 08:52:49 +0300501 pci_write_config32(dev, 0x330, reg32);
Aaron Durbin76c37002012-10-30 09:03:43 -0500502
503 /* Set 0x33C[24:0] = 0x854c74 */
Kyösti Mälkki386b3e62013-07-26 08:52:49 +0300504 reg32 = pci_read_config32(dev, 0x33c);
Aaron Durbin76c37002012-10-30 09:03:43 -0500505 reg32 &= 0xff000000;
506 reg32 |= 0x00854c74;
Kyösti Mälkki386b3e62013-07-26 08:52:49 +0300507 pci_write_config32(dev, 0x33c, reg32);
Aaron Durbin76c37002012-10-30 09:03:43 -0500508
509 /* No IO-APIC, Disable EOI forwarding */
510 reg32 = pci_read_config32(dev, 0xd4);
511 reg32 |= (1 << 1);
512 pci_write_config32(dev, 0xd4, reg32);
513
514 /* Get configured ASPM state */
515 apmc = pci_read_config32(dev, 0x50) & 3;
516
517 /* If both L0s and L1 enabled then set root port 0xE8[1]=1 */
518 if (apmc == PCIE_ASPM_BOTH) {
519 reg32 = pci_read_config32(dev, 0xe8);
520 reg32 |= (1 << 1);
521 pci_write_config32(dev, 0xe8, reg32);
522 }
523}
524
525static void pci_init(struct device *dev)
526{
527 u16 reg16;
528 u32 reg32;
529
530 printk(BIOS_DEBUG, "Initializing PCH PCIe bridge.\n");
531
Aaron Durbinc0254e62013-06-20 01:20:30 -0500532 /* Enable SERR */
533 reg32 = pci_read_config32(dev, PCI_COMMAND);
534 reg32 |= PCI_COMMAND_SERR;
535 pci_write_config32(dev, PCI_COMMAND, reg32);
536
Aaron Durbin76c37002012-10-30 09:03:43 -0500537 /* Enable Bus Master */
538 reg32 = pci_read_config32(dev, PCI_COMMAND);
539 reg32 |= PCI_COMMAND_MASTER;
540 pci_write_config32(dev, PCI_COMMAND, reg32);
541
542 /* Set Cache Line Size to 0x10 */
543 // This has no effect but the OS might expect it
544 pci_write_config8(dev, 0x0c, 0x10);
545
546 reg16 = pci_read_config16(dev, 0x3e);
547 reg16 &= ~(1 << 0); /* disable parity error response */
548 // reg16 &= ~(1 << 1); /* disable SERR */
549 reg16 |= (1 << 2); /* ISA enable */
550 pci_write_config16(dev, 0x3e, reg16);
551
552#ifdef EVEN_MORE_DEBUG
553 reg32 = pci_read_config32(dev, 0x20);
554 printk(BIOS_SPEW, " MBL = 0x%08x\n", reg32);
555 reg32 = pci_read_config32(dev, 0x24);
556 printk(BIOS_SPEW, " PMBL = 0x%08x\n", reg32);
557 reg32 = pci_read_config32(dev, 0x28);
558 printk(BIOS_SPEW, " PMBU32 = 0x%08x\n", reg32);
559 reg32 = pci_read_config32(dev, 0x2c);
560 printk(BIOS_SPEW, " PMLU32 = 0x%08x\n", reg32);
561#endif
562
563 /* Clear errors in status registers */
564 reg16 = pci_read_config16(dev, 0x06);
565 //reg16 |= 0xf900;
566 pci_write_config16(dev, 0x06, reg16);
567
568 reg16 = pci_read_config16(dev, 0x1e);
569 //reg16 |= 0xf900;
570 pci_write_config16(dev, 0x1e, reg16);
571
572 /* Power Management init after enumeration */
573 pch_pcie_pm_late(dev);
574}
575
576static void pch_pcie_enable(device_t dev)
577{
Aaron Durbinc0254e62013-06-20 01:20:30 -0500578 /* Add this device to the root port config structure. */
579 root_port_init_config(dev);
580
581 /* Check to see if this Root Port should be disabled. */
582 root_port_check_disable(dev);
583
Aaron Durbin76c37002012-10-30 09:03:43 -0500584 /* Power Management init before enumeration */
Aaron Durbinc0254e62013-06-20 01:20:30 -0500585 if (dev->enabled)
586 pch_pcie_pm_early(dev);
587
588 /*
589 * When processing the last PCIe root port we can now
590 * update the Root Port Function Number and Hide register.
591 */
592 if (root_port_is_last(dev))
593 root_port_commit_config();
Aaron Durbin76c37002012-10-30 09:03:43 -0500594}
595
596static void pcie_set_subsystem(device_t dev, unsigned vendor, unsigned device)
597{
598 /* NOTE: This is not the default position! */
599 if (!vendor || !device) {
600 pci_write_config32(dev, 0x94,
601 pci_read_config32(dev, 0));
602 } else {
603 pci_write_config32(dev, 0x94,
604 ((device & 0xffff) << 16) | (vendor & 0xffff));
605 }
606}
607
608static struct pci_operations pci_ops = {
609 .set_subsystem = pcie_set_subsystem,
610};
611
612static struct device_operations device_ops = {
613 .read_resources = pci_bus_read_resources,
614 .set_resources = pci_dev_set_resources,
615 .enable_resources = pci_bus_enable_resources,
616 .init = pci_init,
617 .enable = pch_pcie_enable,
618 .scan_bus = pciexp_scan_bridge,
619 .ops_pci = &pci_ops,
620};
621
Duncan Laurie74c0d052012-12-17 11:31:40 -0800622static const unsigned short pci_device_ids[] = {
623 /* Lynxpoint Mobile */
624 0x8c10, 0x8c12, 0x8c14, 0x8c16, 0x8c18, 0x8c1a, 0x8c1c, 0x8c1e,
625 /* Lynxpoint Low Power */
626 0x9c10, 0x9c12, 0x9c14, 0x9c16, 0x9c18, 0x9c1a,
627 0
628};
Aaron Durbin76c37002012-10-30 09:03:43 -0500629
630static const struct pci_driver pch_pcie __pci_driver = {
631 .ops = &device_ops,
632 .vendor = PCI_VENDOR_ID_INTEL,
633 .devices = pci_device_ids,
634};