blob: 0ca49b802c28cf119aabbf7c077f3e926dd92e7a [file] [log] [blame]
Angel Pons182dbde2020-04-02 23:49:05 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
Aaron Durbin76c37002012-10-30 09:03:43 -05003
Tristan Corrick05b75242018-12-06 22:47:42 +13004#include <assert.h>
5#include <commonlib/helpers.h>
Aaron Durbin76c37002012-10-30 09:03:43 -05006#include <console/console.h>
7#include <device/device.h>
8#include <device/pci.h>
Kyösti Mälkkidf128a52019-09-21 18:35:37 +03009#include <device/pci_def.h>
Aaron Durbin76c37002012-10-30 09:03:43 -050010#include <device/pciexp.h>
11#include <device/pci_ids.h>
Patrick Rudolphe56189c2018-04-18 10:11:59 +020012#include <device/pci_ops.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 <stddef.h>
16#include <stdint.h>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030017#include "chip.h"
Aaron Durbin76c37002012-10-30 09:03:43 -050018
Aaron Durbinc0254e62013-06-20 01:20:30 -050019#define MAX_NUM_ROOT_PORTS 8
Aaron Durbinc0254e62013-06-20 01:20:30 -050020
21struct root_port_config {
22 /* RPFN is a write-once register so keep a copy until it is written */
23 u32 orig_rpfn;
24 u32 new_rpfn;
25 u32 pin_ownership;
26 u32 strpfusecfg1;
27 u32 strpfusecfg2;
28 u32 strpfusecfg3;
Stefan Reinauerab365af2013-12-03 12:13:26 -080029 u32 b0d28f0_32c;
30 u32 b0d28f4_32c;
31 u32 b0d28f5_32c;
Aaron Durbinc0254e62013-06-20 01:20:30 -050032 int coalesce;
33 int gbe_port;
34 int num_ports;
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +020035 struct device *ports[MAX_NUM_ROOT_PORTS];
Aaron Durbinc0254e62013-06-20 01:20:30 -050036};
37
38static struct root_port_config rpc;
39
40static inline int max_root_ports(void)
Aaron Durbin60f82082013-06-19 13:28:04 -050041{
Tristan Corrickd3f01b22018-12-06 22:46:58 +130042 if (pch_is_lp() || pch_silicon_id() == PCI_DEVICE_ID_INTEL_LPT_H81)
43 return 6;
44
45 return 8;
Aaron Durbin60f82082013-06-19 13:28:04 -050046}
47
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +020048static inline int root_port_is_first(struct device *dev)
Aaron Durbin60f82082013-06-19 13:28:04 -050049{
Aaron Durbinc0254e62013-06-20 01:20:30 -050050 return PCI_FUNC(dev->path.pci.devfn) == 0;
51}
Aaron Durbin60f82082013-06-19 13:28:04 -050052
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +020053static inline int root_port_is_last(struct device *dev)
Aaron Durbinc0254e62013-06-20 01:20:30 -050054{
55 return PCI_FUNC(dev->path.pci.devfn) == (rpc.num_ports - 1);
56}
Aaron Durbin60f82082013-06-19 13:28:04 -050057
Aaron Durbinc0254e62013-06-20 01:20:30 -050058/* Root ports are numbered 1..N in the documentation. */
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +020059static inline int root_port_number(struct device *dev)
Aaron Durbinc0254e62013-06-20 01:20:30 -050060{
61 return PCI_FUNC(dev->path.pci.devfn) + 1;
62}
Aaron Durbin60f82082013-06-19 13:28:04 -050063
Tristan Corrick05b75242018-12-06 22:47:42 +130064static bool is_rp_enabled(int rp)
65{
66 ASSERT(rp > 0 && rp <= ARRAY_SIZE(rpc.ports));
67
68 if (rpc.ports[rp - 1] == NULL)
69 return false;
70
71 return rpc.ports[rp - 1]->enabled;
72}
73
Aaron Durbinc0254e62013-06-20 01:20:30 -050074static void root_port_config_update_gbe_port(void)
75{
76 /* Is the Gbe Port enabled? */
77 if (!((rpc.strpfusecfg1 >> 19) & 1))
78 return;
79
80 if (pch_is_lp()) {
81 switch ((rpc.strpfusecfg1 >> 16) & 0x7) {
82 case 0:
83 rpc.gbe_port = 3;
84 break;
85 case 1:
86 rpc.gbe_port = 4;
87 break;
88 case 2:
89 case 3:
90 case 4:
91 case 5:
92 /* Lanes 0-4 of Root Port 5. */
93 rpc.gbe_port = 5;
94 break;
95 default:
96 printk(BIOS_DEBUG, "Invalid GbE Port Selection.\n");
97 }
98 } else {
99 /* Non-LP has 1:1 mapping with root ports. */
100 rpc.gbe_port = ((rpc.strpfusecfg1 >> 16) & 0x7) + 1;
101 }
102}
103
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200104static void root_port_init_config(struct device *dev)
Aaron Durbinc0254e62013-06-20 01:20:30 -0500105{
106 int rp;
107
108 if (root_port_is_first(dev)) {
109 rpc.orig_rpfn = RCBA32(RPFN);
110 rpc.new_rpfn = rpc.orig_rpfn;
111 rpc.num_ports = max_root_ports();
112 rpc.gbe_port = -1;
113
114 rpc.pin_ownership = pci_read_config32(dev, 0x410);
115 root_port_config_update_gbe_port();
116
117 if (dev->chip_info != NULL) {
118 struct southbridge_intel_lynxpoint_config *config;
119
120 config = dev->chip_info;
121 rpc.coalesce = config->pcie_port_coalesce;
122 }
123 }
124
125 rp = root_port_number(dev);
126 if (rp > rpc.num_ports) {
127 printk(BIOS_ERR, "Found Root Port %d, expecting %d\n",
128 rp, rpc.num_ports);
129 return;
130 }
131
132 /* Read the fuse configuration and pin ownership. */
133 switch (rp) {
134 case 1:
135 rpc.strpfusecfg1 = pci_read_config32(dev, 0xfc);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800136 rpc.b0d28f0_32c = pci_read_config32(dev, 0x32c);
Aaron Durbinc0254e62013-06-20 01:20:30 -0500137 break;
138 case 5:
139 rpc.strpfusecfg2 = pci_read_config32(dev, 0xfc);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800140 rpc.b0d28f4_32c = pci_read_config32(dev, 0x32c);
Aaron Durbinc0254e62013-06-20 01:20:30 -0500141 break;
142 case 6:
Stefan Reinauerab365af2013-12-03 12:13:26 -0800143 rpc.b0d28f5_32c = pci_read_config32(dev, 0x32c);
Aaron Durbinc0254e62013-06-20 01:20:30 -0500144 rpc.strpfusecfg3 = pci_read_config32(dev, 0xfc);
145 break;
146 default:
147 break;
148 }
149
150 /* Cache pci device. */
151 rpc.ports[rp - 1] = dev;
Aaron Durbin60f82082013-06-19 13:28:04 -0500152}
153
154/* Update devicetree with new Root Port function number assignment */
Aaron Durbinc0254e62013-06-20 01:20:30 -0500155static void pch_pcie_device_set_func(int index, int pci_func)
Aaron Durbin60f82082013-06-19 13:28:04 -0500156{
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200157 struct device *dev;
Martin Rothff744bf2019-10-23 21:46:03 -0600158 unsigned int new_devfn;
Aaron Durbin60f82082013-06-19 13:28:04 -0500159
Aaron Durbinc0254e62013-06-20 01:20:30 -0500160 dev = rpc.ports[index];
Aaron Durbin60f82082013-06-19 13:28:04 -0500161
Aaron Durbinc0254e62013-06-20 01:20:30 -0500162 /* Set the new PCI function field for this Root Port. */
163 rpc.new_rpfn &= ~RPFN_FNMASK(index);
164 rpc.new_rpfn |= RPFN_FNSET(index, pci_func);
Aaron Durbin60f82082013-06-19 13:28:04 -0500165
Aaron Durbinc0254e62013-06-20 01:20:30 -0500166 /* Determine the new devfn for this port */
167 new_devfn = PCI_DEVFN(PCH_PCIE_DEV_SLOT, pci_func);
Aaron Durbin60f82082013-06-19 13:28:04 -0500168
Tristan Corrick05b75242018-12-06 22:47:42 +1300169 if (dev && dev->path.pci.devfn != new_devfn) {
Aaron Durbinc0254e62013-06-20 01:20:30 -0500170 printk(BIOS_DEBUG,
171 "PCH: PCIe map %02x.%1x -> %02x.%1x\n",
172 PCI_SLOT(dev->path.pci.devfn),
173 PCI_FUNC(dev->path.pci.devfn),
174 PCI_SLOT(new_devfn), PCI_FUNC(new_devfn));
Aaron Durbin60f82082013-06-19 13:28:04 -0500175
Aaron Durbinc0254e62013-06-20 01:20:30 -0500176 dev->path.pci.devfn = new_devfn;
Aaron Durbin60f82082013-06-19 13:28:04 -0500177 }
178}
179
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500180static void pcie_enable_clock_gating(void)
181{
182 int i;
183 int is_lp;
184 int enabled_ports;
185
186 is_lp = pch_is_lp();
187 enabled_ports = 0;
188
189 for (i = 0; i < rpc.num_ports; i++) {
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200190 struct device *dev;
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500191 int rp;
192
193 dev = rpc.ports[i];
Tristan Corrick05b75242018-12-06 22:47:42 +1300194 if (!dev)
195 continue;
196
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500197 rp = root_port_number(dev);
198
Tristan Corrick05b75242018-12-06 22:47:42 +1300199 if (!is_rp_enabled(rp)) {
Ryan Salsamendi3f2fe182017-07-04 13:14:16 -0700200 static const uint32_t high_bit = (1UL << 31);
201
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500202 /* Configure shared resource clock gating. */
203 if (rp == 1 || rp == 5 || (rp == 6 && is_lp))
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300204 pci_update_config8(dev, 0xe1, 0xc3, 0x3c);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500205
206 if (!is_lp) {
Tristan Corrick05b75242018-12-06 22:47:42 +1300207 if (rp == 1 && !is_rp_enabled(2) &&
208 !is_rp_enabled(3) && !is_rp_enabled(4)) {
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300209 pci_update_config8(dev, 0xe2, ~1, 1);
210 pci_update_config8(dev, 0xe1, 0x7f, 0x80);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500211 }
Tristan Corrick05b75242018-12-06 22:47:42 +1300212 if (rp == 5 && !is_rp_enabled(6) &&
213 !is_rp_enabled(7) && !is_rp_enabled(8)) {
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300214 pci_update_config8(dev, 0xe2, ~1, 1);
215 pci_update_config8(dev, 0xe1, 0x7f, 0x80);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500216 }
217 continue;
218 }
219
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300220 pci_update_config8(dev, 0xe2, ~(3 << 4), (3 << 4));
Ryan Salsamendi3f2fe182017-07-04 13:14:16 -0700221 pci_update_config32(dev, 0x420, ~high_bit, high_bit);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500222
223 /* Per-Port CLKREQ# handling. */
224 if (is_lp && gpio_is_native(18 + rp - 1))
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300225 pci_update_config32(dev, 0x420, ~0, (3 << 29));
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500226
227 /* Enable static clock gating. */
Tristan Corrick05b75242018-12-06 22:47:42 +1300228 if (rp == 1 && !is_rp_enabled(2) &&
229 !is_rp_enabled(3) && !is_rp_enabled(4)) {
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300230 pci_update_config8(dev, 0xe2, ~1, 1);
231 pci_update_config8(dev, 0xe1, 0x7f, 0x80);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500232 } else if (rp == 5 || rp == 6) {
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300233 pci_update_config8(dev, 0xe2, ~1, 1);
234 pci_update_config8(dev, 0xe1, 0x7f, 0x80);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500235 }
236 continue;
237 }
238
239 enabled_ports++;
240
241 /* Enable dynamic clock gating. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300242 pci_update_config8(dev, 0xe1, 0xfc, 0x03);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500243
244 if (is_lp) {
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300245 pci_update_config8(dev, 0xe2, ~(1 << 6), (1 << 6));
246 pci_update_config8(dev, 0xe8, ~(3 << 2), (2 << 2));
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500247 }
248
249 /* Update PECR1 register. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300250 pci_update_config8(dev, 0xe8, ~0, 1);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500251
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300252 pci_update_config8(dev, 0x324, ~(1 << 5), (1 < 5));
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500253
254 /* Per-Port CLKREQ# handling. */
255 if (is_lp && gpio_is_native(18 + rp - 1))
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300256 pci_update_config32(dev, 0x420, ~0, (3 << 29));
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500257
258 /* Configure shared resource clock gating. */
259 if (rp == 1 || rp == 5 || (rp == 6 && is_lp))
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300260 pci_update_config8(dev, 0xe1, 0xc3, 0x3c);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500261 }
262
Tristan Corrick05b75242018-12-06 22:47:42 +1300263 if (!enabled_ports && is_lp && rpc.ports[0])
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300264 pci_update_config8(rpc.ports[0], 0xe1, ~(1 << 6), (1 << 6));
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500265}
266
Aaron Durbinc0254e62013-06-20 01:20:30 -0500267static void root_port_commit_config(void)
Aaron Durbin60f82082013-06-19 13:28:04 -0500268{
Aaron Durbinc0254e62013-06-20 01:20:30 -0500269 int i;
Aaron Durbin60f82082013-06-19 13:28:04 -0500270
Aaron Durbinc0254e62013-06-20 01:20:30 -0500271 /* If the first root port is disabled the coalesce ports. */
Tristan Corrick05b75242018-12-06 22:47:42 +1300272 if (!is_rp_enabled(1))
Aaron Durbinc0254e62013-06-20 01:20:30 -0500273 rpc.coalesce = 1;
Aaron Durbin60f82082013-06-19 13:28:04 -0500274
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500275 /* Perform clock gating configuration. */
276 pcie_enable_clock_gating();
277
Aaron Durbinc0254e62013-06-20 01:20:30 -0500278 for (i = 0; i < rpc.num_ports; i++) {
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200279 struct device *dev;
Aaron Durbinc0254e62013-06-20 01:20:30 -0500280 u32 reg32;
Aaron Durbin60f82082013-06-19 13:28:04 -0500281
Aaron Durbinc0254e62013-06-20 01:20:30 -0500282 dev = rpc.ports[i];
Aaron Durbin60f82082013-06-19 13:28:04 -0500283
Aaron Durbinc0254e62013-06-20 01:20:30 -0500284 if (dev == NULL) {
285 printk(BIOS_ERR, "Root Port %d device is NULL?\n", i+1);
286 continue;
Aaron Durbin60f82082013-06-19 13:28:04 -0500287 }
288
Aaron Durbinc0254e62013-06-20 01:20:30 -0500289 if (dev->enabled)
290 continue;
291
292 printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
293
Aaron Durbin60f82082013-06-19 13:28:04 -0500294 /* Ensure memory, io, and bus master are all disabled */
295 reg32 = pci_read_config32(dev, PCI_COMMAND);
296 reg32 &= ~(PCI_COMMAND_MASTER |
297 PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
298 pci_write_config32(dev, PCI_COMMAND, reg32);
299
Aaron Durbin60f82082013-06-19 13:28:04 -0500300 /* Disable this device if possible */
301 pch_disable_devfn(dev);
Aaron Durbin60f82082013-06-19 13:28:04 -0500302 }
303
Aaron Durbinc0254e62013-06-20 01:20:30 -0500304 if (rpc.coalesce) {
305 int current_func;
Aaron Durbin60f82082013-06-19 13:28:04 -0500306
Aaron Durbinc0254e62013-06-20 01:20:30 -0500307 /* For all Root Ports N enabled ports get assigned the lower
308 * PCI function number. The disabled ones get upper PCI
309 * function numbers. */
310 current_func = 0;
311 for (i = 0; i < rpc.num_ports; i++) {
Tristan Corrick05b75242018-12-06 22:47:42 +1300312 if (!is_rp_enabled(i + 1))
Aaron Durbinc0254e62013-06-20 01:20:30 -0500313 continue;
314 pch_pcie_device_set_func(i, current_func);
315 current_func++;
316 }
317
318 /* Allocate the disabled devices' PCI function number. */
319 for (i = 0; i < rpc.num_ports; i++) {
Tristan Corrick05b75242018-12-06 22:47:42 +1300320 if (is_rp_enabled(i + 1))
Aaron Durbinc0254e62013-06-20 01:20:30 -0500321 continue;
322 pch_pcie_device_set_func(i, current_func);
323 current_func++;
324 }
325 }
326
327 printk(BIOS_SPEW, "PCH: RPFN 0x%08x -> 0x%08x\n",
328 rpc.orig_rpfn, rpc.new_rpfn);
329 RCBA32(RPFN) = rpc.new_rpfn;
330}
331
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200332static void root_port_mark_disable(struct device *dev)
Aaron Durbinc0254e62013-06-20 01:20:30 -0500333{
334 /* Mark device as disabled. */
335 dev->enabled = 0;
336 /* Mark device to be hidden. */
337 rpc.new_rpfn |= RPFN_HIDE(PCI_FUNC(dev->path.pci.devfn));
338}
339
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200340static void root_port_check_disable(struct device *dev)
Aaron Durbinc0254e62013-06-20 01:20:30 -0500341{
342 int rp;
343 int is_lp;
344
345 /* Device already disabled. */
346 if (!dev->enabled) {
347 root_port_mark_disable(dev);
348 return;
349 }
350
351 rp = root_port_number(dev);
352
353 /* Is the GbE port mapped to this Root Port? */
354 if (rp == rpc.gbe_port) {
355 root_port_mark_disable(dev);
356 return;
357 }
358
359 is_lp = pch_is_lp();
360
361 /* Check Root Port Configuration. */
362 switch (rp) {
363 case 2:
364 /* Root Port 2 is disabled for all lane configurations
365 * but config 00b (4x1 links). */
366 if ((rpc.strpfusecfg1 >> 14) & 0x3) {
367 root_port_mark_disable(dev);
368 return;
369 }
370 break;
371 case 3:
372 /* Root Port 3 is disabled in config 11b (1x4 links). */
373 if (((rpc.strpfusecfg1 >> 14) & 0x3) == 0x3) {
374 root_port_mark_disable(dev);
375 return;
376 }
377 break;
378 case 4:
379 /* Root Port 4 is disabled in configs 11b (1x4 links)
380 * and 10b (2x2 links). */
381 if ((rpc.strpfusecfg1 >> 14) & 0x2) {
382 root_port_mark_disable(dev);
383 return;
384 }
385 break;
386 case 6:
387 if (is_lp)
388 break;
389 /* Root Port 6 is disabled for all lane configurations
390 * but config 00b (4x1 links). */
391 if ((rpc.strpfusecfg2 >> 14) & 0x3) {
392 root_port_mark_disable(dev);
393 return;
394 }
395 break;
396 case 7:
397 if (is_lp)
398 break;
Tristan Corrickbaa4c072018-12-06 22:47:21 +1300399 /* Root Port 7 is disabled in config 11b (1x4 links). */
Aaron Durbinc0254e62013-06-20 01:20:30 -0500400 if (((rpc.strpfusecfg2 >> 14) & 0x3) == 0x3) {
401 root_port_mark_disable(dev);
402 return;
403 }
404 break;
405 case 8:
406 if (is_lp)
407 break;
408 /* Root Port 8 is disabled in configs 11b (1x4 links)
409 * and 10b (2x2 links). */
410 if ((rpc.strpfusecfg2 >> 14) & 0x2) {
411 root_port_mark_disable(dev);
412 return;
413 }
414 break;
415 }
416
417 /* Check Pin Ownership. */
418 if (is_lp) {
419 switch (rp) {
420 case 1:
421 /* Bit 0 is Root Port 1 ownership. */
422 if ((rpc.pin_ownership & 0x1) == 0) {
423 root_port_mark_disable(dev);
424 return;
425 }
426 break;
427 case 2:
428 /* Bit 2 is Root Port 2 ownership. */
429 if ((rpc.pin_ownership & 0x4) == 0) {
430 root_port_mark_disable(dev);
431 return;
432 }
433 break;
434 case 6:
435 /* Bits 7:4 are Root Port 6 pin-lane ownership. */
436 if ((rpc.pin_ownership & 0xf0) == 0) {
437 root_port_mark_disable(dev);
438 return;
439 }
440 break;
441 }
442 } else {
443 switch (rp) {
444 case 1:
445 /* Bits 4 and 0 are Root Port 1 ownership. */
446 if ((rpc.pin_ownership & 0x11) == 0) {
447 root_port_mark_disable(dev);
448 return;
449 }
450 break;
451 case 2:
452 /* Bits 5 and 2 are Root Port 2 ownership. */
453 if ((rpc.pin_ownership & 0x24) == 0) {
454 root_port_mark_disable(dev);
455 return;
456 }
457 break;
458 }
Aaron Durbin60f82082013-06-19 13:28:04 -0500459 }
460}
461
Stefan Reinauerab365af2013-12-03 12:13:26 -0800462static void pcie_add_0x0202000_iobp(u32 reg)
463{
464 u32 reg32;
Aaron Durbin76c37002012-10-30 09:03:43 -0500465
Stefan Reinauerab365af2013-12-03 12:13:26 -0800466 reg32 = pch_iobp_read(reg);
467 reg32 += (0x2 << 16) | (0x2 << 8);
468 pch_iobp_write(reg, reg32);
469}
Aaron Durbin76c37002012-10-30 09:03:43 -0500470
Stefan Reinauerab365af2013-12-03 12:13:26 -0800471static void pch_pcie_early(struct device *dev)
472{
473 int rp;
474 int do_aspm;
475 int is_lp;
Duncan Laurie249a03b2013-08-09 09:06:41 -0700476 struct southbridge_intel_lynxpoint_config *config = dev->chip_info;
Aaron Durbin76c37002012-10-30 09:03:43 -0500477
Stefan Reinauerab365af2013-12-03 12:13:26 -0800478 rp = root_port_number(dev);
479 do_aspm = 0;
480 is_lp = pch_is_lp();
Aaron Durbin76c37002012-10-30 09:03:43 -0500481
Stefan Reinauerab365af2013-12-03 12:13:26 -0800482 if (is_lp) {
483 switch (rp) {
484 case 1:
485 case 2:
486 case 3:
487 case 4:
488 /* Bits 31:28 of b0d28f0 0x32c register correspnd to
489 * Root Ports 4:1. */
490 do_aspm = !!(rpc.b0d28f0_32c & (1 << (28 + rp - 1)));
491 break;
492 case 5:
493 /* Bit 28 of b0d28f4 0x32c register correspnd to
494 * Root Ports 4:1. */
495 do_aspm = !!(rpc.b0d28f4_32c & (1 << 28));
496 break;
497 case 6:
498 /* Bit 28 of b0d28f5 0x32c register correspnd to
499 * Root Ports 4:1. */
500 do_aspm = !!(rpc.b0d28f5_32c & (1 << 28));
501 break;
502 }
503 } else {
504 switch (rp) {
505 case 1:
506 case 2:
507 case 3:
508 case 4:
509 /* Bits 31:28 of b0d28f0 0x32c register correspnd to
510 * Root Ports 4:1. */
511 do_aspm = !!(rpc.b0d28f0_32c & (1 << (28 + rp - 1)));
512 break;
513 case 5:
514 case 6:
515 case 7:
516 case 8:
517 /* Bit 31:28 of b0d28f4 0x32c register correspnd to
518 * Root Ports 8:5. */
519 do_aspm = !!(rpc.b0d28f4_32c & (1 << (28 + rp - 5)));
520 break;
521 }
Aaron Durbin76c37002012-10-30 09:03:43 -0500522 }
Stefan Reinauerab365af2013-12-03 12:13:26 -0800523
Duncan Laurie249a03b2013-08-09 09:06:41 -0700524 /* Allow ASPM to be forced on in devicetree */
525 if (config && (config->pcie_port_force_aspm & (1 << (rp - 1))))
526 do_aspm = 1;
527
528 printk(BIOS_DEBUG, "PCIe Root Port %d ASPM is %sabled\n",
529 rp, do_aspm ? "en" : "dis");
530
Stefan Reinauerab365af2013-12-03 12:13:26 -0800531 if (do_aspm) {
532 /* Set ASPM bits in MPC2 register. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300533 pci_update_config32(dev, 0xd4, ~(0x3 << 2), (1 << 4) | (0x2 << 2));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800534
535 /* Set unique clock exit latency in MPC register. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300536 pci_update_config32(dev, 0xd8, ~(0x7 << 18), (0x7 << 18));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800537
538 /* Set L1 exit latency in LCAP register. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300539 pci_update_config32(dev, 0x4c, ~(0x7 << 15), (0x4 << 15));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800540
541 if (is_lp) {
542 switch (rp) {
543 case 1:
544 pcie_add_0x0202000_iobp(0xe9002440);
545 break;
546 case 2:
547 pcie_add_0x0202000_iobp(0xe9002640);
548 break;
549 case 3:
550 pcie_add_0x0202000_iobp(0xe9000840);
551 break;
552 case 4:
553 pcie_add_0x0202000_iobp(0xe9000a40);
554 break;
555 case 5:
556 pcie_add_0x0202000_iobp(0xe9000c40);
557 pcie_add_0x0202000_iobp(0xe9000e40);
558 pcie_add_0x0202000_iobp(0xe9001040);
559 pcie_add_0x0202000_iobp(0xe9001240);
560 break;
561 case 6:
562 /* Update IOBP based on lane ownership. */
563 if (rpc.pin_ownership & (1 << 4))
564 pcie_add_0x0202000_iobp(0xea002040);
565 if (rpc.pin_ownership & (1 << 5))
566 pcie_add_0x0202000_iobp(0xea002240);
567 if (rpc.pin_ownership & (1 << 6))
568 pcie_add_0x0202000_iobp(0xea002440);
569 if (rpc.pin_ownership & (1 << 7))
570 pcie_add_0x0202000_iobp(0xea002640);
571 break;
572 }
573 } else {
574 switch (rp) {
575 case 1:
576 if ((rpc.pin_ownership & 0x3) == 1)
577 pcie_add_0x0202000_iobp(0xe9002e40);
578 else
579 pcie_add_0x0202000_iobp(0xea002040);
580 break;
581 case 2:
582 if ((rpc.pin_ownership & 0xc) == 0x4)
583 pcie_add_0x0202000_iobp(0xe9002c40);
584 else
585 pcie_add_0x0202000_iobp(0xea002240);
586 break;
587 case 3:
588 pcie_add_0x0202000_iobp(0xe9002a40);
589 break;
590 case 4:
591 pcie_add_0x0202000_iobp(0xe9002840);
592 break;
593 case 5:
594 pcie_add_0x0202000_iobp(0xe9002640);
595 break;
596 case 6:
597 pcie_add_0x0202000_iobp(0xe9002440);
598 break;
599 case 7:
600 pcie_add_0x0202000_iobp(0xe9002240);
601 break;
602 case 8:
603 pcie_add_0x0202000_iobp(0xe9002040);
604 break;
605 }
606 }
607
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300608 pci_update_config32(dev, 0x338, ~(1 << 26), 0);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800609 }
610
611 /* Enable LTR in Root Port. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300612 pci_update_config32(dev, 0x64, ~(1 << 11), (1 << 11));
613 pci_update_config32(dev, 0x68, ~(1 << 10), (1 << 10));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800614
Ryan Salsamendi0d9b3602017-06-30 17:15:57 -0700615 pci_update_config32(dev, 0x318, ~(0xffffUL << 16), (0x1414UL << 16));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800616
617 /* Set L1 exit latency in LCAP register. */
618 if (!do_aspm && (pci_read_config8(dev, 0xf5) & 0x1))
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300619 pci_update_config32(dev, 0x4c, ~(0x7 << 15), (0x4 << 15));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800620 else
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300621 pci_update_config32(dev, 0x4c, ~(0x7 << 15), (0x2 << 15));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800622
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300623 pci_update_config32(dev, 0x314, 0x0, 0x743a361b);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800624
625 /* Set Common Clock Exit Latency in MPC register. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300626 pci_update_config32(dev, 0xd8, ~(0x7 << 15), (0x3 << 15));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800627
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300628 pci_update_config32(dev, 0x33c, ~0x00ffffff, 0x854c74);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800629
Stefan Reinauerab365af2013-12-03 12:13:26 -0800630 /* Set Invalid Recieve Range Check Enable in MPC register. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300631 pci_update_config32(dev, 0xd8, ~0, (1 << 25));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800632
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300633 pci_update_config8(dev, 0xf5, 0x3f, 0);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800634
635 if (rp == 1 || rp == 5 || (is_lp && rp == 6))
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300636 pci_update_config8(dev, 0xf7, ~0xc, 0);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800637
638 /* Set EOI forwarding disable. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300639 pci_update_config32(dev, 0xd4, ~0, (1 << 1));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800640
641 /* Set something involving advanced error reporting. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300642 pci_update_config32(dev, 0x100, ~((1 << 20) - 1), 0x10001);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800643
644 if (is_lp)
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300645 pci_update_config32(dev, 0x100, ~0, (1 << 29));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800646
647 /* Read and write back write-once capability registers. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300648 pci_update_config32(dev, 0x34, ~0, 0);
649 pci_update_config32(dev, 0x40, ~0, 0);
650 pci_update_config32(dev, 0x80, ~0, 0);
651 pci_update_config32(dev, 0x90, ~0, 0);
Aaron Durbin76c37002012-10-30 09:03:43 -0500652}
653
654static void pci_init(struct device *dev)
655{
656 u16 reg16;
657 u32 reg32;
658
659 printk(BIOS_DEBUG, "Initializing PCH PCIe bridge.\n");
660
Aaron Durbinc0254e62013-06-20 01:20:30 -0500661 /* Enable SERR */
662 reg32 = pci_read_config32(dev, PCI_COMMAND);
663 reg32 |= PCI_COMMAND_SERR;
664 pci_write_config32(dev, PCI_COMMAND, reg32);
665
Aaron Durbin76c37002012-10-30 09:03:43 -0500666 /* Enable Bus Master */
667 reg32 = pci_read_config32(dev, PCI_COMMAND);
668 reg32 |= PCI_COMMAND_MASTER;
669 pci_write_config32(dev, PCI_COMMAND, reg32);
670
671 /* Set Cache Line Size to 0x10 */
672 // This has no effect but the OS might expect it
673 pci_write_config8(dev, 0x0c, 0x10);
674
Kyösti Mälkkidf128a52019-09-21 18:35:37 +0300675 reg16 = pci_read_config16(dev, PCI_BRIDGE_CONTROL);
676 reg16 &= ~PCI_BRIDGE_CTL_PARITY;
677 reg16 |= PCI_BRIDGE_CTL_NO_ISA;
678 pci_write_config16(dev, PCI_BRIDGE_CONTROL, reg16);
Aaron Durbin76c37002012-10-30 09:03:43 -0500679
680#ifdef EVEN_MORE_DEBUG
681 reg32 = pci_read_config32(dev, 0x20);
682 printk(BIOS_SPEW, " MBL = 0x%08x\n", reg32);
683 reg32 = pci_read_config32(dev, 0x24);
684 printk(BIOS_SPEW, " PMBL = 0x%08x\n", reg32);
685 reg32 = pci_read_config32(dev, 0x28);
686 printk(BIOS_SPEW, " PMBU32 = 0x%08x\n", reg32);
687 reg32 = pci_read_config32(dev, 0x2c);
688 printk(BIOS_SPEW, " PMLU32 = 0x%08x\n", reg32);
689#endif
690
691 /* Clear errors in status registers */
692 reg16 = pci_read_config16(dev, 0x06);
Aaron Durbin76c37002012-10-30 09:03:43 -0500693 pci_write_config16(dev, 0x06, reg16);
Aaron Durbin76c37002012-10-30 09:03:43 -0500694 reg16 = pci_read_config16(dev, 0x1e);
Aaron Durbin76c37002012-10-30 09:03:43 -0500695 pci_write_config16(dev, 0x1e, reg16);
Aaron Durbin76c37002012-10-30 09:03:43 -0500696}
697
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200698static void pch_pcie_enable(struct device *dev)
Aaron Durbin76c37002012-10-30 09:03:43 -0500699{
Aaron Durbinc0254e62013-06-20 01:20:30 -0500700 /* Add this device to the root port config structure. */
701 root_port_init_config(dev);
702
703 /* Check to see if this Root Port should be disabled. */
704 root_port_check_disable(dev);
705
Aaron Durbin76c37002012-10-30 09:03:43 -0500706 /* Power Management init before enumeration */
Aaron Durbinc0254e62013-06-20 01:20:30 -0500707 if (dev->enabled)
Stefan Reinauerab365af2013-12-03 12:13:26 -0800708 pch_pcie_early(dev);
Aaron Durbinc0254e62013-06-20 01:20:30 -0500709
710 /*
711 * When processing the last PCIe root port we can now
712 * update the Root Port Function Number and Hide register.
713 */
714 if (root_port_is_last(dev))
715 root_port_commit_config();
Aaron Durbin76c37002012-10-30 09:03:43 -0500716}
717
Aaron Durbin76c37002012-10-30 09:03:43 -0500718static struct pci_operations pci_ops = {
Subrata Banik15ccbf02019-03-20 15:09:44 +0530719 .set_subsystem = pci_dev_set_subsystem,
Aaron Durbin76c37002012-10-30 09:03:43 -0500720};
721
722static struct device_operations device_ops = {
723 .read_resources = pci_bus_read_resources,
724 .set_resources = pci_dev_set_resources,
725 .enable_resources = pci_bus_enable_resources,
726 .init = pci_init,
727 .enable = pch_pcie_enable,
728 .scan_bus = pciexp_scan_bridge,
729 .ops_pci = &pci_ops,
730};
731
Duncan Laurie74c0d052012-12-17 11:31:40 -0800732static const unsigned short pci_device_ids[] = {
733 /* Lynxpoint Mobile */
734 0x8c10, 0x8c12, 0x8c14, 0x8c16, 0x8c18, 0x8c1a, 0x8c1c, 0x8c1e,
735 /* Lynxpoint Low Power */
736 0x9c10, 0x9c12, 0x9c14, 0x9c16, 0x9c18, 0x9c1a,
737 0
738};
Aaron Durbin76c37002012-10-30 09:03:43 -0500739
740static const struct pci_driver pch_pcie __pci_driver = {
741 .ops = &device_ops,
742 .vendor = PCI_VENDOR_ID_INTEL,
743 .devices = pci_device_ids,
744};