blob: e11a0b77fea9c4cddad63bbe5fbdad293853e126 [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>
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 <stddef.h>
15#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;
Aaron Durbinc0254e62013-06-20 01:20:30 -050031 int coalesce;
32 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{
Tristan Corrickd3f01b22018-12-06 22:46:58 +130041 if (pch_is_lp() || pch_silicon_id() == PCI_DEVICE_ID_INTEL_LPT_H81)
42 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
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200103static void root_port_init_config(struct device *dev)
Aaron Durbinc0254e62013-06-20 01:20:30 -0500104{
105 int rp;
106
107 if (root_port_is_first(dev)) {
108 rpc.orig_rpfn = RCBA32(RPFN);
109 rpc.new_rpfn = rpc.orig_rpfn;
110 rpc.num_ports = max_root_ports();
111 rpc.gbe_port = -1;
112
113 rpc.pin_ownership = pci_read_config32(dev, 0x410);
114 root_port_config_update_gbe_port();
115
116 if (dev->chip_info != NULL) {
117 struct southbridge_intel_lynxpoint_config *config;
118
119 config = dev->chip_info;
120 rpc.coalesce = config->pcie_port_coalesce;
121 }
122 }
123
124 rp = root_port_number(dev);
125 if (rp > rpc.num_ports) {
126 printk(BIOS_ERR, "Found Root Port %d, expecting %d\n",
127 rp, rpc.num_ports);
128 return;
129 }
130
131 /* Read the fuse configuration and pin ownership. */
132 switch (rp) {
133 case 1:
134 rpc.strpfusecfg1 = pci_read_config32(dev, 0xfc);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800135 rpc.b0d28f0_32c = pci_read_config32(dev, 0x32c);
Aaron Durbinc0254e62013-06-20 01:20:30 -0500136 break;
137 case 5:
138 rpc.strpfusecfg2 = pci_read_config32(dev, 0xfc);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800139 rpc.b0d28f4_32c = pci_read_config32(dev, 0x32c);
Aaron Durbinc0254e62013-06-20 01:20:30 -0500140 break;
141 case 6:
Stefan Reinauerab365af2013-12-03 12:13:26 -0800142 rpc.b0d28f5_32c = pci_read_config32(dev, 0x32c);
Aaron Durbinc0254e62013-06-20 01:20:30 -0500143 rpc.strpfusecfg3 = pci_read_config32(dev, 0xfc);
144 break;
145 default:
146 break;
147 }
148
149 /* Cache pci device. */
150 rpc.ports[rp - 1] = dev;
Aaron Durbin60f82082013-06-19 13:28:04 -0500151}
152
153/* Update devicetree with new Root Port function number assignment */
Aaron Durbinc0254e62013-06-20 01:20:30 -0500154static void pch_pcie_device_set_func(int index, int pci_func)
Aaron Durbin60f82082013-06-19 13:28:04 -0500155{
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200156 struct device *dev;
Martin Rothff744bf2019-10-23 21:46:03 -0600157 unsigned int new_devfn;
Aaron Durbin60f82082013-06-19 13:28:04 -0500158
Aaron Durbinc0254e62013-06-20 01:20:30 -0500159 dev = rpc.ports[index];
Aaron Durbin60f82082013-06-19 13:28:04 -0500160
Aaron Durbinc0254e62013-06-20 01:20:30 -0500161 /* Set the new PCI function field for this Root Port. */
162 rpc.new_rpfn &= ~RPFN_FNMASK(index);
163 rpc.new_rpfn |= RPFN_FNSET(index, pci_func);
Aaron Durbin60f82082013-06-19 13:28:04 -0500164
Aaron Durbinc0254e62013-06-20 01:20:30 -0500165 /* Determine the new devfn for this port */
166 new_devfn = PCI_DEVFN(PCH_PCIE_DEV_SLOT, pci_func);
Aaron Durbin60f82082013-06-19 13:28:04 -0500167
Tristan Corrick05b75242018-12-06 22:47:42 +1300168 if (dev && dev->path.pci.devfn != new_devfn) {
Aaron Durbinc0254e62013-06-20 01:20:30 -0500169 printk(BIOS_DEBUG,
170 "PCH: PCIe map %02x.%1x -> %02x.%1x\n",
171 PCI_SLOT(dev->path.pci.devfn),
172 PCI_FUNC(dev->path.pci.devfn),
173 PCI_SLOT(new_devfn), PCI_FUNC(new_devfn));
Aaron Durbin60f82082013-06-19 13:28:04 -0500174
Aaron Durbinc0254e62013-06-20 01:20:30 -0500175 dev->path.pci.devfn = new_devfn;
Aaron Durbin60f82082013-06-19 13:28:04 -0500176 }
177}
178
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500179static void pcie_enable_clock_gating(void)
180{
181 int i;
182 int is_lp;
183 int enabled_ports;
184
185 is_lp = pch_is_lp();
186 enabled_ports = 0;
187
188 for (i = 0; i < rpc.num_ports; i++) {
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200189 struct device *dev;
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500190 int rp;
191
192 dev = rpc.ports[i];
Tristan Corrick05b75242018-12-06 22:47:42 +1300193 if (!dev)
194 continue;
195
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500196 rp = root_port_number(dev);
197
Tristan Corrick05b75242018-12-06 22:47:42 +1300198 if (!is_rp_enabled(rp)) {
Ryan Salsamendi3f2fe182017-07-04 13:14:16 -0700199 static const uint32_t high_bit = (1UL << 31);
200
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500201 /* Configure shared resource clock gating. */
202 if (rp == 1 || rp == 5 || (rp == 6 && is_lp))
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300203 pci_update_config8(dev, 0xe1, 0xc3, 0x3c);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500204
205 if (!is_lp) {
Tristan Corrick05b75242018-12-06 22:47:42 +1300206 if (rp == 1 && !is_rp_enabled(2) &&
207 !is_rp_enabled(3) && !is_rp_enabled(4)) {
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300208 pci_update_config8(dev, 0xe2, ~1, 1);
209 pci_update_config8(dev, 0xe1, 0x7f, 0x80);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500210 }
Tristan Corrick05b75242018-12-06 22:47:42 +1300211 if (rp == 5 && !is_rp_enabled(6) &&
212 !is_rp_enabled(7) && !is_rp_enabled(8)) {
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300213 pci_update_config8(dev, 0xe2, ~1, 1);
214 pci_update_config8(dev, 0xe1, 0x7f, 0x80);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500215 }
216 continue;
217 }
218
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300219 pci_update_config8(dev, 0xe2, ~(3 << 4), (3 << 4));
Ryan Salsamendi3f2fe182017-07-04 13:14:16 -0700220 pci_update_config32(dev, 0x420, ~high_bit, high_bit);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500221
222 /* Per-Port CLKREQ# handling. */
223 if (is_lp && gpio_is_native(18 + rp - 1))
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300224 pci_update_config32(dev, 0x420, ~0, (3 << 29));
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500225
226 /* Enable static clock gating. */
Tristan Corrick05b75242018-12-06 22:47:42 +1300227 if (rp == 1 && !is_rp_enabled(2) &&
228 !is_rp_enabled(3) && !is_rp_enabled(4)) {
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300229 pci_update_config8(dev, 0xe2, ~1, 1);
230 pci_update_config8(dev, 0xe1, 0x7f, 0x80);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500231 } else if (rp == 5 || rp == 6) {
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300232 pci_update_config8(dev, 0xe2, ~1, 1);
233 pci_update_config8(dev, 0xe1, 0x7f, 0x80);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500234 }
235 continue;
236 }
237
238 enabled_ports++;
239
240 /* Enable dynamic clock gating. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300241 pci_update_config8(dev, 0xe1, 0xfc, 0x03);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500242
243 if (is_lp) {
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300244 pci_update_config8(dev, 0xe2, ~(1 << 6), (1 << 6));
245 pci_update_config8(dev, 0xe8, ~(3 << 2), (2 << 2));
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500246 }
247
248 /* Update PECR1 register. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300249 pci_update_config8(dev, 0xe8, ~0, 1);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500250
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300251 pci_update_config8(dev, 0x324, ~(1 << 5), (1 < 5));
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500252
253 /* Per-Port CLKREQ# handling. */
254 if (is_lp && gpio_is_native(18 + rp - 1))
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300255 pci_update_config32(dev, 0x420, ~0, (3 << 29));
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500256
257 /* Configure shared resource clock gating. */
258 if (rp == 1 || rp == 5 || (rp == 6 && is_lp))
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300259 pci_update_config8(dev, 0xe1, 0xc3, 0x3c);
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500260 }
261
Tristan Corrick05b75242018-12-06 22:47:42 +1300262 if (!enabled_ports && is_lp && rpc.ports[0])
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300263 pci_update_config8(rpc.ports[0], 0xe1, ~(1 << 6), (1 << 6));
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500264}
265
Aaron Durbinc0254e62013-06-20 01:20:30 -0500266static void root_port_commit_config(void)
Aaron Durbin60f82082013-06-19 13:28:04 -0500267{
Aaron Durbinc0254e62013-06-20 01:20:30 -0500268 int i;
Aaron Durbin60f82082013-06-19 13:28:04 -0500269
Aaron Durbinc0254e62013-06-20 01:20:30 -0500270 /* If the first root port is disabled the coalesce ports. */
Tristan Corrick05b75242018-12-06 22:47:42 +1300271 if (!is_rp_enabled(1))
Aaron Durbinc0254e62013-06-20 01:20:30 -0500272 rpc.coalesce = 1;
Aaron Durbin60f82082013-06-19 13:28:04 -0500273
Aaron Durbin1c4289d2013-06-21 14:06:11 -0500274 /* Perform clock gating configuration. */
275 pcie_enable_clock_gating();
276
Aaron Durbinc0254e62013-06-20 01:20:30 -0500277 for (i = 0; i < rpc.num_ports; i++) {
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200278 struct device *dev;
Elyes HAOUAS73ae0762020-04-28 10:13:05 +0200279 u16 reg16;
Aaron Durbin60f82082013-06-19 13:28:04 -0500280
Aaron Durbinc0254e62013-06-20 01:20:30 -0500281 dev = rpc.ports[i];
Aaron Durbin60f82082013-06-19 13:28:04 -0500282
Aaron Durbinc0254e62013-06-20 01:20:30 -0500283 if (dev == NULL) {
284 printk(BIOS_ERR, "Root Port %d device is NULL?\n", i+1);
285 continue;
Aaron Durbin60f82082013-06-19 13:28:04 -0500286 }
287
Aaron Durbinc0254e62013-06-20 01:20:30 -0500288 if (dev->enabled)
289 continue;
290
291 printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
292
Aaron Durbin60f82082013-06-19 13:28:04 -0500293 /* Ensure memory, io, and bus master are all disabled */
Elyes HAOUAS73ae0762020-04-28 10:13:05 +0200294 reg16 = pci_read_config16(dev, PCI_COMMAND);
295 reg16 &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
296 pci_write_config16(dev, PCI_COMMAND, reg16);
Aaron Durbin60f82082013-06-19 13:28:04 -0500297
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++) {
Tristan Corrick05b75242018-12-06 22:47:42 +1300310 if (!is_rp_enabled(i + 1))
Aaron Durbinc0254e62013-06-20 01:20:30 -0500311 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++) {
Tristan Corrick05b75242018-12-06 22:47:42 +1300318 if (is_rp_enabled(i + 1))
Aaron Durbinc0254e62013-06-20 01:20:30 -0500319 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
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200330static void root_port_mark_disable(struct device *dev)
Aaron Durbinc0254e62013-06-20 01:20:30 -0500331{
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
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200338static void root_port_check_disable(struct device *dev)
Aaron Durbinc0254e62013-06-20 01:20:30 -0500339{
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;
Tristan Corrickbaa4c072018-12-06 22:47:21 +1300397 /* Root Port 7 is disabled in config 11b (1x4 links). */
Aaron Durbinc0254e62013-06-20 01:20:30 -0500398 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_add_0x0202000_iobp(u32 reg)
461{
462 u32 reg32;
Aaron Durbin76c37002012-10-30 09:03:43 -0500463
Stefan Reinauerab365af2013-12-03 12:13:26 -0800464 reg32 = pch_iobp_read(reg);
465 reg32 += (0x2 << 16) | (0x2 << 8);
466 pch_iobp_write(reg, reg32);
467}
Aaron Durbin76c37002012-10-30 09:03:43 -0500468
Stefan Reinauerab365af2013-12-03 12:13:26 -0800469static void pch_pcie_early(struct device *dev)
470{
471 int rp;
472 int do_aspm;
473 int is_lp;
Duncan Laurie249a03b2013-08-09 09:06:41 -0700474 struct southbridge_intel_lynxpoint_config *config = dev->chip_info;
Aaron Durbin76c37002012-10-30 09:03:43 -0500475
Stefan Reinauerab365af2013-12-03 12:13:26 -0800476 rp = root_port_number(dev);
477 do_aspm = 0;
478 is_lp = pch_is_lp();
Aaron Durbin76c37002012-10-30 09:03:43 -0500479
Stefan Reinauerab365af2013-12-03 12:13:26 -0800480 if (is_lp) {
481 switch (rp) {
482 case 1:
483 case 2:
484 case 3:
485 case 4:
486 /* Bits 31:28 of b0d28f0 0x32c register correspnd to
487 * Root Ports 4:1. */
488 do_aspm = !!(rpc.b0d28f0_32c & (1 << (28 + rp - 1)));
489 break;
490 case 5:
491 /* Bit 28 of b0d28f4 0x32c register correspnd to
492 * Root Ports 4:1. */
493 do_aspm = !!(rpc.b0d28f4_32c & (1 << 28));
494 break;
495 case 6:
496 /* Bit 28 of b0d28f5 0x32c register correspnd to
497 * Root Ports 4:1. */
498 do_aspm = !!(rpc.b0d28f5_32c & (1 << 28));
499 break;
500 }
501 } else {
502 switch (rp) {
503 case 1:
504 case 2:
505 case 3:
506 case 4:
507 /* Bits 31:28 of b0d28f0 0x32c register correspnd to
508 * Root Ports 4:1. */
509 do_aspm = !!(rpc.b0d28f0_32c & (1 << (28 + rp - 1)));
510 break;
511 case 5:
512 case 6:
513 case 7:
514 case 8:
515 /* Bit 31:28 of b0d28f4 0x32c register correspnd to
516 * Root Ports 8:5. */
517 do_aspm = !!(rpc.b0d28f4_32c & (1 << (28 + rp - 5)));
518 break;
519 }
Aaron Durbin76c37002012-10-30 09:03:43 -0500520 }
Stefan Reinauerab365af2013-12-03 12:13:26 -0800521
Duncan Laurie249a03b2013-08-09 09:06:41 -0700522 /* Allow ASPM to be forced on in devicetree */
523 if (config && (config->pcie_port_force_aspm & (1 << (rp - 1))))
524 do_aspm = 1;
525
526 printk(BIOS_DEBUG, "PCIe Root Port %d ASPM is %sabled\n",
527 rp, do_aspm ? "en" : "dis");
528
Stefan Reinauerab365af2013-12-03 12:13:26 -0800529 if (do_aspm) {
530 /* Set ASPM bits in MPC2 register. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300531 pci_update_config32(dev, 0xd4, ~(0x3 << 2), (1 << 4) | (0x2 << 2));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800532
533 /* Set unique clock exit latency in MPC register. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300534 pci_update_config32(dev, 0xd8, ~(0x7 << 18), (0x7 << 18));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800535
536 /* Set L1 exit latency in LCAP register. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300537 pci_update_config32(dev, 0x4c, ~(0x7 << 15), (0x4 << 15));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800538
539 if (is_lp) {
540 switch (rp) {
541 case 1:
542 pcie_add_0x0202000_iobp(0xe9002440);
543 break;
544 case 2:
545 pcie_add_0x0202000_iobp(0xe9002640);
546 break;
547 case 3:
548 pcie_add_0x0202000_iobp(0xe9000840);
549 break;
550 case 4:
551 pcie_add_0x0202000_iobp(0xe9000a40);
552 break;
553 case 5:
554 pcie_add_0x0202000_iobp(0xe9000c40);
555 pcie_add_0x0202000_iobp(0xe9000e40);
556 pcie_add_0x0202000_iobp(0xe9001040);
557 pcie_add_0x0202000_iobp(0xe9001240);
558 break;
559 case 6:
560 /* Update IOBP based on lane ownership. */
561 if (rpc.pin_ownership & (1 << 4))
562 pcie_add_0x0202000_iobp(0xea002040);
563 if (rpc.pin_ownership & (1 << 5))
564 pcie_add_0x0202000_iobp(0xea002240);
565 if (rpc.pin_ownership & (1 << 6))
566 pcie_add_0x0202000_iobp(0xea002440);
567 if (rpc.pin_ownership & (1 << 7))
568 pcie_add_0x0202000_iobp(0xea002640);
569 break;
570 }
571 } else {
572 switch (rp) {
573 case 1:
574 if ((rpc.pin_ownership & 0x3) == 1)
575 pcie_add_0x0202000_iobp(0xe9002e40);
576 else
577 pcie_add_0x0202000_iobp(0xea002040);
578 break;
579 case 2:
580 if ((rpc.pin_ownership & 0xc) == 0x4)
581 pcie_add_0x0202000_iobp(0xe9002c40);
582 else
583 pcie_add_0x0202000_iobp(0xea002240);
584 break;
585 case 3:
586 pcie_add_0x0202000_iobp(0xe9002a40);
587 break;
588 case 4:
589 pcie_add_0x0202000_iobp(0xe9002840);
590 break;
591 case 5:
592 pcie_add_0x0202000_iobp(0xe9002640);
593 break;
594 case 6:
595 pcie_add_0x0202000_iobp(0xe9002440);
596 break;
597 case 7:
598 pcie_add_0x0202000_iobp(0xe9002240);
599 break;
600 case 8:
601 pcie_add_0x0202000_iobp(0xe9002040);
602 break;
603 }
604 }
605
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300606 pci_update_config32(dev, 0x338, ~(1 << 26), 0);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800607 }
608
609 /* Enable LTR in Root Port. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300610 pci_update_config32(dev, 0x64, ~(1 << 11), (1 << 11));
611 pci_update_config32(dev, 0x68, ~(1 << 10), (1 << 10));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800612
Ryan Salsamendi0d9b3602017-06-30 17:15:57 -0700613 pci_update_config32(dev, 0x318, ~(0xffffUL << 16), (0x1414UL << 16));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800614
615 /* Set L1 exit latency in LCAP register. */
616 if (!do_aspm && (pci_read_config8(dev, 0xf5) & 0x1))
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300617 pci_update_config32(dev, 0x4c, ~(0x7 << 15), (0x4 << 15));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800618 else
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300619 pci_update_config32(dev, 0x4c, ~(0x7 << 15), (0x2 << 15));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800620
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300621 pci_update_config32(dev, 0x314, 0x0, 0x743a361b);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800622
623 /* Set Common Clock Exit Latency in MPC register. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300624 pci_update_config32(dev, 0xd8, ~(0x7 << 15), (0x3 << 15));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800625
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300626 pci_update_config32(dev, 0x33c, ~0x00ffffff, 0x854c74);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800627
Stefan Reinauerab365af2013-12-03 12:13:26 -0800628 /* Set Invalid Recieve Range Check Enable in MPC register. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300629 pci_update_config32(dev, 0xd8, ~0, (1 << 25));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800630
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300631 pci_update_config8(dev, 0xf5, 0x3f, 0);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800632
633 if (rp == 1 || rp == 5 || (is_lp && rp == 6))
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300634 pci_update_config8(dev, 0xf7, ~0xc, 0);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800635
636 /* Set EOI forwarding disable. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300637 pci_update_config32(dev, 0xd4, ~0, (1 << 1));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800638
639 /* Set something involving advanced error reporting. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300640 pci_update_config32(dev, 0x100, ~((1 << 20) - 1), 0x10001);
Stefan Reinauerab365af2013-12-03 12:13:26 -0800641
642 if (is_lp)
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300643 pci_update_config32(dev, 0x100, ~0, (1 << 29));
Stefan Reinauerab365af2013-12-03 12:13:26 -0800644
645 /* Read and write back write-once capability registers. */
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300646 pci_update_config32(dev, 0x34, ~0, 0);
647 pci_update_config32(dev, 0x40, ~0, 0);
648 pci_update_config32(dev, 0x80, ~0, 0);
649 pci_update_config32(dev, 0x90, ~0, 0);
Aaron Durbin76c37002012-10-30 09:03:43 -0500650}
651
652static void pci_init(struct device *dev)
653{
654 u16 reg16;
Aaron Durbin76c37002012-10-30 09:03:43 -0500655
656 printk(BIOS_DEBUG, "Initializing PCH PCIe bridge.\n");
657
Aaron Durbinc0254e62013-06-20 01:20:30 -0500658 /* Enable SERR */
Elyes HAOUAS73ae0762020-04-28 10:13:05 +0200659 pci_or_config16(dev, PCI_COMMAND, PCI_COMMAND_SERR);
Aaron Durbinc0254e62013-06-20 01:20:30 -0500660
Aaron Durbin76c37002012-10-30 09:03:43 -0500661 /* Enable Bus Master */
Elyes HAOUAS73ae0762020-04-28 10:13:05 +0200662 pci_or_config16(dev, PCI_COMMAND, PCI_COMMAND_MASTER);
Aaron Durbin76c37002012-10-30 09:03:43 -0500663
664 /* Set Cache Line Size to 0x10 */
665 // This has no effect but the OS might expect it
666 pci_write_config8(dev, 0x0c, 0x10);
667
Kyösti Mälkkidf128a52019-09-21 18:35:37 +0300668 reg16 = pci_read_config16(dev, PCI_BRIDGE_CONTROL);
669 reg16 &= ~PCI_BRIDGE_CTL_PARITY;
670 reg16 |= PCI_BRIDGE_CTL_NO_ISA;
671 pci_write_config16(dev, PCI_BRIDGE_CONTROL, reg16);
Aaron Durbin76c37002012-10-30 09:03:43 -0500672
673#ifdef EVEN_MORE_DEBUG
674 reg32 = pci_read_config32(dev, 0x20);
675 printk(BIOS_SPEW, " MBL = 0x%08x\n", reg32);
676 reg32 = pci_read_config32(dev, 0x24);
677 printk(BIOS_SPEW, " PMBL = 0x%08x\n", reg32);
678 reg32 = pci_read_config32(dev, 0x28);
679 printk(BIOS_SPEW, " PMBU32 = 0x%08x\n", reg32);
680 reg32 = pci_read_config32(dev, 0x2c);
681 printk(BIOS_SPEW, " PMLU32 = 0x%08x\n", reg32);
682#endif
683
684 /* Clear errors in status registers */
685 reg16 = pci_read_config16(dev, 0x06);
Aaron Durbin76c37002012-10-30 09:03:43 -0500686 pci_write_config16(dev, 0x06, reg16);
Aaron Durbin76c37002012-10-30 09:03:43 -0500687 reg16 = pci_read_config16(dev, 0x1e);
Aaron Durbin76c37002012-10-30 09:03:43 -0500688 pci_write_config16(dev, 0x1e, reg16);
Aaron Durbin76c37002012-10-30 09:03:43 -0500689}
690
Elyes HAOUAS7a5f7712018-06-08 17:20:38 +0200691static void pch_pcie_enable(struct device *dev)
Aaron Durbin76c37002012-10-30 09:03:43 -0500692{
Aaron Durbinc0254e62013-06-20 01:20:30 -0500693 /* Add this device to the root port config structure. */
694 root_port_init_config(dev);
695
696 /* Check to see if this Root Port should be disabled. */
697 root_port_check_disable(dev);
698
Aaron Durbin76c37002012-10-30 09:03:43 -0500699 /* Power Management init before enumeration */
Aaron Durbinc0254e62013-06-20 01:20:30 -0500700 if (dev->enabled)
Stefan Reinauerab365af2013-12-03 12:13:26 -0800701 pch_pcie_early(dev);
Aaron Durbinc0254e62013-06-20 01:20:30 -0500702
703 /*
704 * When processing the last PCIe root port we can now
705 * update the Root Port Function Number and Hide register.
706 */
707 if (root_port_is_last(dev))
708 root_port_commit_config();
Aaron Durbin76c37002012-10-30 09:03:43 -0500709}
710
Aaron Durbin76c37002012-10-30 09:03:43 -0500711static struct pci_operations pci_ops = {
Subrata Banik15ccbf02019-03-20 15:09:44 +0530712 .set_subsystem = pci_dev_set_subsystem,
Aaron Durbin76c37002012-10-30 09:03:43 -0500713};
714
715static struct device_operations device_ops = {
716 .read_resources = pci_bus_read_resources,
717 .set_resources = pci_dev_set_resources,
718 .enable_resources = pci_bus_enable_resources,
719 .init = pci_init,
720 .enable = pch_pcie_enable,
721 .scan_bus = pciexp_scan_bridge,
722 .ops_pci = &pci_ops,
723};
724
Duncan Laurie74c0d052012-12-17 11:31:40 -0800725static const unsigned short pci_device_ids[] = {
726 /* Lynxpoint Mobile */
727 0x8c10, 0x8c12, 0x8c14, 0x8c16, 0x8c18, 0x8c1a, 0x8c1c, 0x8c1e,
728 /* Lynxpoint Low Power */
729 0x9c10, 0x9c12, 0x9c14, 0x9c16, 0x9c18, 0x9c1a,
730 0
731};
Aaron Durbin76c37002012-10-30 09:03:43 -0500732
733static const struct pci_driver pch_pcie __pci_driver = {
734 .ops = &device_ops,
735 .vendor = PCI_VENDOR_ID_INTEL,
736 .devices = pci_device_ids,
737};