blob: 07d559ac117226e29f56ebd090fbede5bb216c30 [file] [log] [blame]
Angel Ponsc74dae92020-04-02 23:48:16 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
Yinghai Lu13f1c2a2005-07-08 02:49:49 +00003
4#include <console/console.h>
Kyösti Mälkki94ce79d2019-12-16 17:21:13 +02005#include <commonlib/helpers.h>
Duncan Laurie90dcdd42011-10-25 14:15:11 -07006#include <delay.h>
Yinghai Lu13f1c2a2005-07-08 02:49:49 +00007#include <device/device.h>
8#include <device/pci.h>
Patrick Rudolphe56189c2018-04-18 10:11:59 +02009#include <device/pci_ops.h>
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000010#include <device/pciexp.h>
11
Elyes HAOUASb1fa2872018-05-02 21:11:38 +020012unsigned int pciexp_find_extended_cap(struct device *dev, unsigned int cap)
Kenji Chen31c6e632014-10-04 01:14:44 +080013{
14 unsigned int this_cap_offset, next_cap_offset;
15 unsigned int this_cap, cafe;
16
17 this_cap_offset = PCIE_EXT_CAP_OFFSET;
18 do {
Kyösti Mälkki91bfa8e2016-11-20 20:39:56 +020019 this_cap = pci_read_config32(dev, this_cap_offset);
Kenji Chen31c6e632014-10-04 01:14:44 +080020 next_cap_offset = this_cap >> 20;
21 this_cap &= 0xffff;
Kyösti Mälkki91bfa8e2016-11-20 20:39:56 +020022 cafe = pci_read_config32(dev, this_cap_offset + 4);
Kenji Chen31c6e632014-10-04 01:14:44 +080023 cafe &= 0xffff;
24 if (this_cap == cap)
25 return this_cap_offset;
26 else if (cafe == cap)
27 return this_cap_offset + 4;
28 else
29 this_cap_offset = next_cap_offset;
30 } while (next_cap_offset != 0);
31
32 return 0;
33}
Kenji Chen31c6e632014-10-04 01:14:44 +080034
Duncan Laurie90dcdd42011-10-25 14:15:11 -070035/*
36 * Re-train a PCIe link
37 */
38#define PCIE_TRAIN_RETRY 10000
Martin Roth38ddbfb2019-10-23 21:41:00 -060039static int pciexp_retrain_link(struct device *dev, unsigned int cap)
Duncan Laurie90dcdd42011-10-25 14:15:11 -070040{
Youness Alaouibb5fb642017-05-03 17:57:13 -040041 unsigned int try;
Duncan Laurie90dcdd42011-10-25 14:15:11 -070042 u16 lnk;
43
Youness Alaouibb5fb642017-05-03 17:57:13 -040044 /*
45 * Implementation note (page 633) in PCIe Specification 3.0 suggests
46 * polling the Link Training bit in the Link Status register until the
47 * value returned is 0 before setting the Retrain Link bit to 1.
48 * This is meant to avoid a race condition when using the
49 * Retrain Link mechanism.
50 */
51 for (try = PCIE_TRAIN_RETRY; try > 0; try--) {
52 lnk = pci_read_config16(dev, cap + PCI_EXP_LNKSTA);
53 if (!(lnk & PCI_EXP_LNKSTA_LT))
54 break;
55 udelay(100);
56 }
57 if (try == 0) {
58 printk(BIOS_ERR, "%s: Link Retrain timeout\n", dev_path(dev));
59 return -1;
60 }
61
Duncan Laurie90dcdd42011-10-25 14:15:11 -070062 /* Start link retraining */
63 lnk = pci_read_config16(dev, cap + PCI_EXP_LNKCTL);
64 lnk |= PCI_EXP_LNKCTL_RL;
65 pci_write_config16(dev, cap + PCI_EXP_LNKCTL, lnk);
66
67 /* Wait for training to complete */
Youness Alaouibb5fb642017-05-03 17:57:13 -040068 for (try = PCIE_TRAIN_RETRY; try > 0; try--) {
Duncan Laurie90dcdd42011-10-25 14:15:11 -070069 lnk = pci_read_config16(dev, cap + PCI_EXP_LNKSTA);
70 if (!(lnk & PCI_EXP_LNKSTA_LT))
71 return 0;
72 udelay(100);
73 }
74
75 printk(BIOS_ERR, "%s: Link Retrain timeout\n", dev_path(dev));
76 return -1;
77}
78
79/*
80 * Check the Slot Clock Configuration for root port and endpoint
81 * and enable Common Clock Configuration if possible. If CCC is
82 * enabled the link must be retrained.
83 */
Martin Roth38ddbfb2019-10-23 21:41:00 -060084static void pciexp_enable_common_clock(struct device *root, unsigned int root_cap,
85 struct device *endp, unsigned int endp_cap)
Duncan Laurie90dcdd42011-10-25 14:15:11 -070086{
87 u16 root_scc, endp_scc, lnkctl;
88
89 /* Get Slot Clock Configuration for root port */
90 root_scc = pci_read_config16(root, root_cap + PCI_EXP_LNKSTA);
91 root_scc &= PCI_EXP_LNKSTA_SLC;
92
93 /* Get Slot Clock Configuration for endpoint */
94 endp_scc = pci_read_config16(endp, endp_cap + PCI_EXP_LNKSTA);
95 endp_scc &= PCI_EXP_LNKSTA_SLC;
96
97 /* Enable Common Clock Configuration and retrain */
98 if (root_scc && endp_scc) {
99 printk(BIOS_INFO, "Enabling Common Clock Configuration\n");
100
101 /* Set in endpoint */
102 lnkctl = pci_read_config16(endp, endp_cap + PCI_EXP_LNKCTL);
103 lnkctl |= PCI_EXP_LNKCTL_CCC;
104 pci_write_config16(endp, endp_cap + PCI_EXP_LNKCTL, lnkctl);
105
106 /* Set in root port */
107 lnkctl = pci_read_config16(root, root_cap + PCI_EXP_LNKCTL);
108 lnkctl |= PCI_EXP_LNKCTL_CCC;
109 pci_write_config16(root, root_cap + PCI_EXP_LNKCTL, lnkctl);
110
111 /* Retrain link if CCC was enabled */
112 pciexp_retrain_link(root, root_cap);
113 }
114}
Duncan Laurie90dcdd42011-10-25 14:15:11 -0700115
Martin Roth38ddbfb2019-10-23 21:41:00 -0600116static void pciexp_enable_clock_power_pm(struct device *endp, unsigned int endp_cap)
Kane Chen18cb1342014-10-01 11:13:54 +0800117{
118 /* check if per port clk req is supported in device */
119 u32 endp_ca;
120 u16 lnkctl;
121 endp_ca = pci_read_config32(endp, endp_cap + PCI_EXP_LNKCAP);
122 if ((endp_ca & PCI_EXP_CLK_PM) == 0) {
Arthur Heymans330c46b2017-07-12 19:17:56 +0200123 printk(BIOS_INFO, "PCIE CLK PM is not supported by endpoint\n");
Kane Chen18cb1342014-10-01 11:13:54 +0800124 return;
125 }
126 lnkctl = pci_read_config16(endp, endp_cap + PCI_EXP_LNKCTL);
127 lnkctl = lnkctl | PCI_EXP_EN_CLK_PM;
128 pci_write_config16(endp, endp_cap + PCI_EXP_LNKCTL, lnkctl);
129}
Kane Chen18cb1342014-10-01 11:13:54 +0800130
Elyes HAOUASb1fa2872018-05-02 21:11:38 +0200131static void pciexp_config_max_latency(struct device *root, struct device *dev)
Kenji Chen31c6e632014-10-04 01:14:44 +0800132{
133 unsigned int cap;
134 cap = pciexp_find_extended_cap(dev, PCIE_EXT_CAP_LTR_ID);
Pratik Prajapati0cd0d282015-06-09 12:06:20 -0700135 if ((cap) && (root->ops->ops_pci != NULL) &&
136 (root->ops->ops_pci->set_L1_ss_latency != NULL))
137 root->ops->ops_pci->set_L1_ss_latency(dev, cap + 4);
Kenji Chen31c6e632014-10-04 01:14:44 +0800138}
139
Elyes HAOUASb1fa2872018-05-02 21:11:38 +0200140static bool pciexp_is_ltr_supported(struct device *dev, unsigned int cap)
Aamir Bohra2188f572017-09-22 19:07:21 +0530141{
142 unsigned int val;
143
144 val = pci_read_config16(dev, cap + PCI_EXP_DEV_CAP2_OFFSET);
145
146 if (val & LTR_MECHANISM_SUPPORT)
147 return true;
148
149 return false;
150}
151
Elyes HAOUASb1fa2872018-05-02 21:11:38 +0200152static void pciexp_configure_ltr(struct device *dev)
Kenji Chen31c6e632014-10-04 01:14:44 +0800153{
154 unsigned int cap;
Aamir Bohra2188f572017-09-22 19:07:21 +0530155
Kenji Chen31c6e632014-10-04 01:14:44 +0800156 cap = pci_find_capability(dev, PCI_CAP_ID_PCIE);
Aamir Bohra2188f572017-09-22 19:07:21 +0530157
158 /*
Elyes HAOUASaeff5122019-12-07 11:57:35 +0100159 * Check if capability pointer is valid and
Aamir Bohra2188f572017-09-22 19:07:21 +0530160 * device supports LTR mechanism.
161 */
162 if (!cap || !pciexp_is_ltr_supported(dev, cap)) {
Pratik Prajapati0cd0d282015-06-09 12:06:20 -0700163 printk(BIOS_INFO, "Failed to enable LTR for dev = %s\n",
Aamir Bohra2188f572017-09-22 19:07:21 +0530164 dev_path(dev));
Pratik Prajapati0cd0d282015-06-09 12:06:20 -0700165 return;
166 }
Aamir Bohra2188f572017-09-22 19:07:21 +0530167
168 cap += PCI_EXP_DEV_CTL_STS2_CAP_OFFSET;
169
170 /* Enable LTR for device */
171 pci_update_config32(dev, cap, ~LTR_MECHANISM_EN, LTR_MECHANISM_EN);
172
173 /* Configure Max Snoop Latency */
174 pciexp_config_max_latency(dev->bus->dev, dev);
175}
176
Elyes HAOUASb1fa2872018-05-02 21:11:38 +0200177static void pciexp_enable_ltr(struct device *dev)
Aamir Bohra2188f572017-09-22 19:07:21 +0530178{
179 struct bus *bus;
Elyes HAOUASb1fa2872018-05-02 21:11:38 +0200180 struct device *child;
Aamir Bohra2188f572017-09-22 19:07:21 +0530181
182 for (bus = dev->link_list ; bus ; bus = bus->next) {
183 for (child = bus->children; child; child = child->sibling) {
184 pciexp_configure_ltr(child);
185 if (child->ops && child->ops->scan_bus)
186 pciexp_enable_ltr(child);
187 }
188 }
Kenji Chen31c6e632014-10-04 01:14:44 +0800189}
190
Elyes HAOUASb1fa2872018-05-02 21:11:38 +0200191static unsigned char pciexp_L1_substate_cal(struct device *dev, unsigned int endp_cap,
Kenji Chen31c6e632014-10-04 01:14:44 +0800192 unsigned int *data)
193{
194 unsigned char mult[4] = {2, 10, 100, 0};
195
196 unsigned int L1SubStateSupport = *data & 0xf;
197 unsigned int comm_mode_rst_time = (*data >> 8) & 0xff;
198 unsigned int power_on_scale = (*data >> 16) & 0x3;
199 unsigned int power_on_value = (*data >> 19) & 0x1f;
200
Kyösti Mälkki91bfa8e2016-11-20 20:39:56 +0200201 unsigned int endp_data = pci_read_config32(dev, endp_cap + 4);
Kenji Chen31c6e632014-10-04 01:14:44 +0800202 unsigned int endp_L1SubStateSupport = endp_data & 0xf;
203 unsigned int endp_comm_mode_restore_time = (endp_data >> 8) & 0xff;
204 unsigned int endp_power_on_scale = (endp_data >> 16) & 0x3;
205 unsigned int endp_power_on_value = (endp_data >> 19) & 0x1f;
206
207 L1SubStateSupport &= endp_L1SubStateSupport;
208
209 if (L1SubStateSupport == 0)
210 return 0;
211
212 if (power_on_value * mult[power_on_scale] <
213 endp_power_on_value * mult[endp_power_on_scale]) {
214 power_on_value = endp_power_on_value;
215 power_on_scale = endp_power_on_scale;
216 }
217 if (comm_mode_rst_time < endp_comm_mode_restore_time)
218 comm_mode_rst_time = endp_comm_mode_restore_time;
219
220 *data = (comm_mode_rst_time << 8) | (power_on_scale << 16)
221 | (power_on_value << 19) | L1SubStateSupport;
222
223 return 1;
224}
225
Elyes HAOUASb1fa2872018-05-02 21:11:38 +0200226static void pciexp_L1_substate_commit(struct device *root, struct device *dev,
Kenji Chen31c6e632014-10-04 01:14:44 +0800227 unsigned int root_cap, unsigned int end_cap)
228{
Elyes HAOUASb1fa2872018-05-02 21:11:38 +0200229 struct device *dev_t;
Kenji Chen31c6e632014-10-04 01:14:44 +0800230 unsigned char L1_ss_ok;
Kyösti Mälkki91bfa8e2016-11-20 20:39:56 +0200231 unsigned int rp_L1_support = pci_read_config32(root, root_cap + 4);
Kenji Chen31c6e632014-10-04 01:14:44 +0800232 unsigned int L1SubStateSupport;
233 unsigned int comm_mode_rst_time;
234 unsigned int power_on_scale;
235 unsigned int endp_power_on_value;
236
237 for (dev_t = dev; dev_t; dev_t = dev_t->sibling) {
238 /*
239 * rp_L1_support is init'd above from root port.
240 * it needs coordination with endpoints to reach in common.
241 * if certain endpoint doesn't support L1 Sub-State, abort
242 * this feature enabling.
243 */
244 L1_ss_ok = pciexp_L1_substate_cal(dev_t, end_cap,
245 &rp_L1_support);
246 if (!L1_ss_ok)
247 return;
248 }
249
250 L1SubStateSupport = rp_L1_support & 0xf;
251 comm_mode_rst_time = (rp_L1_support >> 8) & 0xff;
252 power_on_scale = (rp_L1_support >> 16) & 0x3;
253 endp_power_on_value = (rp_L1_support >> 19) & 0x1f;
254
255 printk(BIOS_INFO, "L1 Sub-State supported from root port %d\n",
256 root->path.pci.devfn >> 3);
257 printk(BIOS_INFO, "L1 Sub-State Support = 0x%x\n", L1SubStateSupport);
258 printk(BIOS_INFO, "CommonModeRestoreTime = 0x%x\n", comm_mode_rst_time);
259 printk(BIOS_INFO, "Power On Value = 0x%x, Power On Scale = 0x%x\n",
260 endp_power_on_value, power_on_scale);
261
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300262 pci_update_config32(root, root_cap + 0x08, ~0xff00,
Kenji Chen31c6e632014-10-04 01:14:44 +0800263 (comm_mode_rst_time << 8));
264
Elyes HAOUASa342f392018-10-17 10:56:26 +0200265 pci_update_config32(root, root_cap + 0x0c, 0xffffff04,
Kenji Chen31c6e632014-10-04 01:14:44 +0800266 (endp_power_on_value << 3) | (power_on_scale));
267
Patrick Georgi9adcbfe2017-12-05 16:36:30 -0500268 /* TODO: 0xa0, 2 are values that work on some chipsets but really
269 * should be determined dynamically by looking at downstream devices.
270 */
271 pci_update_config32(root, root_cap + 0x08,
272 ~(ASPM_LTR_L12_THRESHOLD_VALUE_MASK |
273 ASPM_LTR_L12_THRESHOLD_SCALE_MASK),
274 (0xa0 << ASPM_LTR_L12_THRESHOLD_VALUE_OFFSET) |
275 (2 << ASPM_LTR_L12_THRESHOLD_SCALE_OFFSET));
Kenji Chen31c6e632014-10-04 01:14:44 +0800276
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300277 pci_update_config32(root, root_cap + 0x08, ~0x1f,
Kenji Chen31c6e632014-10-04 01:14:44 +0800278 L1SubStateSupport);
279
280 for (dev_t = dev; dev_t; dev_t = dev_t->sibling) {
Elyes HAOUASa342f392018-10-17 10:56:26 +0200281 pci_update_config32(dev_t, end_cap + 0x0c, 0xffffff04,
Kenji Chen31c6e632014-10-04 01:14:44 +0800282 (endp_power_on_value << 3) | (power_on_scale));
283
Patrick Georgi9adcbfe2017-12-05 16:36:30 -0500284 pci_update_config32(dev_t, end_cap + 0x08,
285 ~(ASPM_LTR_L12_THRESHOLD_VALUE_MASK |
286 ASPM_LTR_L12_THRESHOLD_SCALE_MASK),
287 (0xa0 << ASPM_LTR_L12_THRESHOLD_VALUE_OFFSET) |
288 (2 << ASPM_LTR_L12_THRESHOLD_SCALE_OFFSET));
Kenji Chen31c6e632014-10-04 01:14:44 +0800289
Kyösti Mälkki48c389e2013-07-26 08:53:59 +0300290 pci_update_config32(dev_t, end_cap + 0x08, ~0x1f,
Kenji Chen31c6e632014-10-04 01:14:44 +0800291 L1SubStateSupport);
Kenji Chen31c6e632014-10-04 01:14:44 +0800292 }
293}
294
Elyes HAOUASb1fa2872018-05-02 21:11:38 +0200295static void pciexp_config_L1_sub_state(struct device *root, struct device *dev)
Kenji Chen31c6e632014-10-04 01:14:44 +0800296{
297 unsigned int root_cap, end_cap;
298
299 /* Do it for function 0 only */
300 if (dev->path.pci.devfn & 0x7)
301 return;
302
303 root_cap = pciexp_find_extended_cap(root, PCIE_EXT_CAP_L1SS_ID);
304 if (!root_cap)
305 return;
306
307 end_cap = pciexp_find_extended_cap(dev, PCIE_EXT_CAP_L1SS_ID);
308 if (!end_cap) {
309 end_cap = pciexp_find_extended_cap(dev, 0xcafe);
310 if (!end_cap)
311 return;
312 }
313
314 pciexp_L1_substate_commit(root, dev, root_cap, end_cap);
315}
Kenji Chen31c6e632014-10-04 01:14:44 +0800316
Duncan Laurie90dcdd42011-10-25 14:15:11 -0700317/*
318 * Determine the ASPM L0s or L1 exit latency for a link
319 * by checking both root port and endpoint and returning
320 * the highest latency value.
321 */
Martin Roth38ddbfb2019-10-23 21:41:00 -0600322static int pciexp_aspm_latency(struct device *root, unsigned int root_cap,
323 struct device *endp, unsigned int endp_cap,
Duncan Laurie90dcdd42011-10-25 14:15:11 -0700324 enum aspm_type type)
325{
326 int root_lat = 0, endp_lat = 0;
327 u32 root_lnkcap, endp_lnkcap;
328
329 root_lnkcap = pci_read_config32(root, root_cap + PCI_EXP_LNKCAP);
330 endp_lnkcap = pci_read_config32(endp, endp_cap + PCI_EXP_LNKCAP);
331
332 /* Make sure the link supports this ASPM type by checking
333 * capability bits 11:10 with aspm_type offset by 1 */
334 if (!(root_lnkcap & (1 << (type + 9))) ||
335 !(endp_lnkcap & (1 << (type + 9))))
336 return -1;
337
338 /* Find the one with higher latency */
339 switch (type) {
340 case PCIE_ASPM_L0S:
341 root_lat = (root_lnkcap & PCI_EXP_LNKCAP_L0SEL) >> 12;
342 endp_lat = (endp_lnkcap & PCI_EXP_LNKCAP_L0SEL) >> 12;
343 break;
344 case PCIE_ASPM_L1:
345 root_lat = (root_lnkcap & PCI_EXP_LNKCAP_L1EL) >> 15;
346 endp_lat = (endp_lnkcap & PCI_EXP_LNKCAP_L1EL) >> 15;
347 break;
348 default:
349 return -1;
350 }
351
352 return (endp_lat > root_lat) ? endp_lat : root_lat;
353}
354
355/*
356 * Enable ASPM on PCIe root port and endpoint.
Duncan Laurie90dcdd42011-10-25 14:15:11 -0700357 */
Martin Roth38ddbfb2019-10-23 21:41:00 -0600358static void pciexp_enable_aspm(struct device *root, unsigned int root_cap,
359 struct device *endp, unsigned int endp_cap)
Duncan Laurie90dcdd42011-10-25 14:15:11 -0700360{
361 const char *aspm_type_str[] = { "None", "L0s", "L1", "L0s and L1" };
362 enum aspm_type apmc = PCIE_ASPM_NONE;
363 int exit_latency, ok_latency;
364 u16 lnkctl;
365 u32 devcap;
366
Nico Huber570b1832017-08-30 13:38:50 +0200367 if (endp->disable_pcie_aspm)
368 return;
369
Duncan Laurie90dcdd42011-10-25 14:15:11 -0700370 /* Get endpoint device capabilities for acceptable limits */
371 devcap = pci_read_config32(endp, endp_cap + PCI_EXP_DEVCAP);
372
373 /* Enable L0s if it is within endpoint acceptable limit */
374 ok_latency = (devcap & PCI_EXP_DEVCAP_L0S) >> 6;
375 exit_latency = pciexp_aspm_latency(root, root_cap, endp, endp_cap,
376 PCIE_ASPM_L0S);
377 if (exit_latency >= 0 && exit_latency <= ok_latency)
378 apmc |= PCIE_ASPM_L0S;
379
380 /* Enable L1 if it is within endpoint acceptable limit */
381 ok_latency = (devcap & PCI_EXP_DEVCAP_L1) >> 9;
382 exit_latency = pciexp_aspm_latency(root, root_cap, endp, endp_cap,
383 PCIE_ASPM_L1);
384 if (exit_latency >= 0 && exit_latency <= ok_latency)
385 apmc |= PCIE_ASPM_L1;
386
387 if (apmc != PCIE_ASPM_NONE) {
388 /* Set APMC in root port first */
389 lnkctl = pci_read_config16(root, root_cap + PCI_EXP_LNKCTL);
390 lnkctl |= apmc;
391 pci_write_config16(root, root_cap + PCI_EXP_LNKCTL, lnkctl);
392
393 /* Set APMC in endpoint device next */
394 lnkctl = pci_read_config16(endp, endp_cap + PCI_EXP_LNKCTL);
395 lnkctl |= apmc;
396 pci_write_config16(endp, endp_cap + PCI_EXP_LNKCTL, lnkctl);
397 }
398
399 printk(BIOS_INFO, "ASPM: Enabled %s\n", aspm_type_str[apmc]);
Duncan Laurie90dcdd42011-10-25 14:15:11 -0700400}
Duncan Laurie90dcdd42011-10-25 14:15:11 -0700401
Kyösti Mälkki94ce79d2019-12-16 17:21:13 +0200402/*
403 * Set max payload size of endpoint in accordance with max payload size of root port.
404 */
405static void pciexp_set_max_payload_size(struct device *root, unsigned int root_cap,
406 struct device *endp, unsigned int endp_cap)
407{
408 unsigned int endp_max_payload, root_max_payload, max_payload;
409 u16 endp_devctl, root_devctl;
410 u32 endp_devcap, root_devcap;
411
412 /* Get max payload size supported by endpoint */
413 endp_devcap = pci_read_config32(endp, endp_cap + PCI_EXP_DEVCAP);
414 endp_max_payload = endp_devcap & PCI_EXP_DEVCAP_PAYLOAD;
415
416 /* Get max payload size supported by root port */
417 root_devcap = pci_read_config32(root, root_cap + PCI_EXP_DEVCAP);
418 root_max_payload = root_devcap & PCI_EXP_DEVCAP_PAYLOAD;
419
420 /* Set max payload to smaller of the reported device capability. */
421 max_payload = MIN(endp_max_payload, root_max_payload);
422 if (max_payload > 5) {
423 /* Values 6 and 7 are reserved in PCIe 3.0 specs. */
424 printk(BIOS_ERR, "PCIe: Max_Payload_Size field restricted from %d to 5\n",
425 max_payload);
426 max_payload = 5;
427 }
428
429 endp_devctl = pci_read_config16(endp, endp_cap + PCI_EXP_DEVCTL);
430 endp_devctl &= ~PCI_EXP_DEVCTL_PAYLOAD;
431 endp_devctl |= max_payload << 5;
432 pci_write_config16(endp, endp_cap + PCI_EXP_DEVCTL, endp_devctl);
433
434 root_devctl = pci_read_config16(root, root_cap + PCI_EXP_DEVCTL);
435 root_devctl &= ~PCI_EXP_DEVCTL_PAYLOAD;
436 root_devctl |= max_payload << 5;
437 pci_write_config16(root, root_cap + PCI_EXP_DEVCTL, root_devctl);
438
439 printk(BIOS_INFO, "PCIe: Max_Payload_Size adjusted to %d\n", (1 << (max_payload + 7)));
440}
441
Elyes HAOUASb1fa2872018-05-02 21:11:38 +0200442static void pciexp_tune_dev(struct device *dev)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000443{
Elyes HAOUASb1fa2872018-05-02 21:11:38 +0200444 struct device *root = dev->bus->dev;
Duncan Laurie90dcdd42011-10-25 14:15:11 -0700445 unsigned int root_cap, cap;
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000446
447 cap = pci_find_capability(dev, PCI_CAP_ID_PCIE);
Uwe Hermannd453dd02010-10-18 00:00:57 +0000448 if (!cap)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000449 return;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000450
Duncan Laurie90dcdd42011-10-25 14:15:11 -0700451 root_cap = pci_find_capability(root, PCI_CAP_ID_PCIE);
452 if (!root_cap)
453 return;
Stefan Reinauerf6eb88a2010-01-17 13:54:08 +0000454
Duncan Laurie90dcdd42011-10-25 14:15:11 -0700455 /* Check for and enable Common Clock */
Julius Wernercd49cce2019-03-05 16:53:33 -0800456 if (CONFIG(PCIEXP_COMMON_CLOCK))
Kyösti Mälkki91bfa8e2016-11-20 20:39:56 +0200457 pciexp_enable_common_clock(root, root_cap, dev, cap);
Uwe Hermanne4870472010-11-04 23:23:47 +0000458
Kane Chen18cb1342014-10-01 11:13:54 +0800459 /* Check if per port CLK req is supported by endpoint*/
Julius Wernercd49cce2019-03-05 16:53:33 -0800460 if (CONFIG(PCIEXP_CLK_PM))
Kyösti Mälkki91bfa8e2016-11-20 20:39:56 +0200461 pciexp_enable_clock_power_pm(dev, cap);
Kane Chen18cb1342014-10-01 11:13:54 +0800462
Kenji Chen31c6e632014-10-04 01:14:44 +0800463 /* Enable L1 Sub-State when both root port and endpoint support */
Julius Wernercd49cce2019-03-05 16:53:33 -0800464 if (CONFIG(PCIEXP_L1_SUB_STATE))
Kyösti Mälkki91bfa8e2016-11-20 20:39:56 +0200465 pciexp_config_L1_sub_state(root, dev);
Kenji Chen31c6e632014-10-04 01:14:44 +0800466
Duncan Laurie90dcdd42011-10-25 14:15:11 -0700467 /* Check for and enable ASPM */
Julius Wernercd49cce2019-03-05 16:53:33 -0800468 if (CONFIG(PCIEXP_ASPM))
Kyösti Mälkki91bfa8e2016-11-20 20:39:56 +0200469 pciexp_enable_aspm(root, root_cap, dev, cap);
Kyösti Mälkki94ce79d2019-12-16 17:21:13 +0200470
471 /* Adjust Max_Payload_Size of link ends. */
472 pciexp_set_max_payload_size(root, root_cap, dev, cap);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000473}
474
Kyösti Mälkkide271a82015-03-18 13:09:47 +0200475void pciexp_scan_bus(struct bus *bus, unsigned int min_devfn,
476 unsigned int max_devfn)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000477{
Elyes HAOUASb1fa2872018-05-02 21:11:38 +0200478 struct device *child;
Kyösti Mälkkide271a82015-03-18 13:09:47 +0200479 pci_scan_bus(bus, min_devfn, max_devfn);
Uwe Hermannd453dd02010-10-18 00:00:57 +0000480
481 for (child = bus->children; child; child = child->sibling) {
482 if ((child->path.pci.devfn < min_devfn) ||
483 (child->path.pci.devfn > max_devfn)) {
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000484 continue;
485 }
486 pciexp_tune_dev(child);
487 }
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000488}
489
Elyes HAOUASb1fa2872018-05-02 21:11:38 +0200490void pciexp_scan_bridge(struct device *dev)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000491{
Kyösti Mälkki580e7222015-03-19 21:04:23 +0200492 do_pci_scan_bridge(dev, pciexp_scan_bus);
Aamir Bohra2188f572017-09-22 19:07:21 +0530493 pciexp_enable_ltr(dev);
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000494}
495
496/** Default device operations for PCI Express bridges */
497static struct pci_operations pciexp_bus_ops_pci = {
498 .set_subsystem = 0,
499};
500
501struct device_operations default_pciexp_ops_bus = {
502 .read_resources = pci_bus_read_resources,
503 .set_resources = pci_dev_set_resources,
504 .enable_resources = pci_bus_enable_resources,
Uwe Hermannd453dd02010-10-18 00:00:57 +0000505 .scan_bus = pciexp_scan_bridge,
Yinghai Lu13f1c2a2005-07-08 02:49:49 +0000506 .reset_bus = pci_bus_reset,
507 .ops_pci = &pciexp_bus_ops_pci,
508};
Jeremy Sollercf2ac542019-10-09 21:40:36 -0600509
510#if CONFIG(PCIEXP_HOTPLUG)
511
512static void pciexp_hotplug_dummy_read_resources(struct device *dev)
513{
514 struct resource *resource;
515
516 // Add extra memory space
517 resource = new_resource(dev, 0x10);
518 resource->size = CONFIG_PCIEXP_HOTPLUG_MEM;
519 resource->align = 12;
520 resource->gran = 12;
521 resource->limit = 0xffffffff;
522 resource->flags |= IORESOURCE_MEM;
523
524 // Add extra prefetchable memory space
525 resource = new_resource(dev, 0x14);
526 resource->size = CONFIG_PCIEXP_HOTPLUG_PREFETCH_MEM;
527 resource->align = 12;
528 resource->gran = 12;
529 resource->limit = 0xffffffffffffffff;
530 resource->flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
531
532 // Add extra I/O space
533 resource = new_resource(dev, 0x18);
534 resource->size = CONFIG_PCIEXP_HOTPLUG_IO;
535 resource->align = 12;
536 resource->gran = 12;
537 resource->limit = 0xffff;
538 resource->flags |= IORESOURCE_IO;
539}
540
541static struct device_operations pciexp_hotplug_dummy_ops = {
542 .read_resources = pciexp_hotplug_dummy_read_resources,
543};
544
545void pciexp_hotplug_scan_bridge(struct device *dev)
546{
547 dev->hotplug_buses = CONFIG_PCIEXP_HOTPLUG_BUSES;
548
549 /* Normal PCIe Scan */
550 pciexp_scan_bridge(dev);
551
552 /* Add dummy slot to preserve resources, must happen after bus scan */
553 struct device *dummy;
554 struct device_path dummy_path = { .type = DEVICE_PATH_NONE };
555 dummy = alloc_dev(dev->link_list, &dummy_path);
556 dummy->ops = &pciexp_hotplug_dummy_ops;
557}
558
559struct device_operations default_pciexp_hotplug_ops_bus = {
560 .read_resources = pci_bus_read_resources,
561 .set_resources = pci_dev_set_resources,
562 .enable_resources = pci_bus_enable_resources,
563 .scan_bus = pciexp_hotplug_scan_bridge,
564 .reset_bus = pci_bus_reset,
565 .ops_pci = &pciexp_bus_ops_pci,
566};
567#endif /* CONFIG(PCIEXP_HOTPLUG) */