blob: 86935f8efd0d6af12189db8f2e3539ed61bca165 [file] [log] [blame]
Angel Pons182dbde2020-04-02 23:49:05 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauer8e073822012-04-04 00:07:22 +02002
3#include <console/console.h>
4#include <device/device.h>
5#include <device/pci.h>
Kyösti Mälkkidf128a52019-09-21 18:35:37 +03006#include <device/pci_def.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02007#include <device/pci_ops.h>
Stefan Reinauer8e073822012-04-04 00:07:22 +02008#include <device/pciexp.h>
9#include <device/pci_ids.h>
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +010010#include <southbridge/intel/common/pciehp.h>
Patrick Rudolph604f6982017-06-07 09:46:52 +020011#include <assert.h>
Kyösti Mälkki12b121c2019-08-18 16:33:39 +030012
13#include "chip.h"
Stefan Reinauer8e073822012-04-04 00:07:22 +020014#include "pch.h"
15
Stefan Reinauer8e073822012-04-04 00:07:22 +020016static void pch_pcie_pm_early(struct device *dev)
17{
18 u16 link_width_p0, link_width_p4;
19 u8 slot_power_limit = 10; /* 10W for x1 */
20 u32 reg32;
21 u8 reg8;
22
Duncan Laurie4aca5d72012-04-27 10:58:22 -070023 reg32 = RCBA32(RPC);
24
25 /* Port 0-3 link aggregation from PCIEPCS1[1:0] soft strap */
26 switch (reg32 & 3) {
27 case 3:
28 link_width_p0 = 4;
29 break;
30 case 1:
31 case 2:
32 link_width_p0 = 2;
33 break;
34 case 0:
35 default:
36 link_width_p0 = 1;
37 }
38
39 /* Port 4-7 link aggregation from PCIEPCS2[1:0] soft strap */
40 switch ((reg32 >> 2) & 3) {
41 case 3:
42 link_width_p4 = 4;
43 break;
44 case 1:
45 case 2:
46 link_width_p4 = 2;
47 break;
48 case 0:
49 default:
50 link_width_p4 = 1;
51 }
Stefan Reinauer8e073822012-04-04 00:07:22 +020052
53 /* Enable dynamic clock gating where needed */
54 reg8 = pci_read_config8(dev, 0xe1);
55 switch (PCI_FUNC(dev->path.pci.devfn)) {
56 case 0: /* Port 0 */
57 if (link_width_p0 == 4)
58 slot_power_limit = 40; /* 40W for x4 */
59 else if (link_width_p0 == 2)
60 slot_power_limit = 20; /* 20W for x2 */
Duncan Laurie4aca5d72012-04-27 10:58:22 -070061 reg8 |= 0x3f;
62 break;
Stefan Reinauer8e073822012-04-04 00:07:22 +020063 case 4: /* Port 4 */
64 if (link_width_p4 == 4)
65 slot_power_limit = 40; /* 40W for x4 */
66 else if (link_width_p4 == 2)
67 slot_power_limit = 20; /* 20W for x2 */
68 reg8 |= 0x3f;
69 break;
70 case 1: /* Port 1 only if Port 0 is x1 */
71 if (link_width_p0 == 1)
72 reg8 |= 0x3;
73 break;
74 case 2: /* Port 2 only if Port 0 is x1 or x2 */
75 case 3: /* Port 3 only if Port 0 is x1 or x2 */
76 if (link_width_p0 <= 2)
77 reg8 |= 0x3;
78 break;
79 case 5: /* Port 5 only if Port 4 is x1 */
80 if (link_width_p4 == 1)
81 reg8 |= 0x3;
82 break;
83 case 6: /* Port 7 only if Port 4 is x1 or x2 */
84 case 7: /* Port 7 only if Port 4 is x1 or x2 */
85 if (link_width_p4 <= 2)
86 reg8 |= 0x3;
87 break;
88 }
89 pci_write_config8(dev, 0xe1, reg8);
90
91 /* Set 0xE8[0] = 1 */
92 reg32 = pci_read_config32(dev, 0xe8);
93 reg32 |= 1;
94 pci_write_config32(dev, 0xe8, reg32);
95
96 /* Adjust Common Clock exit latency */
97 reg32 = pci_read_config32(dev, 0xd8);
98 reg32 &= ~(1 << 17);
99 reg32 |= (1 << 16) | (1 << 15);
100 reg32 &= ~(1 << 31); /* Disable PME# SCI for native PME handling */
101 pci_write_config32(dev, 0xd8, reg32);
102
103 /* Adjust ASPM L1 exit latency */
104 reg32 = pci_read_config32(dev, 0x4c);
105 reg32 &= ~((1 << 17) | (1 << 16) | (1 << 15));
Patrick Rudolph4f8b1082019-07-14 11:54:58 +0200106 if (RCBA32(CIR9) & (1 << 16)) {
Stefan Reinauer8e073822012-04-04 00:07:22 +0200107 /* If RCBA+2320[15]=1 set ASPM L1 to 8-16us */
108 reg32 |= (1 << 17);
109 } else {
110 /* Else set ASPM L1 to 2-4us */
111 reg32 |= (1 << 16);
112 }
113 pci_write_config32(dev, 0x4c, reg32);
114
115 /* Set slot power limit as configured above */
116 reg32 = pci_read_config32(dev, 0x54);
117 reg32 &= ~((1 << 15) | (1 << 16)); /* 16:15 = Slot power scale */
118 reg32 &= ~(0xff << 7); /* 14:7 = Slot power limit */
119 reg32 |= (slot_power_limit << 7);
120 pci_write_config32(dev, 0x54, reg32);
121}
122
123static void pch_pcie_pm_late(struct device *dev)
124{
Marc Jones4adc8cd2012-10-31 16:24:37 -0600125 struct southbridge_intel_bd82x6x_config *config = dev->chip_info;
126 enum aspm_type apmc = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200127 u32 reg32;
128
129 /* Set 0x314 = 0x743a361b */
Kyösti Mälkkifd98c652013-07-26 08:50:53 +0300130 pci_write_config32(dev, 0x314, 0x743a361b);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200131
132 /* Set 0x318[31:16] = 0x1414 */
Kyösti Mälkkifd98c652013-07-26 08:50:53 +0300133 reg32 = pci_read_config32(dev, 0x318);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200134 reg32 &= 0x0000ffff;
135 reg32 |= 0x14140000;
Kyösti Mälkkifd98c652013-07-26 08:50:53 +0300136 pci_write_config32(dev, 0x318, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200137
138 /* Set 0x324[5] = 1 */
Kyösti Mälkkifd98c652013-07-26 08:50:53 +0300139 reg32 = pci_read_config32(dev, 0x324);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200140 reg32 |= (1 << 5);
Kyösti Mälkkifd98c652013-07-26 08:50:53 +0300141 pci_write_config32(dev, 0x324, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200142
143 /* Set 0x330[7:0] = 0x40 */
Kyösti Mälkkifd98c652013-07-26 08:50:53 +0300144 reg32 = pci_read_config32(dev, 0x330);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200145 reg32 &= ~(0xff);
146 reg32 |= 0x40;
Kyösti Mälkkifd98c652013-07-26 08:50:53 +0300147 pci_write_config32(dev, 0x330, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200148
149 /* Set 0x33C[24:0] = 0x854c74 */
Kyösti Mälkkifd98c652013-07-26 08:50:53 +0300150 reg32 = pci_read_config32(dev, 0x33c);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200151 reg32 &= 0xff000000;
152 reg32 |= 0x00854c74;
Kyösti Mälkkifd98c652013-07-26 08:50:53 +0300153 pci_write_config32(dev, 0x33c, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200154
155 /* No IO-APIC, Disable EOI forwarding */
156 reg32 = pci_read_config32(dev, 0xd4);
157 reg32 |= (1 << 1);
158 pci_write_config32(dev, 0xd4, reg32);
159
Marc Jones4adc8cd2012-10-31 16:24:37 -0600160 /* Check for a rootport ASPM override */
161 switch (PCI_FUNC(dev->path.pci.devfn)) {
162 case 0:
163 apmc = config->pcie_aspm_f0;
164 break;
165 case 1:
166 apmc = config->pcie_aspm_f1;
167 break;
168 case 2:
169 apmc = config->pcie_aspm_f2;
170 break;
171 case 3:
172 apmc = config->pcie_aspm_f3;
173 break;
174 case 4:
175 apmc = config->pcie_aspm_f4;
176 break;
177 case 5:
178 apmc = config->pcie_aspm_f5;
179 break;
180 case 6:
181 apmc = config->pcie_aspm_f6;
182 break;
183 case 7:
184 apmc = config->pcie_aspm_f7;
185 break;
186 }
187
188 /* Setup the override or get the real ASPM setting */
189 if (apmc) {
190 reg32 = pci_read_config32(dev, 0xd4);
191 reg32 |= (apmc << 2) | (1 << 4);
192 pci_write_config32(dev, 0xd4, reg32);
193 } else {
194 apmc = pci_read_config32(dev, 0x50) & 3;
195 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200196
197 /* If both L0s and L1 enabled then set root port 0xE8[1]=1 */
198 if (apmc == PCIE_ASPM_BOTH) {
199 reg32 = pci_read_config32(dev, 0xe8);
200 reg32 |= (1 << 1);
201 pci_write_config32(dev, 0xe8, reg32);
202 }
203}
204
205static void pci_init(struct device *dev)
206{
207 u16 reg16;
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100208 struct southbridge_intel_bd82x6x_config *config = dev->chip_info;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200209
210 printk(BIOS_DEBUG, "Initializing PCH PCIe bridge.\n");
211
212 /* Enable Bus Master */
Elyes HAOUAS729c0692020-04-28 19:50:44 +0200213 pci_or_config16(dev, PCI_COMMAND, PCI_COMMAND_MASTER);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200214
215 /* Set Cache Line Size to 0x10 */
216 // This has no effect but the OS might expect it
217 pci_write_config8(dev, 0x0c, 0x10);
218
Kyösti Mälkkidf128a52019-09-21 18:35:37 +0300219 reg16 = pci_read_config16(dev, PCI_BRIDGE_CONTROL);
220 reg16 &= ~PCI_BRIDGE_CTL_PARITY;
221 reg16 |= PCI_BRIDGE_CTL_NO_ISA;
222 pci_write_config16(dev, PCI_BRIDGE_CONTROL, reg16);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200223
224#ifdef EVEN_MORE_DEBUG
Elyes HAOUAS729c0692020-04-28 19:50:44 +0200225 u32 reg32;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200226 reg32 = pci_read_config32(dev, 0x20);
227 printk(BIOS_SPEW, " MBL = 0x%08x\n", reg32);
228 reg32 = pci_read_config32(dev, 0x24);
229 printk(BIOS_SPEW, " PMBL = 0x%08x\n", reg32);
230 reg32 = pci_read_config32(dev, 0x28);
231 printk(BIOS_SPEW, " PMBU32 = 0x%08x\n", reg32);
232 reg32 = pci_read_config32(dev, 0x2c);
233 printk(BIOS_SPEW, " PMLU32 = 0x%08x\n", reg32);
234#endif
235
236 /* Clear errors in status registers */
237 reg16 = pci_read_config16(dev, 0x06);
238 //reg16 |= 0xf900;
239 pci_write_config16(dev, 0x06, reg16);
240
241 reg16 = pci_read_config16(dev, 0x1e);
242 //reg16 |= 0xf900;
243 pci_write_config16(dev, 0x1e, reg16);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100244
245 /* Enable expresscard hotplug events. */
246 if (config->pcie_hotplug_map[PCI_FUNC(dev->path.pci.devfn)]) {
247 pci_write_config32(dev, 0xd8,
248 pci_read_config32(dev, 0xd8)
249 | (1 << 30));
250 pci_write_config16(dev, 0x42, 0x142);
251 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200252}
253
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200254static void pch_pcie_enable(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200255{
256 /* Power Management init before enumeration */
257 pch_pcie_pm_early(dev);
258}
259
Elyes HAOUAS4aec3402018-05-25 08:29:27 +0200260static void pch_pciexp_scan_bridge(struct device *dev)
Marc Jones4adc8cd2012-10-31 16:24:37 -0600261{
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100262 struct southbridge_intel_bd82x6x_config *config = dev->chip_info;
Marc Jones4adc8cd2012-10-31 16:24:37 -0600263
264 /* Normal PCIe Scan */
Kyösti Mälkki580e7222015-03-19 21:04:23 +0200265 pciexp_scan_bridge(dev);
Marc Jones4adc8cd2012-10-31 16:24:37 -0600266
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100267 if (config->pcie_hotplug_map[PCI_FUNC(dev->path.pci.devfn)]) {
268 intel_acpi_pcie_hotplug_scan_slot(dev->link_list);
269 }
270
Marc Jones4adc8cd2012-10-31 16:24:37 -0600271 /* Late Power Management init after bridge device enumeration */
272 pch_pcie_pm_late(dev);
Marc Jones4adc8cd2012-10-31 16:24:37 -0600273}
274
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600275static const char *pch_pcie_acpi_name(const struct device *dev)
Patrick Rudolph604f6982017-06-07 09:46:52 +0200276{
277 ASSERT(dev);
278
279 if (PCI_SLOT(dev->path.pci.devfn) == 0x1c) {
280 static const char *names[] = { "RP01",
281 "RP02",
282 "RP03",
283 "RP04",
284 "RP05",
285 "RP06",
286 "RP07",
287 "RP08"};
288
289 return names[PCI_FUNC(dev->path.pci.devfn)];
290 }
291
292 return NULL;
293}
294
Stefan Reinauer8e073822012-04-04 00:07:22 +0200295static struct pci_operations pci_ops = {
Subrata Banik15ccbf02019-03-20 15:09:44 +0530296 .set_subsystem = pci_dev_set_subsystem,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200297};
298
299static struct device_operations device_ops = {
300 .read_resources = pci_bus_read_resources,
301 .set_resources = pci_dev_set_resources,
302 .enable_resources = pci_bus_enable_resources,
303 .init = pci_init,
304 .enable = pch_pcie_enable,
Marc Jones4adc8cd2012-10-31 16:24:37 -0600305 .scan_bus = pch_pciexp_scan_bridge,
Patrick Rudolph604f6982017-06-07 09:46:52 +0200306 .acpi_name = pch_pcie_acpi_name,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200307 .ops_pci = &pci_ops,
308};
309
Stefan Reinauer9a380ab2012-06-22 13:16:11 -0700310static const unsigned short pci_device_ids[] = { 0x1c10, 0x1c12, 0x1c14, 0x1c16,
311 0x1c18, 0x1c1a, 0x1c1c, 0x1c1e,
312 0x1e10, 0x1e12, 0x1e14, 0x1e16,
313 0x1e18, 0x1e1a, 0x1e1c, 0x1e1e,
314 0 };
Stefan Reinauer8e073822012-04-04 00:07:22 +0200315
Stefan Reinauer9a380ab2012-06-22 13:16:11 -0700316static const struct pci_driver pch_pcie __pci_driver = {
317 .ops = &device_ops,
318 .vendor = PCI_VENDOR_ID_INTEL,
319 .devices = pci_device_ids,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200320};