blob: 7d31b3ea1872ca320809c9c949f50e797e18f24a [file] [log] [blame]
Angel Pons182dbde2020-04-02 23:49:05 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Aaron Durbin76c37002012-10-30 09:03:43 -05002
Tristan Corrick05b75242018-12-06 22:47:42 +13003#include <assert.h>
4#include <commonlib/helpers.h>
Aaron Durbin76c37002012-10-30 09:03:43 -05005#include <console/console.h>
6#include <device/device.h>
7#include <device/pci.h>
8#include <device/pciexp.h>
9#include <device/pci_ids.h>
Patrick Rudolphe56189c2018-04-18 10:11:59 +020010#include <device/pci_ops.h>
Angel Pons2178b722020-05-31 00:55:35 +020011#include "iobp.h"
Aaron Durbin76c37002012-10-30 09:03:43 -050012#include "pch.h"
Patrick Rudolph273a8dc2016-02-06 18:07:59 +010013#include <southbridge/intel/common/gpio.h>
Tristan Corrick05b75242018-12-06 22:47:42 +130014#include <stdint.h>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030015#include "chip.h"
Aaron Durbin76c37002012-10-30 09:03:43 -050016
Aaron Durbinc0254e62013-06-20 01:20:30 -050017#define MAX_NUM_ROOT_PORTS 8
Aaron Durbinc0254e62013-06-20 01:20:30 -050018
19struct root_port_config {
20 /* RPFN is a write-once register so keep a copy until it is written */
21 u32 orig_rpfn;
22 u32 new_rpfn;
23 u32 pin_ownership;
24 u32 strpfusecfg1;
25 u32 strpfusecfg2;
26 u32 strpfusecfg3;
Stefan Reinauerab365af2013-12-03 12:13:26 -080027 u32 b0d28f0_32c;
28 u32 b0d28f4_32c;
29 u32 b0d28f5_32c;
Angel Ponsaf4bd562021-12-28 13:05:56 +010030 bool coalesce;
Aaron Durbinc0254e62013-06-20 01:20:30 -050031 int gbe_port;
32 int num_ports;
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +020033 struct device *ports[MAX_NUM_ROOT_PORTS];
Aaron Durbinc0254e62013-06-20 01:20:30 -050034};
35
36static struct root_port_config rpc;
37
38static inline int max_root_ports(void)
Aaron Durbin60f82082013-06-19 13:28:04 -050039{
Felix Singer43b7f412022-03-07 04:34:52 +010040 if (pch_is_lp() || pch_silicon_id() == PCI_DID_INTEL_LPT_H81)
Tristan Corrickd3f01b22018-12-06 22:46:58 +130041 return 6;
42
43 return 8;
Aaron Durbin60f82082013-06-19 13:28:04 -050044}
45
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +020046static inline int root_port_is_first(struct device *dev)
Aaron Durbin60f82082013-06-19 13:28:04 -050047{
Aaron Durbinc0254e62013-06-20 01:20:30 -050048 return PCI_FUNC(dev->path.pci.devfn) == 0;
49}
Aaron Durbin60f82082013-06-19 13:28:04 -050050
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +020051static inline int root_port_is_last(struct device *dev)
Aaron Durbinc0254e62013-06-20 01:20:30 -050052{
53 return PCI_FUNC(dev->path.pci.devfn) == (rpc.num_ports - 1);
54}
Aaron Durbin60f82082013-06-19 13:28:04 -050055
Aaron Durbinc0254e62013-06-20 01:20:30 -050056/* Root ports are numbered 1..N in the documentation. */
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +020057static inline int root_port_number(struct device *dev)
Aaron Durbinc0254e62013-06-20 01:20:30 -050058{
59 return PCI_FUNC(dev->path.pci.devfn) + 1;
60}
Aaron Durbin60f82082013-06-19 13:28:04 -050061
Tristan Corrick05b75242018-12-06 22:47:42 +130062static bool is_rp_enabled(int rp)
63{
64 ASSERT(rp > 0 && rp <= ARRAY_SIZE(rpc.ports));
65
66 if (rpc.ports[rp - 1] == NULL)
67 return false;
68
69 return rpc.ports[rp - 1]->enabled;
70}
71
Aaron Durbinc0254e62013-06-20 01:20:30 -050072static void root_port_config_update_gbe_port(void)
73{
74 /* Is the Gbe Port enabled? */
75 if (!((rpc.strpfusecfg1 >> 19) & 1))
76 return;
77
78 if (pch_is_lp()) {
79 switch ((rpc.strpfusecfg1 >> 16) & 0x7) {
80 case 0:
81 rpc.gbe_port = 3;
82 break;
83 case 1:
84 rpc.gbe_port = 4;
85 break;
86 case 2:
87 case 3:
88 case 4:
89 case 5:
90 /* Lanes 0-4 of Root Port 5. */
91 rpc.gbe_port = 5;
92 break;
93 default:
94 printk(BIOS_DEBUG, "Invalid GbE Port Selection.\n");
95 }
96 } else {
97 /* Non-LP has 1:1 mapping with root ports. */
98 rpc.gbe_port = ((rpc.strpfusecfg1 >> 16) & 0x7) + 1;
99 }
100}
101
Angel Pons12404e02020-08-04 00:26:45 +0200102static void update_num_ports(void)
103{
104 /*
105 * According to existing code in 'root_port_check_disable()', which does
106 * not agree with the confusing information on the datasheets, the last
107 * visible function depends on the strapped root port width as follows:
108 *
109 * +-----+----+----+----+----+
110 * | RPC | #5 | #6 | #7 | #8 |
111 * +-----+----+----+----+----+
112 * | 0 | x1 | x1 | x1 | x1 |
113 * | 1 | x2 | | x1 | x1 |
114 * | 2 | x2 | | x2 | |
115 * | 3 | x4 | | | |
116 * +-----+----+----+----+----+
117 */
118 switch ((rpc.strpfusecfg2 >> 14) & 0x3) {
119 case 0:
120 case 1:
121 break;
122 case 2:
123 rpc.num_ports = MIN(rpc.num_ports, 7);
124 break;
125 case 3:
126 rpc.num_ports = MIN(rpc.num_ports, 5);
127 break;
128 }
129
130 printk(BIOS_DEBUG, "Adjusted number of PCIe root ports to %d as per strpfusecfg2\n",
131 rpc.num_ports);
132}
133
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200134static void root_port_init_config(struct device *dev)
Aaron Durbinc0254e62013-06-20 01:20:30 -0500135{
136 int rp;
137
138 if (root_port_is_first(dev)) {
139 rpc.orig_rpfn = RCBA32(RPFN);
140 rpc.new_rpfn = rpc.orig_rpfn;
141 rpc.num_ports = max_root_ports();
142 rpc.gbe_port = -1;
143
144 rpc.pin_ownership = pci_read_config32(dev, 0x410);
145 root_port_config_update_gbe_port();
146
147 if (dev->chip_info != NULL) {
148 struct southbridge_intel_lynxpoint_config *config;
149
150 config = dev->chip_info;
151 rpc.coalesce = config->pcie_port_coalesce;
152 }
153 }
154
155 rp = root_port_number(dev);
156 if (rp > rpc.num_ports) {
157 printk(BIOS_ERR, "Found Root Port %d, expecting %d\n",
158 rp, rpc.num_ports);
159 return;
160 }
161
162 /* Read the fuse configuration and pin ownership. */
163 switch (rp) {
164 case 1:
165 rpc.strpfusecfg1 = pci_read_config32(dev, 0xfc);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800166 rpc.b0d28f0_32c = pci_read_config32(dev, 0x32c);
Aaron Durbinc0254e62013-06-20 01:20:30 -0500167 break;
168 case 5:
169 rpc.strpfusecfg2 = pci_read_config32(dev, 0xfc);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800170 rpc.b0d28f4_32c = pci_read_config32(dev, 0x32c);
Angel Pons12404e02020-08-04 00:26:45 +0200171
172 if (!pch_is_lp())
173 update_num_ports();
174
Aaron Durbinc0254e62013-06-20 01:20:30 -0500175 break;
176 case 6:
Stefan Reinauerab365af2013-12-03 12:13:26 -0800177 rpc.b0d28f5_32c = pci_read_config32(dev, 0x32c);
Aaron Durbinc0254e62013-06-20 01:20:30 -0500178 rpc.strpfusecfg3 = pci_read_config32(dev, 0xfc);
179 break;
180 default:
181 break;
182 }
183
184 /* Cache pci device. */
185 rpc.ports[rp - 1] = dev;
Aaron Durbin60f82082013-06-19 13:28:04 -0500186}
187
188/* Update devicetree with new Root Port function number assignment */
Aaron Durbinc0254e62013-06-20 01:20:30 -0500189static void pch_pcie_device_set_func(int index, int pci_func)
Aaron Durbin60f82082013-06-19 13:28:04 -0500190{
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200191 struct device *dev;
Martin Rothff744bf2019-10-23 21:46:03 -0600192 unsigned int new_devfn;
Aaron Durbin60f82082013-06-19 13:28:04 -0500193
Aaron Durbinc0254e62013-06-20 01:20:30 -0500194 dev = rpc.ports[index];
Aaron Durbin60f82082013-06-19 13:28:04 -0500195
Aaron Durbinc0254e62013-06-20 01:20:30 -0500196 /* 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);
Aaron Durbin60f82082013-06-19 13:28:04 -0500199
Aaron Durbinc0254e62013-06-20 01:20:30 -0500200 /* Determine the new devfn for this port */
201 new_devfn = PCI_DEVFN(PCH_PCIE_DEV_SLOT, pci_func);
Aaron Durbin60f82082013-06-19 13:28:04 -0500202
Tristan Corrick05b75242018-12-06 22:47:42 +1300203 if (dev && dev->path.pci.devfn != new_devfn) {
Aaron Durbinc0254e62013-06-20 01:20:30 -0500204 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));
Aaron Durbin60f82082013-06-19 13:28:04 -0500209
Aaron Durbinc0254e62013-06-20 01:20:30 -0500210 dev->path.pci.devfn = new_devfn;
Aaron Durbin60f82082013-06-19 13:28:04 -0500211 }
212}
213
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500214static void pcie_enable_clock_gating(void)
215{
216 int i;
217 int is_lp;
218 int enabled_ports;
219
220 is_lp = pch_is_lp();
221 enabled_ports = 0;
222
223 for (i = 0; i < rpc.num_ports; i++) {
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200224 struct device *dev;
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500225 int rp;
226
227 dev = rpc.ports[i];
Tristan Corrick05b75242018-12-06 22:47:42 +1300228 if (!dev)
229 continue;
230
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500231 rp = root_port_number(dev);
232
Tristan Corrick05b75242018-12-06 22:47:42 +1300233 if (!is_rp_enabled(rp)) {
Ryan Salsamendi3f2fe182017-07-04 13:14:16 -0700234
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500235 /* Configure shared resource clock gating. */
236 if (rp == 1 || rp == 5 || (rp == 6 && is_lp))
Angel Ponsbf9bc502020-06-08 00:12:43 +0200237 pci_or_config8(dev, 0xe1, 0x3c);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500238
239 if (!is_lp) {
Tristan Corrick05b75242018-12-06 22:47:42 +1300240 if (rp == 1 && !is_rp_enabled(2) &&
241 !is_rp_enabled(3) && !is_rp_enabled(4)) {
Angel Ponsbf9bc502020-06-08 00:12:43 +0200242 pci_or_config8(dev, 0xe2, 1);
243 pci_or_config8(dev, 0xe1, 1 << 7);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500244 }
Tristan Corrick05b75242018-12-06 22:47:42 +1300245 if (rp == 5 && !is_rp_enabled(6) &&
246 !is_rp_enabled(7) && !is_rp_enabled(8)) {
Angel Ponsbf9bc502020-06-08 00:12:43 +0200247 pci_or_config8(dev, 0xe2, 1);
248 pci_or_config8(dev, 0xe1, 1 << 7);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500249 }
250 continue;
251 }
252
Angel Ponsbf9bc502020-06-08 00:12:43 +0200253 pci_or_config8(dev, 0xe2, 3 << 4);
254 pci_or_config32(dev, 0x420, 1 << 31);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500255
256 /* Per-Port CLKREQ# handling. */
257 if (is_lp && gpio_is_native(18 + rp - 1))
Angel Ponsbf9bc502020-06-08 00:12:43 +0200258 pci_or_config32(dev, 0x420, 3 << 29);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500259
260 /* Enable static clock gating. */
Tristan Corrick05b75242018-12-06 22:47:42 +1300261 if (rp == 1 && !is_rp_enabled(2) &&
262 !is_rp_enabled(3) && !is_rp_enabled(4)) {
Angel Ponsbf9bc502020-06-08 00:12:43 +0200263 pci_or_config8(dev, 0xe2, 1);
264 pci_or_config8(dev, 0xe1, 1 << 7);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500265 } else if (rp == 5 || rp == 6) {
Angel Ponsbf9bc502020-06-08 00:12:43 +0200266 pci_or_config8(dev, 0xe2, 1);
267 pci_or_config8(dev, 0xe1, 1 << 7);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500268 }
269 continue;
270 }
271
272 enabled_ports++;
273
274 /* Enable dynamic clock gating. */
Angel Ponsbf9bc502020-06-08 00:12:43 +0200275 pci_or_config8(dev, 0xe1, 0x03);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500276
277 if (is_lp) {
Angel Ponsbf9bc502020-06-08 00:12:43 +0200278 pci_or_config8(dev, 0xe2, 1 << 6);
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300279 pci_update_config8(dev, 0xe8, ~(3 << 2), (2 << 2));
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500280 }
281
282 /* Update PECR1 register. */
Angel Ponsbf9bc502020-06-08 00:12:43 +0200283 pci_or_config8(dev, 0xe8, 1);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500284
Angel Pons72f4dda2020-09-25 00:23:20 +0200285 pci_or_config8(dev, 0x324, 1 << 5);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500286
287 /* Per-Port CLKREQ# handling. */
288 if (is_lp && gpio_is_native(18 + rp - 1))
Angel Ponsbf9bc502020-06-08 00:12:43 +0200289 pci_or_config32(dev, 0x420, 3 << 29);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500290
291 /* Configure shared resource clock gating. */
292 if (rp == 1 || rp == 5 || (rp == 6 && is_lp))
Angel Ponsbf9bc502020-06-08 00:12:43 +0200293 pci_or_config8(dev, 0xe1, 0x3c);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500294 }
295
Tristan Corrick05b75242018-12-06 22:47:42 +1300296 if (!enabled_ports && is_lp && rpc.ports[0])
Angel Ponsbf9bc502020-06-08 00:12:43 +0200297 pci_or_config8(rpc.ports[0], 0xe1, 1 << 6);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500298}
299
Aaron Durbinc0254e62013-06-20 01:20:30 -0500300static void root_port_commit_config(void)
Aaron Durbin60f82082013-06-19 13:28:04 -0500301{
Aaron Durbinc0254e62013-06-20 01:20:30 -0500302 int i;
Aaron Durbin60f82082013-06-19 13:28:04 -0500303
Aaron Durbinc0254e62013-06-20 01:20:30 -0500304 /* If the first root port is disabled the coalesce ports. */
Tristan Corrick05b75242018-12-06 22:47:42 +1300305 if (!is_rp_enabled(1))
Angel Ponsaf4bd562021-12-28 13:05:56 +0100306 rpc.coalesce = true;
Aaron Durbin60f82082013-06-19 13:28:04 -0500307
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500308 /* Perform clock gating configuration. */
309 pcie_enable_clock_gating();
310
Aaron Durbinc0254e62013-06-20 01:20:30 -0500311 for (i = 0; i < rpc.num_ports; i++) {
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200312 struct device *dev;
Aaron Durbin60f82082013-06-19 13:28:04 -0500313
Aaron Durbinc0254e62013-06-20 01:20:30 -0500314 dev = rpc.ports[i];
Aaron Durbin60f82082013-06-19 13:28:04 -0500315
Aaron Durbinc0254e62013-06-20 01:20:30 -0500316 if (dev == NULL) {
317 printk(BIOS_ERR, "Root Port %d device is NULL?\n", i+1);
318 continue;
Aaron Durbin60f82082013-06-19 13:28:04 -0500319 }
320
Aaron Durbinc0254e62013-06-20 01:20:30 -0500321 if (dev->enabled)
322 continue;
323
Elyes Haouas8b8ada62022-11-22 17:36:02 +0100324 printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
Aaron Durbinc0254e62013-06-20 01:20:30 -0500325
Aaron Durbin60f82082013-06-19 13:28:04 -0500326 /* Ensure memory, io, and bus master are all disabled */
Angel Ponsbf9bc502020-06-08 00:12:43 +0200327 pci_and_config16(dev, PCI_COMMAND,
328 ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO));
Aaron Durbin60f82082013-06-19 13:28:04 -0500329
Aaron Durbin60f82082013-06-19 13:28:04 -0500330 /* Disable this device if possible */
331 pch_disable_devfn(dev);
Aaron Durbin60f82082013-06-19 13:28:04 -0500332 }
333
Aaron Durbinc0254e62013-06-20 01:20:30 -0500334 if (rpc.coalesce) {
335 int current_func;
Aaron Durbin60f82082013-06-19 13:28:04 -0500336
Aaron Durbinc0254e62013-06-20 01:20:30 -0500337 /* For all Root Ports N enabled ports get assigned the lower
338 * PCI function number. The disabled ones get upper PCI
339 * function numbers. */
340 current_func = 0;
341 for (i = 0; i < rpc.num_ports; i++) {
Tristan Corrick05b75242018-12-06 22:47:42 +1300342 if (!is_rp_enabled(i + 1))
Aaron Durbinc0254e62013-06-20 01:20:30 -0500343 continue;
344 pch_pcie_device_set_func(i, current_func);
345 current_func++;
346 }
347
348 /* Allocate the disabled devices' PCI function number. */
349 for (i = 0; i < rpc.num_ports; i++) {
Tristan Corrick05b75242018-12-06 22:47:42 +1300350 if (is_rp_enabled(i + 1))
Aaron Durbinc0254e62013-06-20 01:20:30 -0500351 continue;
352 pch_pcie_device_set_func(i, current_func);
353 current_func++;
354 }
355 }
356
357 printk(BIOS_SPEW, "PCH: RPFN 0x%08x -> 0x%08x\n",
358 rpc.orig_rpfn, rpc.new_rpfn);
359 RCBA32(RPFN) = rpc.new_rpfn;
360}
361
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200362static void root_port_mark_disable(struct device *dev)
Aaron Durbinc0254e62013-06-20 01:20:30 -0500363{
364 /* Mark device as disabled. */
365 dev->enabled = 0;
366 /* Mark device to be hidden. */
367 rpc.new_rpfn |= RPFN_HIDE(PCI_FUNC(dev->path.pci.devfn));
368}
369
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200370static void root_port_check_disable(struct device *dev)
Aaron Durbinc0254e62013-06-20 01:20:30 -0500371{
372 int rp;
373 int is_lp;
374
375 /* Device already disabled. */
376 if (!dev->enabled) {
377 root_port_mark_disable(dev);
378 return;
379 }
380
381 rp = root_port_number(dev);
382
383 /* Is the GbE port mapped to this Root Port? */
384 if (rp == rpc.gbe_port) {
385 root_port_mark_disable(dev);
386 return;
387 }
388
389 is_lp = pch_is_lp();
390
391 /* Check Root Port Configuration. */
392 switch (rp) {
393 case 2:
394 /* Root Port 2 is disabled for all lane configurations
395 * but config 00b (4x1 links). */
396 if ((rpc.strpfusecfg1 >> 14) & 0x3) {
397 root_port_mark_disable(dev);
398 return;
399 }
400 break;
401 case 3:
402 /* Root Port 3 is disabled in config 11b (1x4 links). */
403 if (((rpc.strpfusecfg1 >> 14) & 0x3) == 0x3) {
404 root_port_mark_disable(dev);
405 return;
406 }
407 break;
408 case 4:
409 /* Root Port 4 is disabled in configs 11b (1x4 links)
410 * and 10b (2x2 links). */
411 if ((rpc.strpfusecfg1 >> 14) & 0x2) {
412 root_port_mark_disable(dev);
413 return;
414 }
415 break;
416 case 6:
417 if (is_lp)
418 break;
419 /* Root Port 6 is disabled for all lane configurations
420 * but config 00b (4x1 links). */
421 if ((rpc.strpfusecfg2 >> 14) & 0x3) {
422 root_port_mark_disable(dev);
423 return;
424 }
425 break;
426 case 7:
427 if (is_lp)
428 break;
Tristan Corrickbaa4c072018-12-06 22:47:21 +1300429 /* Root Port 7 is disabled in config 11b (1x4 links). */
Aaron Durbinc0254e62013-06-20 01:20:30 -0500430 if (((rpc.strpfusecfg2 >> 14) & 0x3) == 0x3) {
431 root_port_mark_disable(dev);
432 return;
433 }
434 break;
435 case 8:
436 if (is_lp)
437 break;
438 /* Root Port 8 is disabled in configs 11b (1x4 links)
439 * and 10b (2x2 links). */
440 if ((rpc.strpfusecfg2 >> 14) & 0x2) {
441 root_port_mark_disable(dev);
442 return;
443 }
444 break;
445 }
446
447 /* Check Pin Ownership. */
448 if (is_lp) {
449 switch (rp) {
450 case 1:
451 /* Bit 0 is Root Port 1 ownership. */
452 if ((rpc.pin_ownership & 0x1) == 0) {
453 root_port_mark_disable(dev);
454 return;
455 }
456 break;
457 case 2:
458 /* Bit 2 is Root Port 2 ownership. */
459 if ((rpc.pin_ownership & 0x4) == 0) {
460 root_port_mark_disable(dev);
461 return;
462 }
463 break;
464 case 6:
465 /* Bits 7:4 are Root Port 6 pin-lane ownership. */
466 if ((rpc.pin_ownership & 0xf0) == 0) {
467 root_port_mark_disable(dev);
468 return;
469 }
470 break;
471 }
472 } else {
473 switch (rp) {
474 case 1:
475 /* Bits 4 and 0 are Root Port 1 ownership. */
476 if ((rpc.pin_ownership & 0x11) == 0) {
477 root_port_mark_disable(dev);
478 return;
479 }
480 break;
481 case 2:
482 /* Bits 5 and 2 are Root Port 2 ownership. */
483 if ((rpc.pin_ownership & 0x24) == 0) {
484 root_port_mark_disable(dev);
485 return;
486 }
487 break;
488 }
Aaron Durbin60f82082013-06-19 13:28:04 -0500489 }
490}
491
Stefan Reinauerab365af2013-12-03 12:13:26 -0800492static void pcie_add_0x0202000_iobp(u32 reg)
493{
494 u32 reg32;
Aaron Durbin76c37002012-10-30 09:03:43 -0500495
Stefan Reinauerab365af2013-12-03 12:13:26 -0800496 reg32 = pch_iobp_read(reg);
497 reg32 += (0x2 << 16) | (0x2 << 8);
498 pch_iobp_write(reg, reg32);
499}
Aaron Durbin76c37002012-10-30 09:03:43 -0500500
Stefan Reinauerab365af2013-12-03 12:13:26 -0800501static void pch_pcie_early(struct device *dev)
502{
Duncan Laurie249a03b2013-08-09 09:06:41 -0700503 struct southbridge_intel_lynxpoint_config *config = dev->chip_info;
Angel Pons2aaf7c02020-09-24 18:03:18 +0200504 int do_aspm = 0;
505 int rp = root_port_number(dev);
506 int is_lp = pch_is_lp();
Aaron Durbin76c37002012-10-30 09:03:43 -0500507
Stefan Reinauerab365af2013-12-03 12:13:26 -0800508 if (is_lp) {
509 switch (rp) {
510 case 1:
511 case 2:
512 case 3:
513 case 4:
Angel Pons2aaf7c02020-09-24 18:03:18 +0200514 /*
515 * Bits 31:28 of b0d28f0 0x32c register correspond to
516 * Root Ports 4:1.
517 */
Stefan Reinauerab365af2013-12-03 12:13:26 -0800518 do_aspm = !!(rpc.b0d28f0_32c & (1 << (28 + rp - 1)));
519 break;
520 case 5:
Angel Pons2aaf7c02020-09-24 18:03:18 +0200521 /*
522 * Bit 28 of b0d28f4 0x32c register correspond to
523 * Root Ports 4:1.
524 */
Stefan Reinauerab365af2013-12-03 12:13:26 -0800525 do_aspm = !!(rpc.b0d28f4_32c & (1 << 28));
526 break;
527 case 6:
Angel Pons2aaf7c02020-09-24 18:03:18 +0200528 /*
529 * Bit 28 of b0d28f5 0x32c register correspond to
530 * Root Ports 4:1.
531 */
Stefan Reinauerab365af2013-12-03 12:13:26 -0800532 do_aspm = !!(rpc.b0d28f5_32c & (1 << 28));
533 break;
534 }
535 } else {
536 switch (rp) {
537 case 1:
538 case 2:
539 case 3:
540 case 4:
Angel Pons2aaf7c02020-09-24 18:03:18 +0200541 /*
542 * Bits 31:28 of b0d28f0 0x32c register correspond to
543 * Root Ports 4:1.
544 */
Stefan Reinauerab365af2013-12-03 12:13:26 -0800545 do_aspm = !!(rpc.b0d28f0_32c & (1 << (28 + rp - 1)));
546 break;
547 case 5:
548 case 6:
549 case 7:
550 case 8:
Angel Pons2aaf7c02020-09-24 18:03:18 +0200551 /*
552 * Bits 31:28 of b0d28f4 0x32c register correspond to
553 * Root Ports 8:5.
554 */
Stefan Reinauerab365af2013-12-03 12:13:26 -0800555 do_aspm = !!(rpc.b0d28f4_32c & (1 << (28 + rp - 5)));
556 break;
557 }
Aaron Durbin76c37002012-10-30 09:03:43 -0500558 }
Stefan Reinauerab365af2013-12-03 12:13:26 -0800559
Duncan Laurie249a03b2013-08-09 09:06:41 -0700560 /* Allow ASPM to be forced on in devicetree */
561 if (config && (config->pcie_port_force_aspm & (1 << (rp - 1))))
562 do_aspm = 1;
563
564 printk(BIOS_DEBUG, "PCIe Root Port %d ASPM is %sabled\n",
565 rp, do_aspm ? "en" : "dis");
566
Stefan Reinauerab365af2013-12-03 12:13:26 -0800567 if (do_aspm) {
568 /* Set ASPM bits in MPC2 register. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300569 pci_update_config32(dev, 0xd4, ~(0x3 << 2), (1 << 4) | (0x2 << 2));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800570
571 /* Set unique clock exit latency in MPC register. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300572 pci_update_config32(dev, 0xd8, ~(0x7 << 18), (0x7 << 18));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800573
574 /* Set L1 exit latency in LCAP register. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300575 pci_update_config32(dev, 0x4c, ~(0x7 << 15), (0x4 << 15));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800576
577 if (is_lp) {
578 switch (rp) {
579 case 1:
580 pcie_add_0x0202000_iobp(0xe9002440);
581 break;
582 case 2:
583 pcie_add_0x0202000_iobp(0xe9002640);
584 break;
585 case 3:
586 pcie_add_0x0202000_iobp(0xe9000840);
587 break;
588 case 4:
589 pcie_add_0x0202000_iobp(0xe9000a40);
590 break;
591 case 5:
592 pcie_add_0x0202000_iobp(0xe9000c40);
593 pcie_add_0x0202000_iobp(0xe9000e40);
594 pcie_add_0x0202000_iobp(0xe9001040);
595 pcie_add_0x0202000_iobp(0xe9001240);
596 break;
597 case 6:
598 /* Update IOBP based on lane ownership. */
599 if (rpc.pin_ownership & (1 << 4))
600 pcie_add_0x0202000_iobp(0xea002040);
601 if (rpc.pin_ownership & (1 << 5))
602 pcie_add_0x0202000_iobp(0xea002240);
603 if (rpc.pin_ownership & (1 << 6))
604 pcie_add_0x0202000_iobp(0xea002440);
605 if (rpc.pin_ownership & (1 << 7))
606 pcie_add_0x0202000_iobp(0xea002640);
607 break;
608 }
609 } else {
610 switch (rp) {
611 case 1:
612 if ((rpc.pin_ownership & 0x3) == 1)
613 pcie_add_0x0202000_iobp(0xe9002e40);
614 else
615 pcie_add_0x0202000_iobp(0xea002040);
616 break;
617 case 2:
618 if ((rpc.pin_ownership & 0xc) == 0x4)
619 pcie_add_0x0202000_iobp(0xe9002c40);
620 else
621 pcie_add_0x0202000_iobp(0xea002240);
622 break;
623 case 3:
624 pcie_add_0x0202000_iobp(0xe9002a40);
625 break;
626 case 4:
627 pcie_add_0x0202000_iobp(0xe9002840);
628 break;
629 case 5:
630 pcie_add_0x0202000_iobp(0xe9002640);
631 break;
632 case 6:
633 pcie_add_0x0202000_iobp(0xe9002440);
634 break;
635 case 7:
636 pcie_add_0x0202000_iobp(0xe9002240);
637 break;
638 case 8:
639 pcie_add_0x0202000_iobp(0xe9002040);
640 break;
641 }
642 }
643
Angel Ponsbf9bc502020-06-08 00:12:43 +0200644 pci_and_config32(dev, 0x338, ~(1 << 26));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800645 }
646
Angel Ponsa575759c2020-11-05 11:35:54 +0100647 /* Enable LTR in Root Port. Disable OBFF. */
648 pci_update_config32(dev, 0x64, ~(3 << 18), 1 << 11);
649 pci_update_config16(dev, 0x68, ~(3 << 13), 1 << 10);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800650
Angel Pons2aaf7c02020-09-24 18:03:18 +0200651 pci_update_config32(dev, 0x318, ~(0xffff << 16), (0x1414 << 16));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800652
653 /* Set L1 exit latency in LCAP register. */
654 if (!do_aspm && (pci_read_config8(dev, 0xf5) & 0x1))
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300655 pci_update_config32(dev, 0x4c, ~(0x7 << 15), (0x4 << 15));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800656 else
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300657 pci_update_config32(dev, 0x4c, ~(0x7 << 15), (0x2 << 15));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800658
Angel Ponsbf9bc502020-06-08 00:12:43 +0200659 pci_update_config32(dev, 0x314, 0, 0x743a361b);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800660
661 /* Set Common Clock Exit Latency in MPC register. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300662 pci_update_config32(dev, 0xd8, ~(0x7 << 15), (0x3 << 15));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800663
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300664 pci_update_config32(dev, 0x33c, ~0x00ffffff, 0x854c74);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800665
Matt DeVillier1aeccd12020-10-07 13:18:55 -0500666 /* Set Invalid Receive Range Check Enable in MPC register. */
Angel Ponsbf9bc502020-06-08 00:12:43 +0200667 pci_or_config32(dev, 0xd8, 1 << 25);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800668
Angel Ponsbf9bc502020-06-08 00:12:43 +0200669 pci_and_config8(dev, 0xf5, 0x3f);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800670
671 if (rp == 1 || rp == 5 || (is_lp && rp == 6))
Angel Ponsbf9bc502020-06-08 00:12:43 +0200672 pci_and_config8(dev, 0xf7, ~0x0c);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800673
674 /* Set EOI forwarding disable. */
Angel Ponsbf9bc502020-06-08 00:12:43 +0200675 pci_or_config32(dev, 0xd4, 1 << 1);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800676
Matt DeVillier7f633532020-10-07 13:11:58 -0500677 /* Set AER Extended Cap ID to 01h and Next Cap Pointer to 200h. */
678 if (CONFIG(PCIEXP_AER))
679 pci_update_config32(dev, 0x100, ~0xfffff, (1 << 29) | 0x10001);
680 else
681 pci_update_config32(dev, 0x100, ~0xfffff, (1 << 29));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800682
Matt DeVillier54e1f592020-10-07 13:17:09 -0500683 /* Set L1 Sub-State Cap ID to 1Eh and Next Cap Pointer to None. */
684 if (CONFIG(PCIEXP_L1_SUB_STATE))
685 pci_update_config32(dev, 0x200, ~0xfffff, 0x001e);
686 else
687 pci_update_config32(dev, 0x200, ~0xfffff, 0);
688
Stefan Reinauerab365af2013-12-03 12:13:26 -0800689 if (is_lp)
Angel Ponsbf9bc502020-06-08 00:12:43 +0200690 pci_or_config32(dev, 0x100, 1 << 29);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800691
692 /* Read and write back write-once capability registers. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300693 pci_update_config32(dev, 0x34, ~0, 0);
694 pci_update_config32(dev, 0x40, ~0, 0);
695 pci_update_config32(dev, 0x80, ~0, 0);
696 pci_update_config32(dev, 0x90, ~0, 0);
Aaron Durbin76c37002012-10-30 09:03:43 -0500697}
698
Angel Pons2aaf7c02020-09-24 18:03:18 +0200699static void pch_pcie_init(struct device *dev)
Aaron Durbin76c37002012-10-30 09:03:43 -0500700{
Aaron Durbin76c37002012-10-30 09:03:43 -0500701 printk(BIOS_DEBUG, "Initializing PCH PCIe bridge.\n");
702
Aaron Durbinc0254e62013-06-20 01:20:30 -0500703 /* Enable SERR */
Elyes HAOUAS73ae0762020-04-28 10:13:05 +0200704 pci_or_config16(dev, PCI_COMMAND, PCI_COMMAND_SERR);
Aaron Durbinc0254e62013-06-20 01:20:30 -0500705
Aaron Durbin76c37002012-10-30 09:03:43 -0500706 /* Enable Bus Master */
Elyes HAOUAS73ae0762020-04-28 10:13:05 +0200707 pci_or_config16(dev, PCI_COMMAND, PCI_COMMAND_MASTER);
Aaron Durbin76c37002012-10-30 09:03:43 -0500708
709 /* Set Cache Line Size to 0x10 */
710 // This has no effect but the OS might expect it
711 pci_write_config8(dev, 0x0c, 0x10);
712
Angel Ponsbf9bc502020-06-08 00:12:43 +0200713 pci_and_config16(dev, PCI_BRIDGE_CONTROL, ~PCI_BRIDGE_CTL_PARITY);
Aaron Durbin76c37002012-10-30 09:03:43 -0500714
Aaron Durbin76c37002012-10-30 09:03:43 -0500715 /* Clear errors in status registers */
Angel Ponsbf9bc502020-06-08 00:12:43 +0200716 pci_update_config16(dev, 0x06, ~0, 0);
717 pci_update_config16(dev, 0x1e, ~0, 0);
Aaron Durbin76c37002012-10-30 09:03:43 -0500718}
719
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200720static void pch_pcie_enable(struct device *dev)
Aaron Durbin76c37002012-10-30 09:03:43 -0500721{
Aaron Durbinc0254e62013-06-20 01:20:30 -0500722 /* Add this device to the root port config structure. */
723 root_port_init_config(dev);
724
725 /* Check to see if this Root Port should be disabled. */
726 root_port_check_disable(dev);
727
Aaron Durbin76c37002012-10-30 09:03:43 -0500728 /* Power Management init before enumeration */
Aaron Durbinc0254e62013-06-20 01:20:30 -0500729 if (dev->enabled)
Stefan Reinauerab365af2013-12-03 12:13:26 -0800730 pch_pcie_early(dev);
Aaron Durbinc0254e62013-06-20 01:20:30 -0500731
732 /*
733 * When processing the last PCIe root port we can now
734 * update the Root Port Function Number and Hide register.
735 */
736 if (root_port_is_last(dev))
737 root_port_commit_config();
Aaron Durbin76c37002012-10-30 09:03:43 -0500738}
739
Aaron Durbin76c37002012-10-30 09:03:43 -0500740static struct device_operations device_ops = {
741 .read_resources = pci_bus_read_resources,
742 .set_resources = pci_dev_set_resources,
743 .enable_resources = pci_bus_enable_resources,
Angel Pons2aaf7c02020-09-24 18:03:18 +0200744 .init = pch_pcie_init,
Aaron Durbin76c37002012-10-30 09:03:43 -0500745 .enable = pch_pcie_enable,
746 .scan_bus = pciexp_scan_bridge,
Angel Pons1fc0edd2020-05-31 00:03:28 +0200747 .ops_pci = &pci_dev_ops_pci,
Aaron Durbin76c37002012-10-30 09:03:43 -0500748};
749
Duncan Laurie74c0d052012-12-17 11:31:40 -0800750static const unsigned short pci_device_ids[] = {
Felix Singer43b7f412022-03-07 04:34:52 +0100751 PCI_DID_INTEL_LPT_H_PCIE_RP1,
752 PCI_DID_INTEL_LPT_H_PCIE_RP2,
753 PCI_DID_INTEL_LPT_H_PCIE_RP3,
754 PCI_DID_INTEL_LPT_H_PCIE_RP4,
755 PCI_DID_INTEL_LPT_H_PCIE_RP5,
756 PCI_DID_INTEL_LPT_H_PCIE_RP6,
757 PCI_DID_INTEL_LPT_H_PCIE_RP7,
758 PCI_DID_INTEL_LPT_H_PCIE_RP8,
759 PCI_DID_INTEL_LPT_LP_PCIE_RP1,
760 PCI_DID_INTEL_LPT_LP_PCIE_RP2,
761 PCI_DID_INTEL_LPT_LP_PCIE_RP3,
762 PCI_DID_INTEL_LPT_LP_PCIE_RP4,
763 PCI_DID_INTEL_LPT_LP_PCIE_RP5,
764 PCI_DID_INTEL_LPT_LP_PCIE_RP6,
Duncan Laurie74c0d052012-12-17 11:31:40 -0800765 0
766};
Aaron Durbin76c37002012-10-30 09:03:43 -0500767
768static const struct pci_driver pch_pcie __pci_driver = {
769 .ops = &device_ops,
Felix Singer43b7f412022-03-07 04:34:52 +0100770 .vendor = PCI_VID_INTEL,
Aaron Durbin76c37002012-10-30 09:03:43 -0500771 .devices = pci_device_ids,
772};