blob: 24fab3b41e3e0c37e8816298b2c94469ee206b50 [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>
Kyösti Mälkkidf128a52019-09-21 18:35:37 +03008#include <device/pci_def.h>
Aaron Durbin76c37002012-10-30 09:03:43 -05009#include <device/pciexp.h>
10#include <device/pci_ids.h>
Patrick Rudolphe56189c2018-04-18 10:11:59 +020011#include <device/pci_ops.h>
Angel Pons2178b722020-05-31 00:55:35 +020012#include "iobp.h"
Aaron Durbin76c37002012-10-30 09:03:43 -050013#include "pch.h"
Patrick Rudolph273a8dc2016-02-06 18:07:59 +010014#include <southbridge/intel/common/gpio.h>
Tristan Corrick05b75242018-12-06 22:47:42 +130015#include <stdint.h>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030016#include "chip.h"
Aaron Durbin76c37002012-10-30 09:03:43 -050017
Aaron Durbinc0254e62013-06-20 01:20:30 -050018#define MAX_NUM_ROOT_PORTS 8
Aaron Durbinc0254e62013-06-20 01:20:30 -050019
20struct root_port_config {
21 /* RPFN is a write-once register so keep a copy until it is written */
22 u32 orig_rpfn;
23 u32 new_rpfn;
24 u32 pin_ownership;
25 u32 strpfusecfg1;
26 u32 strpfusecfg2;
27 u32 strpfusecfg3;
Stefan Reinauerab365af2013-12-03 12:13:26 -080028 u32 b0d28f0_32c;
29 u32 b0d28f4_32c;
30 u32 b0d28f5_32c;
Angel Ponsaf4bd562021-12-28 13:05:56 +010031 bool coalesce;
Aaron Durbinc0254e62013-06-20 01:20:30 -050032 int gbe_port;
33 int num_ports;
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +020034 struct device *ports[MAX_NUM_ROOT_PORTS];
Aaron Durbinc0254e62013-06-20 01:20:30 -050035};
36
37static struct root_port_config rpc;
38
39static inline int max_root_ports(void)
Aaron Durbin60f82082013-06-19 13:28:04 -050040{
Felix Singer43b7f412022-03-07 04:34:52 +010041 if (pch_is_lp() || pch_silicon_id() == PCI_DID_INTEL_LPT_H81)
Tristan Corrickd3f01b22018-12-06 22:46:58 +130042 return 6;
43
44 return 8;
Aaron Durbin60f82082013-06-19 13:28:04 -050045}
46
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +020047static inline int root_port_is_first(struct device *dev)
Aaron Durbin60f82082013-06-19 13:28:04 -050048{
Aaron Durbinc0254e62013-06-20 01:20:30 -050049 return PCI_FUNC(dev->path.pci.devfn) == 0;
50}
Aaron Durbin60f82082013-06-19 13:28:04 -050051
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +020052static inline int root_port_is_last(struct device *dev)
Aaron Durbinc0254e62013-06-20 01:20:30 -050053{
54 return PCI_FUNC(dev->path.pci.devfn) == (rpc.num_ports - 1);
55}
Aaron Durbin60f82082013-06-19 13:28:04 -050056
Aaron Durbinc0254e62013-06-20 01:20:30 -050057/* Root ports are numbered 1..N in the documentation. */
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +020058static inline int root_port_number(struct device *dev)
Aaron Durbinc0254e62013-06-20 01:20:30 -050059{
60 return PCI_FUNC(dev->path.pci.devfn) + 1;
61}
Aaron Durbin60f82082013-06-19 13:28:04 -050062
Tristan Corrick05b75242018-12-06 22:47:42 +130063static bool is_rp_enabled(int rp)
64{
65 ASSERT(rp > 0 && rp <= ARRAY_SIZE(rpc.ports));
66
67 if (rpc.ports[rp - 1] == NULL)
68 return false;
69
70 return rpc.ports[rp - 1]->enabled;
71}
72
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
Angel Pons12404e02020-08-04 00:26:45 +0200103static void update_num_ports(void)
104{
105 /*
106 * According to existing code in 'root_port_check_disable()', which does
107 * not agree with the confusing information on the datasheets, the last
108 * visible function depends on the strapped root port width as follows:
109 *
110 * +-----+----+----+----+----+
111 * | RPC | #5 | #6 | #7 | #8 |
112 * +-----+----+----+----+----+
113 * | 0 | x1 | x1 | x1 | x1 |
114 * | 1 | x2 | | x1 | x1 |
115 * | 2 | x2 | | x2 | |
116 * | 3 | x4 | | | |
117 * +-----+----+----+----+----+
118 */
119 switch ((rpc.strpfusecfg2 >> 14) & 0x3) {
120 case 0:
121 case 1:
122 break;
123 case 2:
124 rpc.num_ports = MIN(rpc.num_ports, 7);
125 break;
126 case 3:
127 rpc.num_ports = MIN(rpc.num_ports, 5);
128 break;
129 }
130
131 printk(BIOS_DEBUG, "Adjusted number of PCIe root ports to %d as per strpfusecfg2\n",
132 rpc.num_ports);
133}
134
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200135static void root_port_init_config(struct device *dev)
Aaron Durbinc0254e62013-06-20 01:20:30 -0500136{
137 int rp;
138
139 if (root_port_is_first(dev)) {
140 rpc.orig_rpfn = RCBA32(RPFN);
141 rpc.new_rpfn = rpc.orig_rpfn;
142 rpc.num_ports = max_root_ports();
143 rpc.gbe_port = -1;
144
145 rpc.pin_ownership = pci_read_config32(dev, 0x410);
146 root_port_config_update_gbe_port();
147
148 if (dev->chip_info != NULL) {
149 struct southbridge_intel_lynxpoint_config *config;
150
151 config = dev->chip_info;
152 rpc.coalesce = config->pcie_port_coalesce;
153 }
154 }
155
156 rp = root_port_number(dev);
157 if (rp > rpc.num_ports) {
158 printk(BIOS_ERR, "Found Root Port %d, expecting %d\n",
159 rp, rpc.num_ports);
160 return;
161 }
162
163 /* Read the fuse configuration and pin ownership. */
164 switch (rp) {
165 case 1:
166 rpc.strpfusecfg1 = pci_read_config32(dev, 0xfc);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800167 rpc.b0d28f0_32c = pci_read_config32(dev, 0x32c);
Aaron Durbinc0254e62013-06-20 01:20:30 -0500168 break;
169 case 5:
170 rpc.strpfusecfg2 = pci_read_config32(dev, 0xfc);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800171 rpc.b0d28f4_32c = pci_read_config32(dev, 0x32c);
Angel Pons12404e02020-08-04 00:26:45 +0200172
173 if (!pch_is_lp())
174 update_num_ports();
175
Aaron Durbinc0254e62013-06-20 01:20:30 -0500176 break;
177 case 6:
Stefan Reinauerab365af2013-12-03 12:13:26 -0800178 rpc.b0d28f5_32c = pci_read_config32(dev, 0x32c);
Aaron Durbinc0254e62013-06-20 01:20:30 -0500179 rpc.strpfusecfg3 = pci_read_config32(dev, 0xfc);
180 break;
181 default:
182 break;
183 }
184
185 /* Cache pci device. */
186 rpc.ports[rp - 1] = dev;
Aaron Durbin60f82082013-06-19 13:28:04 -0500187}
188
189/* Update devicetree with new Root Port function number assignment */
Aaron Durbinc0254e62013-06-20 01:20:30 -0500190static void pch_pcie_device_set_func(int index, int pci_func)
Aaron Durbin60f82082013-06-19 13:28:04 -0500191{
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200192 struct device *dev;
Martin Rothff744bf2019-10-23 21:46:03 -0600193 unsigned int new_devfn;
Aaron Durbin60f82082013-06-19 13:28:04 -0500194
Aaron Durbinc0254e62013-06-20 01:20:30 -0500195 dev = rpc.ports[index];
Aaron Durbin60f82082013-06-19 13:28:04 -0500196
Aaron Durbinc0254e62013-06-20 01:20:30 -0500197 /* Set the new PCI function field for this Root Port. */
198 rpc.new_rpfn &= ~RPFN_FNMASK(index);
199 rpc.new_rpfn |= RPFN_FNSET(index, pci_func);
Aaron Durbin60f82082013-06-19 13:28:04 -0500200
Aaron Durbinc0254e62013-06-20 01:20:30 -0500201 /* Determine the new devfn for this port */
202 new_devfn = PCI_DEVFN(PCH_PCIE_DEV_SLOT, pci_func);
Aaron Durbin60f82082013-06-19 13:28:04 -0500203
Tristan Corrick05b75242018-12-06 22:47:42 +1300204 if (dev && dev->path.pci.devfn != new_devfn) {
Aaron Durbinc0254e62013-06-20 01:20:30 -0500205 printk(BIOS_DEBUG,
206 "PCH: PCIe map %02x.%1x -> %02x.%1x\n",
207 PCI_SLOT(dev->path.pci.devfn),
208 PCI_FUNC(dev->path.pci.devfn),
209 PCI_SLOT(new_devfn), PCI_FUNC(new_devfn));
Aaron Durbin60f82082013-06-19 13:28:04 -0500210
Aaron Durbinc0254e62013-06-20 01:20:30 -0500211 dev->path.pci.devfn = new_devfn;
Aaron Durbin60f82082013-06-19 13:28:04 -0500212 }
213}
214
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500215static void pcie_enable_clock_gating(void)
216{
217 int i;
218 int is_lp;
219 int enabled_ports;
220
221 is_lp = pch_is_lp();
222 enabled_ports = 0;
223
224 for (i = 0; i < rpc.num_ports; i++) {
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200225 struct device *dev;
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500226 int rp;
227
228 dev = rpc.ports[i];
Tristan Corrick05b75242018-12-06 22:47:42 +1300229 if (!dev)
230 continue;
231
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500232 rp = root_port_number(dev);
233
Tristan Corrick05b75242018-12-06 22:47:42 +1300234 if (!is_rp_enabled(rp)) {
Ryan Salsamendi3f2fe182017-07-04 13:14:16 -0700235
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500236 /* Configure shared resource clock gating. */
237 if (rp == 1 || rp == 5 || (rp == 6 && is_lp))
Angel Ponsbf9bc502020-06-08 00:12:43 +0200238 pci_or_config8(dev, 0xe1, 0x3c);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500239
240 if (!is_lp) {
Tristan Corrick05b75242018-12-06 22:47:42 +1300241 if (rp == 1 && !is_rp_enabled(2) &&
242 !is_rp_enabled(3) && !is_rp_enabled(4)) {
Angel Ponsbf9bc502020-06-08 00:12:43 +0200243 pci_or_config8(dev, 0xe2, 1);
244 pci_or_config8(dev, 0xe1, 1 << 7);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500245 }
Tristan Corrick05b75242018-12-06 22:47:42 +1300246 if (rp == 5 && !is_rp_enabled(6) &&
247 !is_rp_enabled(7) && !is_rp_enabled(8)) {
Angel Ponsbf9bc502020-06-08 00:12:43 +0200248 pci_or_config8(dev, 0xe2, 1);
249 pci_or_config8(dev, 0xe1, 1 << 7);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500250 }
251 continue;
252 }
253
Angel Ponsbf9bc502020-06-08 00:12:43 +0200254 pci_or_config8(dev, 0xe2, 3 << 4);
255 pci_or_config32(dev, 0x420, 1 << 31);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500256
257 /* Per-Port CLKREQ# handling. */
258 if (is_lp && gpio_is_native(18 + rp - 1))
Angel Ponsbf9bc502020-06-08 00:12:43 +0200259 pci_or_config32(dev, 0x420, 3 << 29);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500260
261 /* Enable static clock gating. */
Tristan Corrick05b75242018-12-06 22:47:42 +1300262 if (rp == 1 && !is_rp_enabled(2) &&
263 !is_rp_enabled(3) && !is_rp_enabled(4)) {
Angel Ponsbf9bc502020-06-08 00:12:43 +0200264 pci_or_config8(dev, 0xe2, 1);
265 pci_or_config8(dev, 0xe1, 1 << 7);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500266 } else if (rp == 5 || rp == 6) {
Angel Ponsbf9bc502020-06-08 00:12:43 +0200267 pci_or_config8(dev, 0xe2, 1);
268 pci_or_config8(dev, 0xe1, 1 << 7);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500269 }
270 continue;
271 }
272
273 enabled_ports++;
274
275 /* Enable dynamic clock gating. */
Angel Ponsbf9bc502020-06-08 00:12:43 +0200276 pci_or_config8(dev, 0xe1, 0x03);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500277
278 if (is_lp) {
Angel Ponsbf9bc502020-06-08 00:12:43 +0200279 pci_or_config8(dev, 0xe2, 1 << 6);
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300280 pci_update_config8(dev, 0xe8, ~(3 << 2), (2 << 2));
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500281 }
282
283 /* Update PECR1 register. */
Angel Ponsbf9bc502020-06-08 00:12:43 +0200284 pci_or_config8(dev, 0xe8, 1);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500285
Angel Pons72f4dda2020-09-25 00:23:20 +0200286 pci_or_config8(dev, 0x324, 1 << 5);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500287
288 /* Per-Port CLKREQ# handling. */
289 if (is_lp && gpio_is_native(18 + rp - 1))
Angel Ponsbf9bc502020-06-08 00:12:43 +0200290 pci_or_config32(dev, 0x420, 3 << 29);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500291
292 /* Configure shared resource clock gating. */
293 if (rp == 1 || rp == 5 || (rp == 6 && is_lp))
Angel Ponsbf9bc502020-06-08 00:12:43 +0200294 pci_or_config8(dev, 0xe1, 0x3c);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500295 }
296
Tristan Corrick05b75242018-12-06 22:47:42 +1300297 if (!enabled_ports && is_lp && rpc.ports[0])
Angel Ponsbf9bc502020-06-08 00:12:43 +0200298 pci_or_config8(rpc.ports[0], 0xe1, 1 << 6);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500299}
300
Aaron Durbinc0254e62013-06-20 01:20:30 -0500301static void root_port_commit_config(void)
Aaron Durbin60f82082013-06-19 13:28:04 -0500302{
Aaron Durbinc0254e62013-06-20 01:20:30 -0500303 int i;
Aaron Durbin60f82082013-06-19 13:28:04 -0500304
Aaron Durbinc0254e62013-06-20 01:20:30 -0500305 /* If the first root port is disabled the coalesce ports. */
Tristan Corrick05b75242018-12-06 22:47:42 +1300306 if (!is_rp_enabled(1))
Angel Ponsaf4bd562021-12-28 13:05:56 +0100307 rpc.coalesce = true;
Aaron Durbin60f82082013-06-19 13:28:04 -0500308
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500309 /* Perform clock gating configuration. */
310 pcie_enable_clock_gating();
311
Aaron Durbinc0254e62013-06-20 01:20:30 -0500312 for (i = 0; i < rpc.num_ports; i++) {
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200313 struct device *dev;
Aaron Durbin60f82082013-06-19 13:28:04 -0500314
Aaron Durbinc0254e62013-06-20 01:20:30 -0500315 dev = rpc.ports[i];
Aaron Durbin60f82082013-06-19 13:28:04 -0500316
Aaron Durbinc0254e62013-06-20 01:20:30 -0500317 if (dev == NULL) {
318 printk(BIOS_ERR, "Root Port %d device is NULL?\n", i+1);
319 continue;
Aaron Durbin60f82082013-06-19 13:28:04 -0500320 }
321
Aaron Durbinc0254e62013-06-20 01:20:30 -0500322 if (dev->enabled)
323 continue;
324
325 printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
326
Aaron Durbin60f82082013-06-19 13:28:04 -0500327 /* Ensure memory, io, and bus master are all disabled */
Angel Ponsbf9bc502020-06-08 00:12:43 +0200328 pci_and_config16(dev, PCI_COMMAND,
329 ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO));
Aaron Durbin60f82082013-06-19 13:28:04 -0500330
Aaron Durbin60f82082013-06-19 13:28:04 -0500331 /* Disable this device if possible */
332 pch_disable_devfn(dev);
Aaron Durbin60f82082013-06-19 13:28:04 -0500333 }
334
Aaron Durbinc0254e62013-06-20 01:20:30 -0500335 if (rpc.coalesce) {
336 int current_func;
Aaron Durbin60f82082013-06-19 13:28:04 -0500337
Aaron Durbinc0254e62013-06-20 01:20:30 -0500338 /* For all Root Ports N enabled ports get assigned the lower
339 * PCI function number. The disabled ones get upper PCI
340 * function numbers. */
341 current_func = 0;
342 for (i = 0; i < rpc.num_ports; i++) {
Tristan Corrick05b75242018-12-06 22:47:42 +1300343 if (!is_rp_enabled(i + 1))
Aaron Durbinc0254e62013-06-20 01:20:30 -0500344 continue;
345 pch_pcie_device_set_func(i, current_func);
346 current_func++;
347 }
348
349 /* Allocate the disabled devices' PCI function number. */
350 for (i = 0; i < rpc.num_ports; i++) {
Tristan Corrick05b75242018-12-06 22:47:42 +1300351 if (is_rp_enabled(i + 1))
Aaron Durbinc0254e62013-06-20 01:20:30 -0500352 continue;
353 pch_pcie_device_set_func(i, current_func);
354 current_func++;
355 }
356 }
357
358 printk(BIOS_SPEW, "PCH: RPFN 0x%08x -> 0x%08x\n",
359 rpc.orig_rpfn, rpc.new_rpfn);
360 RCBA32(RPFN) = rpc.new_rpfn;
361}
362
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200363static void root_port_mark_disable(struct device *dev)
Aaron Durbinc0254e62013-06-20 01:20:30 -0500364{
365 /* Mark device as disabled. */
366 dev->enabled = 0;
367 /* Mark device to be hidden. */
368 rpc.new_rpfn |= RPFN_HIDE(PCI_FUNC(dev->path.pci.devfn));
369}
370
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200371static void root_port_check_disable(struct device *dev)
Aaron Durbinc0254e62013-06-20 01:20:30 -0500372{
373 int rp;
374 int is_lp;
375
376 /* Device already disabled. */
377 if (!dev->enabled) {
378 root_port_mark_disable(dev);
379 return;
380 }
381
382 rp = root_port_number(dev);
383
384 /* Is the GbE port mapped to this Root Port? */
385 if (rp == rpc.gbe_port) {
386 root_port_mark_disable(dev);
387 return;
388 }
389
390 is_lp = pch_is_lp();
391
392 /* Check Root Port Configuration. */
393 switch (rp) {
394 case 2:
395 /* Root Port 2 is disabled for all lane configurations
396 * but config 00b (4x1 links). */
397 if ((rpc.strpfusecfg1 >> 14) & 0x3) {
398 root_port_mark_disable(dev);
399 return;
400 }
401 break;
402 case 3:
403 /* Root Port 3 is disabled in config 11b (1x4 links). */
404 if (((rpc.strpfusecfg1 >> 14) & 0x3) == 0x3) {
405 root_port_mark_disable(dev);
406 return;
407 }
408 break;
409 case 4:
410 /* Root Port 4 is disabled in configs 11b (1x4 links)
411 * and 10b (2x2 links). */
412 if ((rpc.strpfusecfg1 >> 14) & 0x2) {
413 root_port_mark_disable(dev);
414 return;
415 }
416 break;
417 case 6:
418 if (is_lp)
419 break;
420 /* Root Port 6 is disabled for all lane configurations
421 * but config 00b (4x1 links). */
422 if ((rpc.strpfusecfg2 >> 14) & 0x3) {
423 root_port_mark_disable(dev);
424 return;
425 }
426 break;
427 case 7:
428 if (is_lp)
429 break;
Tristan Corrickbaa4c072018-12-06 22:47:21 +1300430 /* Root Port 7 is disabled in config 11b (1x4 links). */
Aaron Durbinc0254e62013-06-20 01:20:30 -0500431 if (((rpc.strpfusecfg2 >> 14) & 0x3) == 0x3) {
432 root_port_mark_disable(dev);
433 return;
434 }
435 break;
436 case 8:
437 if (is_lp)
438 break;
439 /* Root Port 8 is disabled in configs 11b (1x4 links)
440 * and 10b (2x2 links). */
441 if ((rpc.strpfusecfg2 >> 14) & 0x2) {
442 root_port_mark_disable(dev);
443 return;
444 }
445 break;
446 }
447
448 /* Check Pin Ownership. */
449 if (is_lp) {
450 switch (rp) {
451 case 1:
452 /* Bit 0 is Root Port 1 ownership. */
453 if ((rpc.pin_ownership & 0x1) == 0) {
454 root_port_mark_disable(dev);
455 return;
456 }
457 break;
458 case 2:
459 /* Bit 2 is Root Port 2 ownership. */
460 if ((rpc.pin_ownership & 0x4) == 0) {
461 root_port_mark_disable(dev);
462 return;
463 }
464 break;
465 case 6:
466 /* Bits 7:4 are Root Port 6 pin-lane ownership. */
467 if ((rpc.pin_ownership & 0xf0) == 0) {
468 root_port_mark_disable(dev);
469 return;
470 }
471 break;
472 }
473 } else {
474 switch (rp) {
475 case 1:
476 /* Bits 4 and 0 are Root Port 1 ownership. */
477 if ((rpc.pin_ownership & 0x11) == 0) {
478 root_port_mark_disable(dev);
479 return;
480 }
481 break;
482 case 2:
483 /* Bits 5 and 2 are Root Port 2 ownership. */
484 if ((rpc.pin_ownership & 0x24) == 0) {
485 root_port_mark_disable(dev);
486 return;
487 }
488 break;
489 }
Aaron Durbin60f82082013-06-19 13:28:04 -0500490 }
491}
492
Stefan Reinauerab365af2013-12-03 12:13:26 -0800493static void pcie_add_0x0202000_iobp(u32 reg)
494{
495 u32 reg32;
Aaron Durbin76c37002012-10-30 09:03:43 -0500496
Stefan Reinauerab365af2013-12-03 12:13:26 -0800497 reg32 = pch_iobp_read(reg);
498 reg32 += (0x2 << 16) | (0x2 << 8);
499 pch_iobp_write(reg, reg32);
500}
Aaron Durbin76c37002012-10-30 09:03:43 -0500501
Stefan Reinauerab365af2013-12-03 12:13:26 -0800502static void pch_pcie_early(struct device *dev)
503{
Duncan Laurie249a03b2013-08-09 09:06:41 -0700504 struct southbridge_intel_lynxpoint_config *config = dev->chip_info;
Angel Pons2aaf7c02020-09-24 18:03:18 +0200505 int do_aspm = 0;
506 int rp = root_port_number(dev);
507 int is_lp = pch_is_lp();
Aaron Durbin76c37002012-10-30 09:03:43 -0500508
Stefan Reinauerab365af2013-12-03 12:13:26 -0800509 if (is_lp) {
510 switch (rp) {
511 case 1:
512 case 2:
513 case 3:
514 case 4:
Angel Pons2aaf7c02020-09-24 18:03:18 +0200515 /*
516 * Bits 31:28 of b0d28f0 0x32c register correspond to
517 * Root Ports 4:1.
518 */
Stefan Reinauerab365af2013-12-03 12:13:26 -0800519 do_aspm = !!(rpc.b0d28f0_32c & (1 << (28 + rp - 1)));
520 break;
521 case 5:
Angel Pons2aaf7c02020-09-24 18:03:18 +0200522 /*
523 * Bit 28 of b0d28f4 0x32c register correspond to
524 * Root Ports 4:1.
525 */
Stefan Reinauerab365af2013-12-03 12:13:26 -0800526 do_aspm = !!(rpc.b0d28f4_32c & (1 << 28));
527 break;
528 case 6:
Angel Pons2aaf7c02020-09-24 18:03:18 +0200529 /*
530 * Bit 28 of b0d28f5 0x32c register correspond to
531 * Root Ports 4:1.
532 */
Stefan Reinauerab365af2013-12-03 12:13:26 -0800533 do_aspm = !!(rpc.b0d28f5_32c & (1 << 28));
534 break;
535 }
536 } else {
537 switch (rp) {
538 case 1:
539 case 2:
540 case 3:
541 case 4:
Angel Pons2aaf7c02020-09-24 18:03:18 +0200542 /*
543 * Bits 31:28 of b0d28f0 0x32c register correspond to
544 * Root Ports 4:1.
545 */
Stefan Reinauerab365af2013-12-03 12:13:26 -0800546 do_aspm = !!(rpc.b0d28f0_32c & (1 << (28 + rp - 1)));
547 break;
548 case 5:
549 case 6:
550 case 7:
551 case 8:
Angel Pons2aaf7c02020-09-24 18:03:18 +0200552 /*
553 * Bits 31:28 of b0d28f4 0x32c register correspond to
554 * Root Ports 8:5.
555 */
Stefan Reinauerab365af2013-12-03 12:13:26 -0800556 do_aspm = !!(rpc.b0d28f4_32c & (1 << (28 + rp - 5)));
557 break;
558 }
Aaron Durbin76c37002012-10-30 09:03:43 -0500559 }
Stefan Reinauerab365af2013-12-03 12:13:26 -0800560
Duncan Laurie249a03b2013-08-09 09:06:41 -0700561 /* Allow ASPM to be forced on in devicetree */
562 if (config && (config->pcie_port_force_aspm & (1 << (rp - 1))))
563 do_aspm = 1;
564
565 printk(BIOS_DEBUG, "PCIe Root Port %d ASPM is %sabled\n",
566 rp, do_aspm ? "en" : "dis");
567
Stefan Reinauerab365af2013-12-03 12:13:26 -0800568 if (do_aspm) {
569 /* Set ASPM bits in MPC2 register. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300570 pci_update_config32(dev, 0xd4, ~(0x3 << 2), (1 << 4) | (0x2 << 2));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800571
572 /* Set unique clock exit latency in MPC register. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300573 pci_update_config32(dev, 0xd8, ~(0x7 << 18), (0x7 << 18));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800574
575 /* Set L1 exit latency in LCAP register. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300576 pci_update_config32(dev, 0x4c, ~(0x7 << 15), (0x4 << 15));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800577
578 if (is_lp) {
579 switch (rp) {
580 case 1:
581 pcie_add_0x0202000_iobp(0xe9002440);
582 break;
583 case 2:
584 pcie_add_0x0202000_iobp(0xe9002640);
585 break;
586 case 3:
587 pcie_add_0x0202000_iobp(0xe9000840);
588 break;
589 case 4:
590 pcie_add_0x0202000_iobp(0xe9000a40);
591 break;
592 case 5:
593 pcie_add_0x0202000_iobp(0xe9000c40);
594 pcie_add_0x0202000_iobp(0xe9000e40);
595 pcie_add_0x0202000_iobp(0xe9001040);
596 pcie_add_0x0202000_iobp(0xe9001240);
597 break;
598 case 6:
599 /* Update IOBP based on lane ownership. */
600 if (rpc.pin_ownership & (1 << 4))
601 pcie_add_0x0202000_iobp(0xea002040);
602 if (rpc.pin_ownership & (1 << 5))
603 pcie_add_0x0202000_iobp(0xea002240);
604 if (rpc.pin_ownership & (1 << 6))
605 pcie_add_0x0202000_iobp(0xea002440);
606 if (rpc.pin_ownership & (1 << 7))
607 pcie_add_0x0202000_iobp(0xea002640);
608 break;
609 }
610 } else {
611 switch (rp) {
612 case 1:
613 if ((rpc.pin_ownership & 0x3) == 1)
614 pcie_add_0x0202000_iobp(0xe9002e40);
615 else
616 pcie_add_0x0202000_iobp(0xea002040);
617 break;
618 case 2:
619 if ((rpc.pin_ownership & 0xc) == 0x4)
620 pcie_add_0x0202000_iobp(0xe9002c40);
621 else
622 pcie_add_0x0202000_iobp(0xea002240);
623 break;
624 case 3:
625 pcie_add_0x0202000_iobp(0xe9002a40);
626 break;
627 case 4:
628 pcie_add_0x0202000_iobp(0xe9002840);
629 break;
630 case 5:
631 pcie_add_0x0202000_iobp(0xe9002640);
632 break;
633 case 6:
634 pcie_add_0x0202000_iobp(0xe9002440);
635 break;
636 case 7:
637 pcie_add_0x0202000_iobp(0xe9002240);
638 break;
639 case 8:
640 pcie_add_0x0202000_iobp(0xe9002040);
641 break;
642 }
643 }
644
Angel Ponsbf9bc502020-06-08 00:12:43 +0200645 pci_and_config32(dev, 0x338, ~(1 << 26));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800646 }
647
Angel Ponsa575759c2020-11-05 11:35:54 +0100648 /* Enable LTR in Root Port. Disable OBFF. */
649 pci_update_config32(dev, 0x64, ~(3 << 18), 1 << 11);
650 pci_update_config16(dev, 0x68, ~(3 << 13), 1 << 10);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800651
Angel Pons2aaf7c02020-09-24 18:03:18 +0200652 pci_update_config32(dev, 0x318, ~(0xffff << 16), (0x1414 << 16));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800653
654 /* Set L1 exit latency in LCAP register. */
655 if (!do_aspm && (pci_read_config8(dev, 0xf5) & 0x1))
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300656 pci_update_config32(dev, 0x4c, ~(0x7 << 15), (0x4 << 15));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800657 else
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300658 pci_update_config32(dev, 0x4c, ~(0x7 << 15), (0x2 << 15));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800659
Angel Ponsbf9bc502020-06-08 00:12:43 +0200660 pci_update_config32(dev, 0x314, 0, 0x743a361b);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800661
662 /* Set Common Clock Exit Latency in MPC register. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300663 pci_update_config32(dev, 0xd8, ~(0x7 << 15), (0x3 << 15));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800664
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300665 pci_update_config32(dev, 0x33c, ~0x00ffffff, 0x854c74);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800666
Matt DeVillier1aeccd12020-10-07 13:18:55 -0500667 /* Set Invalid Receive Range Check Enable in MPC register. */
Angel Ponsbf9bc502020-06-08 00:12:43 +0200668 pci_or_config32(dev, 0xd8, 1 << 25);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800669
Angel Ponsbf9bc502020-06-08 00:12:43 +0200670 pci_and_config8(dev, 0xf5, 0x3f);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800671
672 if (rp == 1 || rp == 5 || (is_lp && rp == 6))
Angel Ponsbf9bc502020-06-08 00:12:43 +0200673 pci_and_config8(dev, 0xf7, ~0x0c);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800674
675 /* Set EOI forwarding disable. */
Angel Ponsbf9bc502020-06-08 00:12:43 +0200676 pci_or_config32(dev, 0xd4, 1 << 1);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800677
Matt DeVillier7f633532020-10-07 13:11:58 -0500678 /* Set AER Extended Cap ID to 01h and Next Cap Pointer to 200h. */
679 if (CONFIG(PCIEXP_AER))
680 pci_update_config32(dev, 0x100, ~0xfffff, (1 << 29) | 0x10001);
681 else
682 pci_update_config32(dev, 0x100, ~0xfffff, (1 << 29));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800683
Matt DeVillier54e1f592020-10-07 13:17:09 -0500684 /* Set L1 Sub-State Cap ID to 1Eh and Next Cap Pointer to None. */
685 if (CONFIG(PCIEXP_L1_SUB_STATE))
686 pci_update_config32(dev, 0x200, ~0xfffff, 0x001e);
687 else
688 pci_update_config32(dev, 0x200, ~0xfffff, 0);
689
Stefan Reinauerab365af2013-12-03 12:13:26 -0800690 if (is_lp)
Angel Ponsbf9bc502020-06-08 00:12:43 +0200691 pci_or_config32(dev, 0x100, 1 << 29);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800692
693 /* Read and write back write-once capability registers. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300694 pci_update_config32(dev, 0x34, ~0, 0);
695 pci_update_config32(dev, 0x40, ~0, 0);
696 pci_update_config32(dev, 0x80, ~0, 0);
697 pci_update_config32(dev, 0x90, ~0, 0);
Aaron Durbin76c37002012-10-30 09:03:43 -0500698}
699
Angel Pons2aaf7c02020-09-24 18:03:18 +0200700static void pch_pcie_init(struct device *dev)
Aaron Durbin76c37002012-10-30 09:03:43 -0500701{
Aaron Durbin76c37002012-10-30 09:03:43 -0500702 printk(BIOS_DEBUG, "Initializing PCH PCIe bridge.\n");
703
Aaron Durbinc0254e62013-06-20 01:20:30 -0500704 /* Enable SERR */
Elyes HAOUAS73ae0762020-04-28 10:13:05 +0200705 pci_or_config16(dev, PCI_COMMAND, PCI_COMMAND_SERR);
Aaron Durbinc0254e62013-06-20 01:20:30 -0500706
Aaron Durbin76c37002012-10-30 09:03:43 -0500707 /* Enable Bus Master */
Elyes HAOUAS73ae0762020-04-28 10:13:05 +0200708 pci_or_config16(dev, PCI_COMMAND, PCI_COMMAND_MASTER);
Aaron Durbin76c37002012-10-30 09:03:43 -0500709
710 /* Set Cache Line Size to 0x10 */
711 // This has no effect but the OS might expect it
712 pci_write_config8(dev, 0x0c, 0x10);
713
Angel Ponsbf9bc502020-06-08 00:12:43 +0200714 pci_and_config16(dev, PCI_BRIDGE_CONTROL, ~PCI_BRIDGE_CTL_PARITY);
Aaron Durbin76c37002012-10-30 09:03:43 -0500715
Aaron Durbin76c37002012-10-30 09:03:43 -0500716 /* Clear errors in status registers */
Angel Ponsbf9bc502020-06-08 00:12:43 +0200717 pci_update_config16(dev, 0x06, ~0, 0);
718 pci_update_config16(dev, 0x1e, ~0, 0);
Aaron Durbin76c37002012-10-30 09:03:43 -0500719}
720
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200721static void pch_pcie_enable(struct device *dev)
Aaron Durbin76c37002012-10-30 09:03:43 -0500722{
Aaron Durbinc0254e62013-06-20 01:20:30 -0500723 /* Add this device to the root port config structure. */
724 root_port_init_config(dev);
725
726 /* Check to see if this Root Port should be disabled. */
727 root_port_check_disable(dev);
728
Aaron Durbin76c37002012-10-30 09:03:43 -0500729 /* Power Management init before enumeration */
Aaron Durbinc0254e62013-06-20 01:20:30 -0500730 if (dev->enabled)
Stefan Reinauerab365af2013-12-03 12:13:26 -0800731 pch_pcie_early(dev);
Aaron Durbinc0254e62013-06-20 01:20:30 -0500732
733 /*
734 * When processing the last PCIe root port we can now
735 * update the Root Port Function Number and Hide register.
736 */
737 if (root_port_is_last(dev))
738 root_port_commit_config();
Aaron Durbin76c37002012-10-30 09:03:43 -0500739}
740
Aaron Durbin76c37002012-10-30 09:03:43 -0500741static struct device_operations device_ops = {
742 .read_resources = pci_bus_read_resources,
743 .set_resources = pci_dev_set_resources,
744 .enable_resources = pci_bus_enable_resources,
Angel Pons2aaf7c02020-09-24 18:03:18 +0200745 .init = pch_pcie_init,
Aaron Durbin76c37002012-10-30 09:03:43 -0500746 .enable = pch_pcie_enable,
747 .scan_bus = pciexp_scan_bridge,
Angel Pons1fc0edd2020-05-31 00:03:28 +0200748 .ops_pci = &pci_dev_ops_pci,
Aaron Durbin76c37002012-10-30 09:03:43 -0500749};
750
Duncan Laurie74c0d052012-12-17 11:31:40 -0800751static const unsigned short pci_device_ids[] = {
Felix Singer43b7f412022-03-07 04:34:52 +0100752 PCI_DID_INTEL_LPT_H_PCIE_RP1,
753 PCI_DID_INTEL_LPT_H_PCIE_RP2,
754 PCI_DID_INTEL_LPT_H_PCIE_RP3,
755 PCI_DID_INTEL_LPT_H_PCIE_RP4,
756 PCI_DID_INTEL_LPT_H_PCIE_RP5,
757 PCI_DID_INTEL_LPT_H_PCIE_RP6,
758 PCI_DID_INTEL_LPT_H_PCIE_RP7,
759 PCI_DID_INTEL_LPT_H_PCIE_RP8,
760 PCI_DID_INTEL_LPT_LP_PCIE_RP1,
761 PCI_DID_INTEL_LPT_LP_PCIE_RP2,
762 PCI_DID_INTEL_LPT_LP_PCIE_RP3,
763 PCI_DID_INTEL_LPT_LP_PCIE_RP4,
764 PCI_DID_INTEL_LPT_LP_PCIE_RP5,
765 PCI_DID_INTEL_LPT_LP_PCIE_RP6,
Duncan Laurie74c0d052012-12-17 11:31:40 -0800766 0
767};
Aaron Durbin76c37002012-10-30 09:03:43 -0500768
769static const struct pci_driver pch_pcie __pci_driver = {
770 .ops = &device_ops,
Felix Singer43b7f412022-03-07 04:34:52 +0100771 .vendor = PCI_VID_INTEL,
Aaron Durbin76c37002012-10-30 09:03:43 -0500772 .devices = pci_device_ids,
773};