blob: 5a4999e4b0355efb5e89a152bb2420e828e4aa53 [file] [log] [blame]
Angel Pons4b429832020-04-02 23:48:50 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Patrick Georgi2efc8802012-11-06 11:03:53 +01002
3#include <stdint.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02004#include <device/pci_ops.h>
Patrick Georgi2efc8802012-11-06 11:03:53 +01005#include <device/pci_def.h>
Patrick Georgi2efc8802012-11-06 11:03:53 +01006#include <console/console.h>
7
8#include "gm45.h"
9
10static void init_egress(void)
11{
12 /* VC0: TC0 only */
13 EPBAR8(0x14) &= 1;
14 EPBAR8(0x4) = (EPBAR8(0x4) & ~7) | 1;
15
16 /* VC1: isoch */
17 EPBAR32(0x28) = 0x0a0a0a0a;
18 EPBAR32(0x1c) = (EPBAR32(0x1c) & ~(127 << 16)) | (0x0a << 16);
19
20 /* VC1: ID1, TC7 */
21 EPBAR32(0x20) = (EPBAR32(0x20) & ~(7 << 24)) | (1 << 24);
22 EPBAR8(0x20) = (EPBAR8(0x20) & 1) | (1 << 7);
23
24 /* VC1 ARB table: setup and enable */
25 EPBAR32(0x100) = 0x55555555;
26 EPBAR32(0x104) = 0x55555555;
27 EPBAR32(0x108) = 0x55555555;
28 EPBAR32(0x10c) = 0x55555555;
29 EPBAR32(0x110) = 0x55555555;
30 EPBAR32(0x114) = 0x55555555;
31 EPBAR32(0x118) = 0x55555555;
32 EPBAR32(0x11c) = 0x00005555;
33 EPBAR32(0x20) |= 1 << 16;
34
Elyes HAOUAS7db506c2016-10-02 11:56:39 +020035 while ((EPBAR8(0x26) & 1) != 0);
Patrick Georgi2efc8802012-11-06 11:03:53 +010036
37 /* VC1: enable */
38 EPBAR32(0x20) |= 1 << 31;
39
Elyes HAOUAS7db506c2016-10-02 11:56:39 +020040 while ((EPBAR8(0x26) & 2) != 0);
Patrick Georgi2efc8802012-11-06 11:03:53 +010041}
42
43/* MCH side */
44/* b2step: b2 stepping or higher */
45static void init_dmi(int b2step)
46{
47 /* VC0: TC0 only */
48 DMIBAR8(DMIVC0RCTL) &= 1;
49 DMIBAR8(0x4) = (DMIBAR8(0x4) & ~7) | 1;
50
51 /* VC1: ID1, TC7 */
52 DMIBAR32(0x20) = (DMIBAR32(0x20) & ~(7 << 24)) | (1 << 24);
53 DMIBAR8(0x20) = (DMIBAR8(0x20) & 1) | (1 << 7);
54
55 /* VC1: enable */
56 DMIBAR32(0x20) |= 1 << 31;
57
Elyes HAOUAS7db506c2016-10-02 11:56:39 +020058 while ((DMIBAR8(0x26) & 2) != 0);
Patrick Georgi2efc8802012-11-06 11:03:53 +010059
60 /* additional configuration. */
61 DMIBAR32(0x200) |= 3 << 13;
62 DMIBAR32(0x200) &= ~(1 << 21);
63 DMIBAR32(0x200) = (DMIBAR32(0x200) & ~(3 << 26)) | (2 << 26);
64 DMIBAR32(0x2c) = 0x86000040;
65 DMIBAR32(0xfc) |= 1 << 0;
66 DMIBAR32(0xfc) |= 1 << 1;
67 DMIBAR32(0xfc) |= 1 << 4;
68 if (!b2step) {
69 DMIBAR32(0xfc) |= 1 << 11;
70 } else {
71 DMIBAR32(0xfc) &= ~(1 << 11);
72 }
73 DMIBAR32(0x204) &= ~(3 << 10);
74 DMIBAR32(0xf4) &= ~(1 << 4);
75 DMIBAR32(0xf0) |= 3 << 24;
76 DMIBAR32(0xf04) = 0x07050880;
77 DMIBAR32(0xf44) = 0x07050880;
78 DMIBAR32(0xf84) = 0x07050880;
79 DMIBAR32(0xfc4) = 0x07050880;
80
81 /* lock down write-once registers
82 DMIBAR32(0x84) will be set in setup_aspm(). */
83 DMIBAR32(0x308) = DMIBAR32(0x308);
84 DMIBAR32(0x314) = DMIBAR32(0x314);
85 DMIBAR32(0x324) = DMIBAR32(0x324);
86 DMIBAR32(0x328) = DMIBAR32(0x328);
87 DMIBAR32(0x334) = DMIBAR32(0x334);
88 DMIBAR32(0x338) = DMIBAR32(0x338);
89}
90
91static void init_pcie(const int peg_enabled,
92 const int sdvo_enabled,
93 const int peg_x16)
94{
Furquan Shaikh25f75b22016-08-29 22:51:41 -070095 const pci_devfn_t mch = PCI_DEV(0, 0, 0);
96 const pci_devfn_t pciex = PCI_DEV(0, 1, 0);
Patrick Georgi2efc8802012-11-06 11:03:53 +010097
98 printk(BIOS_DEBUG, "PEG x%d %s, SDVO %s\n", peg_x16?16:1,
99 peg_enabled?"enabled":"disabled",
100 sdvo_enabled?"enabled":"disabled");
101
102 if (peg_enabled) {
Angel Ponsb0535832020-06-08 11:46:58 +0200103 pci_or_config8(mch, D0F0_DEVEN, 1 << 1);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100104
Angel Ponsb0535832020-06-08 11:46:58 +0200105 pci_write_config8(pciex, 0x224,
106 (pci_read_config8(pciex, 0x224) & ~31) | (peg_x16 ? 16 : 0) | 1);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100107
Angel Ponsb0535832020-06-08 11:46:58 +0200108 pci_and_config16(pciex, 0x224, ~(1 << 8));
Patrick Georgi2efc8802012-11-06 11:03:53 +0100109
110 /* FIXME: fill in: slot or fixed? -> devicetree */
111 int peg_is_slot = 0;
112 if (peg_is_slot) {
Angel Ponsb0535832020-06-08 11:46:58 +0200113 pci_or_config16(pciex, PEG_CAP, 1 << 8);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100114 }
115
116 /* FIXME: fill in: slot number, slot power -> devicetree */
117 /* Use slot number 0 by now, slots on sb count from 1. */
118 int peg_slot = 0; /* unique within chassis */
119 /* peg_power := val * 10^-exp */
120 int peg_power_val = 75;
121 int peg_power_exp = 0; /* 0..3 */
Angel Ponsb0535832020-06-08 11:46:58 +0200122 const u32 tmp = (peg_slot << 17) | (peg_power_exp << 15) | (peg_power_val << 7);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100123 pci_write_config32(pciex, SLOTCAP, tmp);
124
125 /* GPEs */
Angel Ponsb0535832020-06-08 11:46:58 +0200126 pci_or_config8(pciex, PEGLC, 7);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100127
128 /* VC0: TC0 only, VC0 only */
Angel Ponsb0535832020-06-08 11:46:58 +0200129 pci_and_config8(pciex, D1F0_VC0RCTL, 1);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100130
Angel Ponsb0535832020-06-08 11:46:58 +0200131 pci_and_config8(pciex, D1F0_VCCAP, ~7);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100132 }
133}
134
135static void setup_aspm(const stepping_t stepping, const int peg_enabled)
136{
137 u32 tmp32;
Furquan Shaikh25f75b22016-08-29 22:51:41 -0700138 const pci_devfn_t pciex = PCI_DEV(0, 1, 0);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100139
140 /* Prerequisites for ASPM: */
141 if (peg_enabled) {
Angel Ponsb0535832020-06-08 11:46:58 +0200142 pci_or_config32(pciex, 0x200, 3 << 13);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100143
Angel Ponsb0535832020-06-08 11:46:58 +0200144 pci_and_config32(pciex, 0x0f0, ~((1 << 27) | (1 << 26)));
Patrick Georgi2efc8802012-11-06 11:03:53 +0100145
Angel Ponsb0535832020-06-08 11:46:58 +0200146 pci_or_config32(pciex, 0x0f0, 3 << 24);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100147
Angel Ponsb0535832020-06-08 11:46:58 +0200148 pci_and_config32(pciex, 0x0f4, ~(1 << 4));
Patrick Georgi2efc8802012-11-06 11:03:53 +0100149
Angel Ponsb0535832020-06-08 11:46:58 +0200150 pci_or_config32(pciex, 0x0fc, 1 << 0);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100151
Angel Ponsb0535832020-06-08 11:46:58 +0200152 pci_or_config32(pciex, 0x0fc, 1 << 1);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100153
Angel Ponsb0535832020-06-08 11:46:58 +0200154 pci_or_config32(pciex, 0x0fc, 1 << 4);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100155
Angel Ponsb0535832020-06-08 11:46:58 +0200156 pci_and_config32(pciex, 0x0fc, ~(7 << 5));
Patrick Georgi2efc8802012-11-06 11:03:53 +0100157
158 /* Set L0s, L1 supported in LCTL? */
Angel Ponsb0535832020-06-08 11:46:58 +0200159 pci_or_config32(pciex, 0x0b0, 3 << 0);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100160
Angel Ponsb0535832020-06-08 11:46:58 +0200161 pci_or_config32(pciex, 0x0f0, 3 << 24);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100162
163 tmp32 = pci_read_config32(pciex, 0x0f0);
164 if ((stepping >= STEPPING_B0) && (stepping <= STEPPING_B1))
165 tmp32 |= (1 << 31);
166 else if (stepping >= STEPPING_B2)
167 tmp32 &= ~(1 << 31);
168 pci_write_config32(pciex, 0x0f0, tmp32);
169
170 tmp32 = pci_read_config32(pciex, 0x0fc);
171 if ((stepping >= STEPPING_B0) && (stepping <= STEPPING_B1))
172 tmp32 |= (1 << 10);
173 else if (stepping >= STEPPING_B2)
174 tmp32 &= ~(1 << 10);
175 pci_write_config32(pciex, 0x0fc, tmp32);
176
177 tmp32 = pci_read_config32(pciex, 0x0fc);
178 if (stepping >= STEPPING_B2)
179 tmp32 |= (1 << 14);
180 pci_write_config32(pciex, 0x0fc, tmp32);
181
182 tmp32 = pci_read_config32(pciex, 0x0fc);
183 if (stepping >= STEPPING_B1)
184 tmp32 &= ~(1 << 13);
185 pci_write_config32(pciex, 0x0fc, tmp32);
186 }
187 DMIBAR8 (0x0e1c) |= (1 << 0);
188 DMIBAR16(0x0f00) |= (3 << 8);
189 DMIBAR16(0x0f00) |= (7 << 3);
190 DMIBAR32(0x0f14) &= ~(1 << 17);
191 DMIBAR16(0x0e1c) &= ~(1 << 8);
192 if (stepping >= STEPPING_B0) {
193 DMIBAR32(0x0e28 + 4) = (DMIBAR32(0x0e28 + 4) &
194 ~(0xf << (52 - 32))) |
195 (0xd << (52 - 32));
196 DMIBAR32(0x0e2c) = 0x88d07333;
197 }
198 if (peg_enabled) {
Angel Ponsb0535832020-06-08 11:46:58 +0200199 pci_and_config32(pciex, 0xa08, ~(1 << 15));
Patrick Georgi2efc8802012-11-06 11:03:53 +0100200
Angel Ponsb0535832020-06-08 11:46:58 +0200201 pci_or_config32(pciex, 0xa84, 1 << 8);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100202
Angel Ponsb0535832020-06-08 11:46:58 +0200203 pci_and_config32(pciex, 0xb14, ~(1 << 17));
Patrick Georgi2efc8802012-11-06 11:03:53 +0100204
Angel Ponsb0535832020-06-08 11:46:58 +0200205 pci_or_config32(pciex, 0xb00, 3 << 8);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100206
Angel Ponsb0535832020-06-08 11:46:58 +0200207 pci_or_config32(pciex, 0xb00, 7 << 3);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100208
Angel Ponsb0535832020-06-08 11:46:58 +0200209 pci_and_config32(pciex, 0xa84, ~(1 << 8));
Patrick Georgi2efc8802012-11-06 11:03:53 +0100210
Angel Ponsb0535832020-06-08 11:46:58 +0200211 pci_or_config32(pciex, 0xa84, 1 << 8);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100212
Angel Ponsb0535832020-06-08 11:46:58 +0200213 pci_update_config32(pciex, 0xb04, ~(0x1f << 23), 0x0e << 23);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100214
Angel Ponsb0535832020-06-08 11:46:58 +0200215 pci_or_config32(pciex, 0xb04, 1 << 31);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100216
Angel Ponsb0535832020-06-08 11:46:58 +0200217 pci_update_config32(pciex, 0xb04, ~(0x03 << 29), 0x01 << 29);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100218 }
219
Patrick Georgi2efc8802012-11-06 11:03:53 +0100220 /*\ Setup ASPM on DMI \*/
221
222 /* Exit latencies should be checked to be supported by
223 the endpoint (ICH), but ICH doesn't give any limits. */
224
225 if (LPC_IS_MOBILE(PCI_DEV(0, 0x1f, 0)))
226 DMIBAR8(0x88) |= (3 << 0); // enable ASPM L0s, L1 (write-once)
227 else
228 DMIBAR8(0x88) |= (1 << 0); // enable ASPM L0s (write-once)
229 /* timing */
230 DMIBAR32(0x84) = (DMIBAR32(0x84) & ~(63 << 12)) | (2 << 12) | (2 << 15);
231 DMIBAR8(0x208 + 3) = 0;
232 DMIBAR32(0x208) &= ~(3 << 20);
233
Patrick Georgi2efc8802012-11-06 11:03:53 +0100234 /*\ Setup ASPM on PEG \*/
235 /*
236 * Maybe we just have to advertise ASPM through LCAP[11:10]
237 * (LCAP[17:15] == 010b is the default, will be locked, as it's R/WO),
238 * set 0x208[31:24,23:22] to zero, 0x224[24:21] = 1 and let the
Martin Roth0cd338e2016-07-29 14:07:30 -0600239 * generic ASPM code do the rest? - Nico
Patrick Georgi2efc8802012-11-06 11:03:53 +0100240 */
241 /* TODO: Prepare PEG for ASPM. */
242}
243
244static void setup_rcrb(const int peg_enabled)
245{
246 /*\ RCRB setup: Egress Port \*/
247
248 /* Set component ID of MCH (1). */
249 EPBAR8(EPESD + 2) = 1;
250
251 /* Link1: component ID 1, link valid. */
252 EPBAR32(EPLE1D) = (EPBAR32(EPLE1D) & 0xff000000) | (1 << 16) | (1 << 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800253 EPBAR32(EPLE1A) = (uintptr_t)DEFAULT_DMIBAR;
Patrick Georgi2efc8802012-11-06 11:03:53 +0100254
255 if (peg_enabled)
256 /* Link2: link_valid. */
257 EPBAR8(EPLE2D) |= (1 << 0); /* link valid */
258
Patrick Georgi2efc8802012-11-06 11:03:53 +0100259 /*\ RCRB setup: DMI Port \*/
260
261 /* Set component ID of MCH (1). */
262 DMIBAR8(DMIESD + 2) = 1;
263
264 /* Link1: target port 0, component id 2 (ICH), link valid. */
265 DMIBAR32(DMILE1D) = (0 << 24) | (2 << 16) | (1 << 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800266 DMIBAR32(DMILE1A) = (uintptr_t)DEFAULT_RCBA;
Patrick Georgi2efc8802012-11-06 11:03:53 +0100267
268 /* Link2: component ID 1 (MCH), link valid */
269 DMIBAR32(DMILE2D) =
270 (DMIBAR32(DMILE2D) & 0xff000000) | (1 << 16) | (1 << 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800271 DMIBAR32(DMILE2A) = (uintptr_t)DEFAULT_MCHBAR;
Patrick Georgi2efc8802012-11-06 11:03:53 +0100272}
273
274void gm45_late_init(const stepping_t stepping)
275{
Furquan Shaikh25f75b22016-08-29 22:51:41 -0700276 const pci_devfn_t mch = PCI_DEV(0, 0, 0);
Patrick Georgi2efc8802012-11-06 11:03:53 +0100277 const int peg_enabled = (pci_read_config8(mch, D0F0_DEVEN) >> 1) & 1;
278 const int sdvo_enabled = (MCHBAR16(0x40) >> 8) & 1;
279 const int peg_x16 = (peg_enabled && !sdvo_enabled);
280
281 init_egress();
282 init_dmi(stepping >= STEPPING_B2);
283 init_pcie(peg_enabled, sdvo_enabled, peg_x16);
284
285 setup_aspm(stepping, peg_enabled);
286 setup_rcrb(peg_enabled);
287}