blob: 41e8890b30cd2fbc4ced886858a6a3a3e01ae296 [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.
Aaron Durbin76c37002012-10-30 09:03:43 -050015 */
16
17#include <console/console.h>
18#include <device/device.h>
19#include <device/pci.h>
20#include <device/pciexp.h>
21#include <device/pci_ids.h>
22#include "pch.h"
23
Aaron Durbin1c4289d2013-06-21 14:06:11 -050024static void pcie_update_cfg8(device_t dev, int reg, u8 mask, u8 or);
25static void pcie_update_cfg(device_t dev, int reg, u32 mask, u32 or);
26
Aaron Durbinc0254e62013-06-20 01:20:30 -050027/* LynxPoint-LP has 6 root ports while non-LP has 8. */
28#define MAX_NUM_ROOT_PORTS 8
29#define H_NUM_ROOT_PORTS MAX_NUM_ROOT_PORTS
30#define LP_NUM_ROOT_PORTS (MAX_NUM_ROOT_PORTS - 2)
31
32struct root_port_config {
33 /* RPFN is a write-once register so keep a copy until it is written */
34 u32 orig_rpfn;
35 u32 new_rpfn;
36 u32 pin_ownership;
37 u32 strpfusecfg1;
38 u32 strpfusecfg2;
39 u32 strpfusecfg3;
Stefan Reinauerab365af2013-12-03 12:13:26 -080040 u32 b0d28f0_32c;
41 u32 b0d28f4_32c;
42 u32 b0d28f5_32c;
Aaron Durbinc0254e62013-06-20 01:20:30 -050043 int coalesce;
44 int gbe_port;
45 int num_ports;
46 device_t ports[MAX_NUM_ROOT_PORTS];
47};
48
49static struct root_port_config rpc;
50
51static inline int max_root_ports(void)
Aaron Durbin60f82082013-06-19 13:28:04 -050052{
Aaron Durbinc0254e62013-06-20 01:20:30 -050053 if (pch_is_lp())
54 return LP_NUM_ROOT_PORTS;
55 else
56 return H_NUM_ROOT_PORTS;
Aaron Durbin60f82082013-06-19 13:28:04 -050057}
58
Aaron Durbinc0254e62013-06-20 01:20:30 -050059static inline int root_port_is_first(device_t dev)
Aaron Durbin60f82082013-06-19 13:28:04 -050060{
Aaron Durbinc0254e62013-06-20 01:20:30 -050061 return PCI_FUNC(dev->path.pci.devfn) == 0;
62}
Aaron Durbin60f82082013-06-19 13:28:04 -050063
Aaron Durbinc0254e62013-06-20 01:20:30 -050064static inline int root_port_is_last(device_t dev)
65{
66 return PCI_FUNC(dev->path.pci.devfn) == (rpc.num_ports - 1);
67}
Aaron Durbin60f82082013-06-19 13:28:04 -050068
Aaron Durbinc0254e62013-06-20 01:20:30 -050069/* Root ports are numbered 1..N in the documentation. */
70static inline int root_port_number(device_t dev)
71{
72 return PCI_FUNC(dev->path.pci.devfn) + 1;
73}
Aaron Durbin60f82082013-06-19 13:28:04 -050074
Aaron Durbinc0254e62013-06-20 01:20:30 -050075static void root_port_config_update_gbe_port(void)
76{
77 /* Is the Gbe Port enabled? */
78 if (!((rpc.strpfusecfg1 >> 19) & 1))
79 return;
80
81 if (pch_is_lp()) {
82 switch ((rpc.strpfusecfg1 >> 16) & 0x7) {
83 case 0:
84 rpc.gbe_port = 3;
85 break;
86 case 1:
87 rpc.gbe_port = 4;
88 break;
89 case 2:
90 case 3:
91 case 4:
92 case 5:
93 /* Lanes 0-4 of Root Port 5. */
94 rpc.gbe_port = 5;
95 break;
96 default:
97 printk(BIOS_DEBUG, "Invalid GbE Port Selection.\n");
98 }
99 } else {
100 /* Non-LP has 1:1 mapping with root ports. */
101 rpc.gbe_port = ((rpc.strpfusecfg1 >> 16) & 0x7) + 1;
102 }
103}
104
105static void root_port_init_config(device_t dev)
106{
107 int rp;
108
109 if (root_port_is_first(dev)) {
110 rpc.orig_rpfn = RCBA32(RPFN);
111 rpc.new_rpfn = rpc.orig_rpfn;
112 rpc.num_ports = max_root_ports();
113 rpc.gbe_port = -1;
114
115 rpc.pin_ownership = pci_read_config32(dev, 0x410);
116 root_port_config_update_gbe_port();
117
118 if (dev->chip_info != NULL) {
119 struct southbridge_intel_lynxpoint_config *config;
120
121 config = dev->chip_info;
122 rpc.coalesce = config->pcie_port_coalesce;
123 }
124 }
125
126 rp = root_port_number(dev);
127 if (rp > rpc.num_ports) {
128 printk(BIOS_ERR, "Found Root Port %d, expecting %d\n",
129 rp, rpc.num_ports);
130 return;
131 }
132
133 /* Read the fuse configuration and pin ownership. */
134 switch (rp) {
135 case 1:
136 rpc.strpfusecfg1 = pci_read_config32(dev, 0xfc);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800137 rpc.b0d28f0_32c = pci_read_config32(dev, 0x32c);
Aaron Durbinc0254e62013-06-20 01:20:30 -0500138 break;
139 case 5:
140 rpc.strpfusecfg2 = pci_read_config32(dev, 0xfc);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800141 rpc.b0d28f4_32c = pci_read_config32(dev, 0x32c);
Aaron Durbinc0254e62013-06-20 01:20:30 -0500142 break;
143 case 6:
Stefan Reinauerab365af2013-12-03 12:13:26 -0800144 rpc.b0d28f5_32c = pci_read_config32(dev, 0x32c);
Aaron Durbinc0254e62013-06-20 01:20:30 -0500145 rpc.strpfusecfg3 = pci_read_config32(dev, 0xfc);
146 break;
147 default:
148 break;
149 }
150
151 /* Cache pci device. */
152 rpc.ports[rp - 1] = dev;
Aaron Durbin60f82082013-06-19 13:28:04 -0500153}
154
155/* Update devicetree with new Root Port function number assignment */
Aaron Durbinc0254e62013-06-20 01:20:30 -0500156static void pch_pcie_device_set_func(int index, int pci_func)
Aaron Durbin60f82082013-06-19 13:28:04 -0500157{
158 device_t dev;
Aaron Durbinc0254e62013-06-20 01:20:30 -0500159 unsigned new_devfn;
Aaron Durbin60f82082013-06-19 13:28:04 -0500160
Aaron Durbinc0254e62013-06-20 01:20:30 -0500161 dev = rpc.ports[index];
Aaron Durbin60f82082013-06-19 13:28:04 -0500162
Aaron Durbinc0254e62013-06-20 01:20:30 -0500163 /* Set the new PCI function field for this Root Port. */
164 rpc.new_rpfn &= ~RPFN_FNMASK(index);
165 rpc.new_rpfn |= RPFN_FNSET(index, pci_func);
Aaron Durbin60f82082013-06-19 13:28:04 -0500166
Aaron Durbinc0254e62013-06-20 01:20:30 -0500167 /* Determine the new devfn for this port */
168 new_devfn = PCI_DEVFN(PCH_PCIE_DEV_SLOT, pci_func);
Aaron Durbin60f82082013-06-19 13:28:04 -0500169
Aaron Durbinc0254e62013-06-20 01:20:30 -0500170 if (dev->path.pci.devfn != new_devfn) {
171 printk(BIOS_DEBUG,
172 "PCH: PCIe map %02x.%1x -> %02x.%1x\n",
173 PCI_SLOT(dev->path.pci.devfn),
174 PCI_FUNC(dev->path.pci.devfn),
175 PCI_SLOT(new_devfn), PCI_FUNC(new_devfn));
Aaron Durbin60f82082013-06-19 13:28:04 -0500176
Aaron Durbinc0254e62013-06-20 01:20:30 -0500177 dev->path.pci.devfn = new_devfn;
Aaron Durbin60f82082013-06-19 13:28:04 -0500178 }
179}
180
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500181static void pcie_enable_clock_gating(void)
182{
183 int i;
184 int is_lp;
185 int enabled_ports;
186
187 is_lp = pch_is_lp();
188 enabled_ports = 0;
189
190 for (i = 0; i < rpc.num_ports; i++) {
191 device_t dev;
192 int rp;
193
194 dev = rpc.ports[i];
195 rp = root_port_number(dev);
196
197 if (!dev->enabled) {
198 /* Configure shared resource clock gating. */
199 if (rp == 1 || rp == 5 || (rp == 6 && is_lp))
200 pcie_update_cfg8(dev, 0xe1, 0xc3, 0x3c);
201
202 if (!is_lp) {
203 if (rp == 1 && !rpc.ports[1]->enabled &&
204 !rpc.ports[2]->enabled &&
205 !rpc.ports[3]->enabled) {
206 pcie_update_cfg8(dev, 0xe2, ~1, 1);
207 pcie_update_cfg8(dev, 0xe1, 0x7f, 0x80);
208 }
209 if (rp == 5 && !rpc.ports[5]->enabled &&
210 !rpc.ports[6]->enabled &&
211 !rpc.ports[7]->enabled) {
212 pcie_update_cfg8(dev, 0xe2, ~1, 1);
213 pcie_update_cfg8(dev, 0xe1, 0x7f, 0x80);
214 }
215 continue;
216 }
217
218 pcie_update_cfg8(dev, 0xe2, ~(3 << 4), (3 << 4));
219 pcie_update_cfg(dev, 0x420, ~(1 << 31), (1 << 31));
220
221 /* Per-Port CLKREQ# handling. */
222 if (is_lp && gpio_is_native(18 + rp - 1))
223 pcie_update_cfg(dev, 0x420, ~0, (3 << 29));
224
225 /* Enable static clock gating. */
226 if (rp == 1 && !rpc.ports[1]->enabled &&
227 !rpc.ports[2]->enabled && !rpc.ports[3]->enabled) {
228 pcie_update_cfg8(dev, 0xe2, ~1, 1);
229 pcie_update_cfg8(dev, 0xe1, 0x7f, 0x80);
230 } else if (rp == 5 || rp == 6) {
231 pcie_update_cfg8(dev, 0xe2, ~1, 1);
232 pcie_update_cfg8(dev, 0xe1, 0x7f, 0x80);
233 }
234 continue;
235 }
236
237 enabled_ports++;
238
239 /* Enable dynamic clock gating. */
240 pcie_update_cfg8(dev, 0xe1, 0xfc, 0x03);
241
242 if (is_lp) {
243 pcie_update_cfg8(dev, 0xe2, ~(1 << 6), (1 << 6));
244 pcie_update_cfg8(dev, 0xe8, ~(3 << 2), (2 << 2));
245 }
246
247 /* Update PECR1 register. */
248 pcie_update_cfg8(dev, 0xe8, ~0, 1);
249
250 pcie_update_cfg8(dev, 0x324, ~(1 << 5), (1 < 5));
251
252 /* Per-Port CLKREQ# handling. */
253 if (is_lp && gpio_is_native(18 + rp - 1))
254 pcie_update_cfg(dev, 0x420, ~0, (3 << 29));
255
256 /* Configure shared resource clock gating. */
257 if (rp == 1 || rp == 5 || (rp == 6 && is_lp))
258 pcie_update_cfg8(dev, 0xe1, 0xc3, 0x3c);
259 }
260
261 if (!enabled_ports && is_lp)
262 pcie_update_cfg8(rpc.ports[0], 0xe1, ~(1 << 6), (1 << 6));
263}
264
Aaron Durbinc0254e62013-06-20 01:20:30 -0500265static void root_port_commit_config(void)
Aaron Durbin60f82082013-06-19 13:28:04 -0500266{
Aaron Durbinc0254e62013-06-20 01:20:30 -0500267 int i;
Aaron Durbin60f82082013-06-19 13:28:04 -0500268
Aaron Durbinc0254e62013-06-20 01:20:30 -0500269 /* If the first root port is disabled the coalesce ports. */
270 if (!rpc.ports[0]->enabled)
271 rpc.coalesce = 1;
Aaron Durbin60f82082013-06-19 13:28:04 -0500272
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500273 /* Perform clock gating configuration. */
274 pcie_enable_clock_gating();
275
Aaron Durbinc0254e62013-06-20 01:20:30 -0500276 for (i = 0; i < rpc.num_ports; i++) {
277 device_t dev;
278 u32 reg32;
Aaron Durbin60f82082013-06-19 13:28:04 -0500279
Aaron Durbinc0254e62013-06-20 01:20:30 -0500280 dev = rpc.ports[i];
Aaron Durbin60f82082013-06-19 13:28:04 -0500281
Aaron Durbinc0254e62013-06-20 01:20:30 -0500282 if (dev == NULL) {
283 printk(BIOS_ERR, "Root Port %d device is NULL?\n", i+1);
284 continue;
Aaron Durbin60f82082013-06-19 13:28:04 -0500285 }
286
Aaron Durbinc0254e62013-06-20 01:20:30 -0500287 if (dev->enabled)
288 continue;
289
290 printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
291
Aaron Durbin60f82082013-06-19 13:28:04 -0500292 /* Ensure memory, io, and bus master are all disabled */
293 reg32 = pci_read_config32(dev, PCI_COMMAND);
294 reg32 &= ~(PCI_COMMAND_MASTER |
295 PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
296 pci_write_config32(dev, PCI_COMMAND, reg32);
297
Aaron Durbin60f82082013-06-19 13:28:04 -0500298 /* Disable this device if possible */
299 pch_disable_devfn(dev);
Aaron Durbin60f82082013-06-19 13:28:04 -0500300 }
301
Aaron Durbinc0254e62013-06-20 01:20:30 -0500302 if (rpc.coalesce) {
303 int current_func;
Aaron Durbin60f82082013-06-19 13:28:04 -0500304
Aaron Durbinc0254e62013-06-20 01:20:30 -0500305 /* For all Root Ports N enabled ports get assigned the lower
306 * PCI function number. The disabled ones get upper PCI
307 * function numbers. */
308 current_func = 0;
309 for (i = 0; i < rpc.num_ports; i++) {
310 if (!rpc.ports[i]->enabled)
311 continue;
312 pch_pcie_device_set_func(i, current_func);
313 current_func++;
314 }
315
316 /* Allocate the disabled devices' PCI function number. */
317 for (i = 0; i < rpc.num_ports; i++) {
318 if (rpc.ports[i]->enabled)
319 continue;
320 pch_pcie_device_set_func(i, current_func);
321 current_func++;
322 }
323 }
324
325 printk(BIOS_SPEW, "PCH: RPFN 0x%08x -> 0x%08x\n",
326 rpc.orig_rpfn, rpc.new_rpfn);
327 RCBA32(RPFN) = rpc.new_rpfn;
328}
329
330static void root_port_mark_disable(device_t dev)
331{
332 /* Mark device as disabled. */
333 dev->enabled = 0;
334 /* Mark device to be hidden. */
335 rpc.new_rpfn |= RPFN_HIDE(PCI_FUNC(dev->path.pci.devfn));
336}
337
338static void root_port_check_disable(device_t dev)
339{
340 int rp;
341 int is_lp;
342
343 /* Device already disabled. */
344 if (!dev->enabled) {
345 root_port_mark_disable(dev);
346 return;
347 }
348
349 rp = root_port_number(dev);
350
351 /* Is the GbE port mapped to this Root Port? */
352 if (rp == rpc.gbe_port) {
353 root_port_mark_disable(dev);
354 return;
355 }
356
357 is_lp = pch_is_lp();
358
359 /* Check Root Port Configuration. */
360 switch (rp) {
361 case 2:
362 /* Root Port 2 is disabled for all lane configurations
363 * but config 00b (4x1 links). */
364 if ((rpc.strpfusecfg1 >> 14) & 0x3) {
365 root_port_mark_disable(dev);
366 return;
367 }
368 break;
369 case 3:
370 /* Root Port 3 is disabled in config 11b (1x4 links). */
371 if (((rpc.strpfusecfg1 >> 14) & 0x3) == 0x3) {
372 root_port_mark_disable(dev);
373 return;
374 }
375 break;
376 case 4:
377 /* Root Port 4 is disabled in configs 11b (1x4 links)
378 * and 10b (2x2 links). */
379 if ((rpc.strpfusecfg1 >> 14) & 0x2) {
380 root_port_mark_disable(dev);
381 return;
382 }
383 break;
384 case 6:
385 if (is_lp)
386 break;
387 /* Root Port 6 is disabled for all lane configurations
388 * but config 00b (4x1 links). */
389 if ((rpc.strpfusecfg2 >> 14) & 0x3) {
390 root_port_mark_disable(dev);
391 return;
392 }
393 break;
394 case 7:
395 if (is_lp)
396 break;
397 /* Root Port 3 is disabled in config 11b (1x4 links). */
398 if (((rpc.strpfusecfg2 >> 14) & 0x3) == 0x3) {
399 root_port_mark_disable(dev);
400 return;
401 }
402 break;
403 case 8:
404 if (is_lp)
405 break;
406 /* Root Port 8 is disabled in configs 11b (1x4 links)
407 * and 10b (2x2 links). */
408 if ((rpc.strpfusecfg2 >> 14) & 0x2) {
409 root_port_mark_disable(dev);
410 return;
411 }
412 break;
413 }
414
415 /* Check Pin Ownership. */
416 if (is_lp) {
417 switch (rp) {
418 case 1:
419 /* Bit 0 is Root Port 1 ownership. */
420 if ((rpc.pin_ownership & 0x1) == 0) {
421 root_port_mark_disable(dev);
422 return;
423 }
424 break;
425 case 2:
426 /* Bit 2 is Root Port 2 ownership. */
427 if ((rpc.pin_ownership & 0x4) == 0) {
428 root_port_mark_disable(dev);
429 return;
430 }
431 break;
432 case 6:
433 /* Bits 7:4 are Root Port 6 pin-lane ownership. */
434 if ((rpc.pin_ownership & 0xf0) == 0) {
435 root_port_mark_disable(dev);
436 return;
437 }
438 break;
439 }
440 } else {
441 switch (rp) {
442 case 1:
443 /* Bits 4 and 0 are Root Port 1 ownership. */
444 if ((rpc.pin_ownership & 0x11) == 0) {
445 root_port_mark_disable(dev);
446 return;
447 }
448 break;
449 case 2:
450 /* Bits 5 and 2 are Root Port 2 ownership. */
451 if ((rpc.pin_ownership & 0x24) == 0) {
452 root_port_mark_disable(dev);
453 return;
454 }
455 break;
456 }
Aaron Durbin60f82082013-06-19 13:28:04 -0500457 }
458}
459
Stefan Reinauerab365af2013-12-03 12:13:26 -0800460static void pcie_update_cfg8(device_t dev, int reg, u8 mask, u8 or)
Aaron Durbin76c37002012-10-30 09:03:43 -0500461{
Aaron Durbin76c37002012-10-30 09:03:43 -0500462 u8 reg8;
463
Stefan Reinauerab365af2013-12-03 12:13:26 -0800464 reg8 = pci_read_config8(dev, reg);
465 reg8 &= mask;
466 reg8 |= or;
467 pci_write_config8(dev, reg, reg8);
Aaron Durbin76c37002012-10-30 09:03:43 -0500468}
469
Stefan Reinauerab365af2013-12-03 12:13:26 -0800470static void pcie_update_cfg(device_t dev, int reg, u32 mask, u32 or)
Aaron Durbin76c37002012-10-30 09:03:43 -0500471{
Aaron Durbin76c37002012-10-30 09:03:43 -0500472 u32 reg32;
473
Stefan Reinauerab365af2013-12-03 12:13:26 -0800474 reg32 = pci_read_config32(dev, reg);
475 reg32 &= mask;
476 reg32 |= or;
477 pci_write_config32(dev, reg, reg32);
478}
Aaron Durbin76c37002012-10-30 09:03:43 -0500479
Stefan Reinauerab365af2013-12-03 12:13:26 -0800480static void pcie_add_0x0202000_iobp(u32 reg)
481{
482 u32 reg32;
Aaron Durbin76c37002012-10-30 09:03:43 -0500483
Stefan Reinauerab365af2013-12-03 12:13:26 -0800484 reg32 = pch_iobp_read(reg);
485 reg32 += (0x2 << 16) | (0x2 << 8);
486 pch_iobp_write(reg, reg32);
487}
Aaron Durbin76c37002012-10-30 09:03:43 -0500488
Stefan Reinauerab365af2013-12-03 12:13:26 -0800489static void pch_pcie_early(struct device *dev)
490{
491 int rp;
492 int do_aspm;
493 int is_lp;
Duncan Laurie249a03b2013-08-09 09:06:41 -0700494 struct southbridge_intel_lynxpoint_config *config = dev->chip_info;
Aaron Durbin76c37002012-10-30 09:03:43 -0500495
Stefan Reinauerab365af2013-12-03 12:13:26 -0800496 rp = root_port_number(dev);
497 do_aspm = 0;
498 is_lp = pch_is_lp();
Aaron Durbin76c37002012-10-30 09:03:43 -0500499
Stefan Reinauerab365af2013-12-03 12:13:26 -0800500 if (is_lp) {
501 switch (rp) {
502 case 1:
503 case 2:
504 case 3:
505 case 4:
506 /* Bits 31:28 of b0d28f0 0x32c register correspnd to
507 * Root Ports 4:1. */
508 do_aspm = !!(rpc.b0d28f0_32c & (1 << (28 + rp - 1)));
509 break;
510 case 5:
511 /* Bit 28 of b0d28f4 0x32c register correspnd to
512 * Root Ports 4:1. */
513 do_aspm = !!(rpc.b0d28f4_32c & (1 << 28));
514 break;
515 case 6:
516 /* Bit 28 of b0d28f5 0x32c register correspnd to
517 * Root Ports 4:1. */
518 do_aspm = !!(rpc.b0d28f5_32c & (1 << 28));
519 break;
520 }
521 } else {
522 switch (rp) {
523 case 1:
524 case 2:
525 case 3:
526 case 4:
527 /* Bits 31:28 of b0d28f0 0x32c register correspnd to
528 * Root Ports 4:1. */
529 do_aspm = !!(rpc.b0d28f0_32c & (1 << (28 + rp - 1)));
530 break;
531 case 5:
532 case 6:
533 case 7:
534 case 8:
535 /* Bit 31:28 of b0d28f4 0x32c register correspnd to
536 * Root Ports 8:5. */
537 do_aspm = !!(rpc.b0d28f4_32c & (1 << (28 + rp - 5)));
538 break;
539 }
Aaron Durbin76c37002012-10-30 09:03:43 -0500540 }
Stefan Reinauerab365af2013-12-03 12:13:26 -0800541
Duncan Laurie249a03b2013-08-09 09:06:41 -0700542 /* Allow ASPM to be forced on in devicetree */
543 if (config && (config->pcie_port_force_aspm & (1 << (rp - 1))))
544 do_aspm = 1;
545
546 printk(BIOS_DEBUG, "PCIe Root Port %d ASPM is %sabled\n",
547 rp, do_aspm ? "en" : "dis");
548
Stefan Reinauerab365af2013-12-03 12:13:26 -0800549 if (do_aspm) {
550 /* Set ASPM bits in MPC2 register. */
551 pcie_update_cfg(dev, 0xd4, ~(0x3 << 2), (1 << 4) | (0x2 << 2));
552
553 /* Set unique clock exit latency in MPC register. */
554 pcie_update_cfg(dev, 0xd8, ~(0x7 << 18), (0x7 << 18));
555
556 /* Set L1 exit latency in LCAP register. */
557 pcie_update_cfg(dev, 0x4c, ~(0x7 << 15), (0x4 << 15));
558
559 if (is_lp) {
560 switch (rp) {
561 case 1:
562 pcie_add_0x0202000_iobp(0xe9002440);
563 break;
564 case 2:
565 pcie_add_0x0202000_iobp(0xe9002640);
566 break;
567 case 3:
568 pcie_add_0x0202000_iobp(0xe9000840);
569 break;
570 case 4:
571 pcie_add_0x0202000_iobp(0xe9000a40);
572 break;
573 case 5:
574 pcie_add_0x0202000_iobp(0xe9000c40);
575 pcie_add_0x0202000_iobp(0xe9000e40);
576 pcie_add_0x0202000_iobp(0xe9001040);
577 pcie_add_0x0202000_iobp(0xe9001240);
578 break;
579 case 6:
580 /* Update IOBP based on lane ownership. */
581 if (rpc.pin_ownership & (1 << 4))
582 pcie_add_0x0202000_iobp(0xea002040);
583 if (rpc.pin_ownership & (1 << 5))
584 pcie_add_0x0202000_iobp(0xea002240);
585 if (rpc.pin_ownership & (1 << 6))
586 pcie_add_0x0202000_iobp(0xea002440);
587 if (rpc.pin_ownership & (1 << 7))
588 pcie_add_0x0202000_iobp(0xea002640);
589 break;
590 }
591 } else {
592 switch (rp) {
593 case 1:
594 if ((rpc.pin_ownership & 0x3) == 1)
595 pcie_add_0x0202000_iobp(0xe9002e40);
596 else
597 pcie_add_0x0202000_iobp(0xea002040);
598 break;
599 case 2:
600 if ((rpc.pin_ownership & 0xc) == 0x4)
601 pcie_add_0x0202000_iobp(0xe9002c40);
602 else
603 pcie_add_0x0202000_iobp(0xea002240);
604 break;
605 case 3:
606 pcie_add_0x0202000_iobp(0xe9002a40);
607 break;
608 case 4:
609 pcie_add_0x0202000_iobp(0xe9002840);
610 break;
611 case 5:
612 pcie_add_0x0202000_iobp(0xe9002640);
613 break;
614 case 6:
615 pcie_add_0x0202000_iobp(0xe9002440);
616 break;
617 case 7:
618 pcie_add_0x0202000_iobp(0xe9002240);
619 break;
620 case 8:
621 pcie_add_0x0202000_iobp(0xe9002040);
622 break;
623 }
624 }
625
626 pcie_update_cfg(dev, 0x338, ~(1 << 26), 0);
627 }
628
629 /* Enable LTR in Root Port. */
630 pcie_update_cfg(dev, 0x64, ~(1 << 11), (1 << 11));
631 pcie_update_cfg(dev, 0x68, ~(1 << 10), (1 << 10));
632
633 pcie_update_cfg(dev, 0x318, ~(0xffff << 16), (0x1414 << 16));
634
635 /* Set L1 exit latency in LCAP register. */
636 if (!do_aspm && (pci_read_config8(dev, 0xf5) & 0x1))
637 pcie_update_cfg(dev, 0x4c, ~(0x7 << 15), (0x4 << 15));
638 else
639 pcie_update_cfg(dev, 0x4c, ~(0x7 << 15), (0x2 << 15));
640
641 pcie_update_cfg(dev, 0x314, 0x0, 0x743a361b);
642
643 /* Set Common Clock Exit Latency in MPC register. */
644 pcie_update_cfg(dev, 0xd8, ~(0x7 << 15), (0x3 << 15));
645
646 pcie_update_cfg(dev, 0x33c, ~0x00ffffff, 0x854c74);
647
Stefan Reinauerab365af2013-12-03 12:13:26 -0800648 /* Set Invalid Recieve Range Check Enable in MPC register. */
649 pcie_update_cfg(dev, 0xd8, ~0, (1 << 25));
650
651 pcie_update_cfg8(dev, 0xf5, 0x3f, 0);
652
653 if (rp == 1 || rp == 5 || (is_lp && rp == 6))
654 pcie_update_cfg8(dev, 0xf7, ~0xc, 0);
655
656 /* Set EOI forwarding disable. */
657 pcie_update_cfg(dev, 0xd4, ~0, (1 << 1));
658
659 /* Set something involving advanced error reporting. */
660 pcie_update_cfg(dev, 0x100, ~((1 << 20) - 1), 0x10001);
661
662 if (is_lp)
663 pcie_update_cfg(dev, 0x100, ~0, (1 << 29));
664
665 /* Read and write back write-once capability registers. */
666 pcie_update_cfg(dev, 0x34, ~0, 0);
667 pcie_update_cfg(dev, 0x40, ~0, 0);
668 pcie_update_cfg(dev, 0x80, ~0, 0);
669 pcie_update_cfg(dev, 0x90, ~0, 0);
Aaron Durbin76c37002012-10-30 09:03:43 -0500670}
671
672static void pci_init(struct device *dev)
673{
674 u16 reg16;
675 u32 reg32;
676
677 printk(BIOS_DEBUG, "Initializing PCH PCIe bridge.\n");
678
Aaron Durbinc0254e62013-06-20 01:20:30 -0500679 /* Enable SERR */
680 reg32 = pci_read_config32(dev, PCI_COMMAND);
681 reg32 |= PCI_COMMAND_SERR;
682 pci_write_config32(dev, PCI_COMMAND, reg32);
683
Aaron Durbin76c37002012-10-30 09:03:43 -0500684 /* Enable Bus Master */
685 reg32 = pci_read_config32(dev, PCI_COMMAND);
686 reg32 |= PCI_COMMAND_MASTER;
687 pci_write_config32(dev, PCI_COMMAND, reg32);
688
689 /* Set Cache Line Size to 0x10 */
690 // This has no effect but the OS might expect it
691 pci_write_config8(dev, 0x0c, 0x10);
692
693 reg16 = pci_read_config16(dev, 0x3e);
694 reg16 &= ~(1 << 0); /* disable parity error response */
695 // reg16 &= ~(1 << 1); /* disable SERR */
696 reg16 |= (1 << 2); /* ISA enable */
697 pci_write_config16(dev, 0x3e, reg16);
698
699#ifdef EVEN_MORE_DEBUG
700 reg32 = pci_read_config32(dev, 0x20);
701 printk(BIOS_SPEW, " MBL = 0x%08x\n", reg32);
702 reg32 = pci_read_config32(dev, 0x24);
703 printk(BIOS_SPEW, " PMBL = 0x%08x\n", reg32);
704 reg32 = pci_read_config32(dev, 0x28);
705 printk(BIOS_SPEW, " PMBU32 = 0x%08x\n", reg32);
706 reg32 = pci_read_config32(dev, 0x2c);
707 printk(BIOS_SPEW, " PMLU32 = 0x%08x\n", reg32);
708#endif
709
710 /* Clear errors in status registers */
711 reg16 = pci_read_config16(dev, 0x06);
Aaron Durbin76c37002012-10-30 09:03:43 -0500712 pci_write_config16(dev, 0x06, reg16);
Aaron Durbin76c37002012-10-30 09:03:43 -0500713 reg16 = pci_read_config16(dev, 0x1e);
Aaron Durbin76c37002012-10-30 09:03:43 -0500714 pci_write_config16(dev, 0x1e, reg16);
Aaron Durbin76c37002012-10-30 09:03:43 -0500715}
716
717static void pch_pcie_enable(device_t dev)
718{
Aaron Durbinc0254e62013-06-20 01:20:30 -0500719 /* Add this device to the root port config structure. */
720 root_port_init_config(dev);
721
722 /* Check to see if this Root Port should be disabled. */
723 root_port_check_disable(dev);
724
Aaron Durbin76c37002012-10-30 09:03:43 -0500725 /* Power Management init before enumeration */
Aaron Durbinc0254e62013-06-20 01:20:30 -0500726 if (dev->enabled)
Stefan Reinauerab365af2013-12-03 12:13:26 -0800727 pch_pcie_early(dev);
Aaron Durbinc0254e62013-06-20 01:20:30 -0500728
729 /*
730 * When processing the last PCIe root port we can now
731 * update the Root Port Function Number and Hide register.
732 */
733 if (root_port_is_last(dev))
734 root_port_commit_config();
Aaron Durbin76c37002012-10-30 09:03:43 -0500735}
736
737static void pcie_set_subsystem(device_t dev, unsigned vendor, unsigned device)
738{
739 /* NOTE: This is not the default position! */
740 if (!vendor || !device) {
741 pci_write_config32(dev, 0x94,
742 pci_read_config32(dev, 0));
743 } else {
744 pci_write_config32(dev, 0x94,
745 ((device & 0xffff) << 16) | (vendor & 0xffff));
746 }
747}
748
749static struct pci_operations pci_ops = {
750 .set_subsystem = pcie_set_subsystem,
751};
752
753static struct device_operations device_ops = {
754 .read_resources = pci_bus_read_resources,
755 .set_resources = pci_dev_set_resources,
756 .enable_resources = pci_bus_enable_resources,
757 .init = pci_init,
758 .enable = pch_pcie_enable,
759 .scan_bus = pciexp_scan_bridge,
760 .ops_pci = &pci_ops,
761};
762
Duncan Laurie74c0d052012-12-17 11:31:40 -0800763static const unsigned short pci_device_ids[] = {
764 /* Lynxpoint Mobile */
765 0x8c10, 0x8c12, 0x8c14, 0x8c16, 0x8c18, 0x8c1a, 0x8c1c, 0x8c1e,
766 /* Lynxpoint Low Power */
767 0x9c10, 0x9c12, 0x9c14, 0x9c16, 0x9c18, 0x9c1a,
768 0
769};
Aaron Durbin76c37002012-10-30 09:03:43 -0500770
771static const struct pci_driver pch_pcie __pci_driver = {
772 .ops = &device_ops,
773 .vendor = PCI_VENDOR_ID_INTEL,
774 .devices = pci_device_ids,
775};