blob: 91add02d7c06b3d4719fbb2a0f2b8aafd544b098 [file] [log] [blame]
Stefan Reinauer8e073822012-04-04 00:07:22 +02001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2008-2009 coresystems GmbH
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; version 2 of
9 * the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Stefan Reinauer8e073822012-04-04 00:07:22 +020015 */
16
17#include <console/console.h>
18#include <device/device.h>
19#include <device/pci.h>
20#include <device/pciexp.h>
21#include <device/pci_ids.h>
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +010022#include <southbridge/intel/common/pciehp.h>
Stefan Reinauer8e073822012-04-04 00:07:22 +020023#include "pch.h"
24
Stefan Reinauer8e073822012-04-04 00:07:22 +020025static void pch_pcie_pm_early(struct device *dev)
26{
27 u16 link_width_p0, link_width_p4;
28 u8 slot_power_limit = 10; /* 10W for x1 */
29 u32 reg32;
30 u8 reg8;
31
Duncan Laurie4aca5d72012-04-27 10:58:22 -070032 reg32 = RCBA32(RPC);
33
34 /* Port 0-3 link aggregation from PCIEPCS1[1:0] soft strap */
35 switch (reg32 & 3) {
36 case 3:
37 link_width_p0 = 4;
38 break;
39 case 1:
40 case 2:
41 link_width_p0 = 2;
42 break;
43 case 0:
44 default:
45 link_width_p0 = 1;
46 }
47
48 /* Port 4-7 link aggregation from PCIEPCS2[1:0] soft strap */
49 switch ((reg32 >> 2) & 3) {
50 case 3:
51 link_width_p4 = 4;
52 break;
53 case 1:
54 case 2:
55 link_width_p4 = 2;
56 break;
57 case 0:
58 default:
59 link_width_p4 = 1;
60 }
Stefan Reinauer8e073822012-04-04 00:07:22 +020061
62 /* Enable dynamic clock gating where needed */
63 reg8 = pci_read_config8(dev, 0xe1);
64 switch (PCI_FUNC(dev->path.pci.devfn)) {
65 case 0: /* Port 0 */
66 if (link_width_p0 == 4)
67 slot_power_limit = 40; /* 40W for x4 */
68 else if (link_width_p0 == 2)
69 slot_power_limit = 20; /* 20W for x2 */
Duncan Laurie4aca5d72012-04-27 10:58:22 -070070 reg8 |= 0x3f;
71 break;
Stefan Reinauer8e073822012-04-04 00:07:22 +020072 case 4: /* Port 4 */
73 if (link_width_p4 == 4)
74 slot_power_limit = 40; /* 40W for x4 */
75 else if (link_width_p4 == 2)
76 slot_power_limit = 20; /* 20W for x2 */
77 reg8 |= 0x3f;
78 break;
79 case 1: /* Port 1 only if Port 0 is x1 */
80 if (link_width_p0 == 1)
81 reg8 |= 0x3;
82 break;
83 case 2: /* Port 2 only if Port 0 is x1 or x2 */
84 case 3: /* Port 3 only if Port 0 is x1 or x2 */
85 if (link_width_p0 <= 2)
86 reg8 |= 0x3;
87 break;
88 case 5: /* Port 5 only if Port 4 is x1 */
89 if (link_width_p4 == 1)
90 reg8 |= 0x3;
91 break;
92 case 6: /* Port 7 only if Port 4 is x1 or x2 */
93 case 7: /* Port 7 only if Port 4 is x1 or x2 */
94 if (link_width_p4 <= 2)
95 reg8 |= 0x3;
96 break;
97 }
98 pci_write_config8(dev, 0xe1, reg8);
99
100 /* Set 0xE8[0] = 1 */
101 reg32 = pci_read_config32(dev, 0xe8);
102 reg32 |= 1;
103 pci_write_config32(dev, 0xe8, reg32);
104
105 /* Adjust Common Clock exit latency */
106 reg32 = pci_read_config32(dev, 0xd8);
107 reg32 &= ~(1 << 17);
108 reg32 |= (1 << 16) | (1 << 15);
109 reg32 &= ~(1 << 31); /* Disable PME# SCI for native PME handling */
110 pci_write_config32(dev, 0xd8, reg32);
111
112 /* Adjust ASPM L1 exit latency */
113 reg32 = pci_read_config32(dev, 0x4c);
114 reg32 &= ~((1 << 17) | (1 << 16) | (1 << 15));
115 if (RCBA32(0x2320) & (1 << 16)) {
116 /* If RCBA+2320[15]=1 set ASPM L1 to 8-16us */
117 reg32 |= (1 << 17);
118 } else {
119 /* Else set ASPM L1 to 2-4us */
120 reg32 |= (1 << 16);
121 }
122 pci_write_config32(dev, 0x4c, reg32);
123
124 /* Set slot power limit as configured above */
125 reg32 = pci_read_config32(dev, 0x54);
126 reg32 &= ~((1 << 15) | (1 << 16)); /* 16:15 = Slot power scale */
127 reg32 &= ~(0xff << 7); /* 14:7 = Slot power limit */
128 reg32 |= (slot_power_limit << 7);
129 pci_write_config32(dev, 0x54, reg32);
130}
131
132static void pch_pcie_pm_late(struct device *dev)
133{
Marc Jones4adc8cd2012-10-31 16:24:37 -0600134 struct southbridge_intel_bd82x6x_config *config = dev->chip_info;
135 enum aspm_type apmc = 0;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200136 u32 reg32;
137
138 /* Set 0x314 = 0x743a361b */
Kyösti Mälkkifd98c652013-07-26 08:50:53 +0300139 pci_write_config32(dev, 0x314, 0x743a361b);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200140
141 /* Set 0x318[31:16] = 0x1414 */
Kyösti Mälkkifd98c652013-07-26 08:50:53 +0300142 reg32 = pci_read_config32(dev, 0x318);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200143 reg32 &= 0x0000ffff;
144 reg32 |= 0x14140000;
Kyösti Mälkkifd98c652013-07-26 08:50:53 +0300145 pci_write_config32(dev, 0x318, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200146
147 /* Set 0x324[5] = 1 */
Kyösti Mälkkifd98c652013-07-26 08:50:53 +0300148 reg32 = pci_read_config32(dev, 0x324);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200149 reg32 |= (1 << 5);
Kyösti Mälkkifd98c652013-07-26 08:50:53 +0300150 pci_write_config32(dev, 0x324, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200151
152 /* Set 0x330[7:0] = 0x40 */
Kyösti Mälkkifd98c652013-07-26 08:50:53 +0300153 reg32 = pci_read_config32(dev, 0x330);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200154 reg32 &= ~(0xff);
155 reg32 |= 0x40;
Kyösti Mälkkifd98c652013-07-26 08:50:53 +0300156 pci_write_config32(dev, 0x330, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200157
158 /* Set 0x33C[24:0] = 0x854c74 */
Kyösti Mälkkifd98c652013-07-26 08:50:53 +0300159 reg32 = pci_read_config32(dev, 0x33c);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200160 reg32 &= 0xff000000;
161 reg32 |= 0x00854c74;
Kyösti Mälkkifd98c652013-07-26 08:50:53 +0300162 pci_write_config32(dev, 0x33c, reg32);
Stefan Reinauer8e073822012-04-04 00:07:22 +0200163
164 /* No IO-APIC, Disable EOI forwarding */
165 reg32 = pci_read_config32(dev, 0xd4);
166 reg32 |= (1 << 1);
167 pci_write_config32(dev, 0xd4, reg32);
168
Marc Jones4adc8cd2012-10-31 16:24:37 -0600169 /* Check for a rootport ASPM override */
170 switch (PCI_FUNC(dev->path.pci.devfn)) {
171 case 0:
172 apmc = config->pcie_aspm_f0;
173 break;
174 case 1:
175 apmc = config->pcie_aspm_f1;
176 break;
177 case 2:
178 apmc = config->pcie_aspm_f2;
179 break;
180 case 3:
181 apmc = config->pcie_aspm_f3;
182 break;
183 case 4:
184 apmc = config->pcie_aspm_f4;
185 break;
186 case 5:
187 apmc = config->pcie_aspm_f5;
188 break;
189 case 6:
190 apmc = config->pcie_aspm_f6;
191 break;
192 case 7:
193 apmc = config->pcie_aspm_f7;
194 break;
195 }
196
197 /* Setup the override or get the real ASPM setting */
198 if (apmc) {
199 reg32 = pci_read_config32(dev, 0xd4);
200 reg32 |= (apmc << 2) | (1 << 4);
201 pci_write_config32(dev, 0xd4, reg32);
202 } else {
203 apmc = pci_read_config32(dev, 0x50) & 3;
204 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200205
206 /* If both L0s and L1 enabled then set root port 0xE8[1]=1 */
207 if (apmc == PCIE_ASPM_BOTH) {
208 reg32 = pci_read_config32(dev, 0xe8);
209 reg32 |= (1 << 1);
210 pci_write_config32(dev, 0xe8, reg32);
211 }
212}
213
214static void pci_init(struct device *dev)
215{
216 u16 reg16;
217 u32 reg32;
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100218 struct southbridge_intel_bd82x6x_config *config = dev->chip_info;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200219
220 printk(BIOS_DEBUG, "Initializing PCH PCIe bridge.\n");
221
222 /* Enable Bus Master */
223 reg32 = pci_read_config32(dev, PCI_COMMAND);
224 reg32 |= PCI_COMMAND_MASTER;
225 pci_write_config32(dev, PCI_COMMAND, reg32);
226
227 /* Set Cache Line Size to 0x10 */
228 // This has no effect but the OS might expect it
229 pci_write_config8(dev, 0x0c, 0x10);
230
231 reg16 = pci_read_config16(dev, 0x3e);
232 reg16 &= ~(1 << 0); /* disable parity error response */
233 // reg16 &= ~(1 << 1); /* disable SERR */
234 reg16 |= (1 << 2); /* ISA enable */
235 pci_write_config16(dev, 0x3e, reg16);
236
237#ifdef EVEN_MORE_DEBUG
238 reg32 = pci_read_config32(dev, 0x20);
239 printk(BIOS_SPEW, " MBL = 0x%08x\n", reg32);
240 reg32 = pci_read_config32(dev, 0x24);
241 printk(BIOS_SPEW, " PMBL = 0x%08x\n", reg32);
242 reg32 = pci_read_config32(dev, 0x28);
243 printk(BIOS_SPEW, " PMBU32 = 0x%08x\n", reg32);
244 reg32 = pci_read_config32(dev, 0x2c);
245 printk(BIOS_SPEW, " PMLU32 = 0x%08x\n", reg32);
246#endif
247
248 /* Clear errors in status registers */
249 reg16 = pci_read_config16(dev, 0x06);
250 //reg16 |= 0xf900;
251 pci_write_config16(dev, 0x06, reg16);
252
253 reg16 = pci_read_config16(dev, 0x1e);
254 //reg16 |= 0xf900;
255 pci_write_config16(dev, 0x1e, reg16);
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100256
257 /* Enable expresscard hotplug events. */
258 if (config->pcie_hotplug_map[PCI_FUNC(dev->path.pci.devfn)]) {
259 pci_write_config32(dev, 0xd8,
260 pci_read_config32(dev, 0xd8)
261 | (1 << 30));
262 pci_write_config16(dev, 0x42, 0x142);
263 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200264}
265
266static void pch_pcie_enable(device_t dev)
267{
268 /* Power Management init before enumeration */
269 pch_pcie_pm_early(dev);
270}
271
Kyösti Mälkki580e7222015-03-19 21:04:23 +0200272static void pch_pciexp_scan_bridge(device_t dev)
Marc Jones4adc8cd2012-10-31 16:24:37 -0600273{
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100274 struct southbridge_intel_bd82x6x_config *config = dev->chip_info;
Marc Jones4adc8cd2012-10-31 16:24:37 -0600275
276 /* Normal PCIe Scan */
Kyösti Mälkki580e7222015-03-19 21:04:23 +0200277 pciexp_scan_bridge(dev);
Marc Jones4adc8cd2012-10-31 16:24:37 -0600278
Vladimir Serbinenko36fa5b82014-10-28 23:43:20 +0100279 if (config->pcie_hotplug_map[PCI_FUNC(dev->path.pci.devfn)]) {
280 intel_acpi_pcie_hotplug_scan_slot(dev->link_list);
281 }
282
Marc Jones4adc8cd2012-10-31 16:24:37 -0600283 /* Late Power Management init after bridge device enumeration */
284 pch_pcie_pm_late(dev);
Marc Jones4adc8cd2012-10-31 16:24:37 -0600285}
286
Stefan Reinauer8e073822012-04-04 00:07:22 +0200287static void pcie_set_subsystem(device_t dev, unsigned vendor, unsigned device)
288{
289 /* NOTE: This is not the default position! */
290 if (!vendor || !device) {
291 pci_write_config32(dev, 0x94,
292 pci_read_config32(dev, 0));
293 } else {
294 pci_write_config32(dev, 0x94,
295 ((device & 0xffff) << 16) | (vendor & 0xffff));
296 }
297}
298
299static struct pci_operations pci_ops = {
300 .set_subsystem = pcie_set_subsystem,
301};
302
303static struct device_operations device_ops = {
304 .read_resources = pci_bus_read_resources,
305 .set_resources = pci_dev_set_resources,
306 .enable_resources = pci_bus_enable_resources,
307 .init = pci_init,
308 .enable = pch_pcie_enable,
Marc Jones4adc8cd2012-10-31 16:24:37 -0600309 .scan_bus = pch_pciexp_scan_bridge,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200310 .ops_pci = &pci_ops,
311};
312
Stefan Reinauer9a380ab2012-06-22 13:16:11 -0700313static const unsigned short pci_device_ids[] = { 0x1c10, 0x1c12, 0x1c14, 0x1c16,
314 0x1c18, 0x1c1a, 0x1c1c, 0x1c1e,
315 0x1e10, 0x1e12, 0x1e14, 0x1e16,
316 0x1e18, 0x1e1a, 0x1e1c, 0x1e1e,
317 0 };
Stefan Reinauer8e073822012-04-04 00:07:22 +0200318
Stefan Reinauer9a380ab2012-06-22 13:16:11 -0700319static const struct pci_driver pch_pcie __pci_driver = {
320 .ops = &device_ops,
321 .vendor = PCI_VENDOR_ID_INTEL,
322 .devices = pci_device_ids,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200323};