blob: 34e56571cad84c36606dfe763eb19e94b4f677ee [file] [log] [blame]
Patrick Georgiac959032020-05-05 22:49:26 +02001/* SPDX-License-Identifier: GPL-2.0-or-later */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003#include <console/console.h>
Elyes HAOUASba9b5042019-12-19 07:47:52 +01004#include <commonlib/helpers.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01005#include <string.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01006#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02007#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +02008#include <device/pci_ops.h>
Kyösti Mälkki1a1b04e2020-01-07 22:34:33 +02009#include <device/smbus_host.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010010#include <cpu/x86/msr.h>
Arthur Heymanse7dd3802019-11-25 12:09:33 +010011#include <cpu/x86/cache.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010012#include <cbmem.h>
Elyes HAOUASd45f3382019-04-28 18:04:35 +020013#include <cf9_reset.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010014#include <ip_checksum.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +020015#include <option.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010016#include <device/pci_def.h>
Patrick Rudolph266a1f72016-06-09 18:13:34 +020017#include <device/device.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010018#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010019#include <spd.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010020#include <timestamp.h>
21#include <cpu/x86/mtrr.h>
22#include <cpu/intel/speedstep.h>
23#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010024#include <mrc_cache.h>
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020025#include <southbridge/intel/ibexpeak/me.h>
Arthur Heymans2878c0b2019-10-14 18:42:00 +020026#include <southbridge/intel/common/pmbase.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010027#include <delay.h>
Elyes HAOUAS51401c32019-05-15 21:09:30 +020028#include <types.h>
29
30#include "chip.h"
Angel Pons95de2312020-02-17 13:08:53 +010031#include "ironlake.h"
Elyes HAOUAS51401c32019-05-15 21:09:30 +020032#include "raminit.h"
Angel Pons18a55cd2019-08-14 20:46:00 +020033#include "raminit_tables.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010034
35#define NORTHBRIDGE PCI_DEV(0, 0, 0)
36#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
37#define GMA PCI_DEV (0, 0x2, 0x0)
38#define HECIDEV PCI_DEV(0, 0x16, 0)
39#define HECIBAR 0x10
40
41#define FOR_ALL_RANKS \
42 for (channel = 0; channel < NUM_CHANNELS; channel++) \
43 for (slot = 0; slot < NUM_SLOTS; slot++) \
44 for (rank = 0; rank < NUM_RANKS; rank++)
45
46#define FOR_POPULATED_RANKS \
47 for (channel = 0; channel < NUM_CHANNELS; channel++) \
48 for (slot = 0; slot < NUM_SLOTS; slot++) \
49 for (rank = 0; rank < NUM_RANKS; rank++) \
50 if (info->populated_ranks[channel][slot][rank])
51
52#define FOR_POPULATED_RANKS_BACKWARDS \
53 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
54 for (slot = 0; slot < NUM_SLOTS; slot++) \
55 for (rank = 0; rank < NUM_RANKS; rank++) \
56 if (info->populated_ranks[channel][slot][rank])
57
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010058#include <lib.h> /* Prototypes */
59
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010060typedef struct _u128 {
61 u64 lo;
62 u64 hi;
63} u128;
64
65static void read128(u32 addr, u64 * out)
66{
67 u128 ret;
68 u128 stor;
69 asm volatile ("movdqu %%xmm0, %0\n"
70 "movdqa (%2), %%xmm0\n"
71 "movdqu %%xmm0, %1\n"
72 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
73 out[0] = ret.lo;
74 out[1] = ret.hi;
75}
76
Angel Ponsc2d6f5f2020-12-11 23:48:51 +010077/*
78 * Ironlake memory I/O timings are located in scan chains, accessible
79 * through MCHBAR register groups. Each channel has a scan chain, and
80 * there's a global scan chain too. Each chain is broken into smaller
81 * sections of N bits, where N <= 32. Each section allows reading and
82 * writing a certain parameter. Each section contains N - 2 data bits
83 * and two additional bits: a Mask bit, and a Halt bit.
84 */
85
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010086/* OK */
87static void write_1d0(u32 val, u16 addr, int bits, int flag)
88{
Felix Held04be2dd2018-07-29 04:53:22 +020089 MCHBAR32(0x1d0) = 0;
90 while (MCHBAR32(0x1d0) & 0x800000)
91 ;
92 MCHBAR32(0x1d4) =
93 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
94 MCHBAR32(0x1d0) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +020095 while (MCHBAR32(0x1d0) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +020096 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010097}
98
99/* OK */
100static u16 read_1d0(u16 addr, int split)
101{
102 u32 val;
Felix Held04be2dd2018-07-29 04:53:22 +0200103 MCHBAR32(0x1d0) = 0;
104 while (MCHBAR32(0x1d0) & 0x800000)
105 ;
106 MCHBAR32(0x1d0) =
107 0x80000000 | (((MCHBAR8(0x246) >> 2) & 3) + 0x361 - addr);
108 while (MCHBAR32(0x1d0) & 0x800000)
109 ;
110 val = MCHBAR32(0x1d8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100111 write_1d0(0, 0x33d, 0, 0);
112 write_1d0(0, 0x33d, 0, 0);
113 val &= ((1 << split) - 1);
114 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
115 return val;
116}
117
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800118static void write32p(uintptr_t addr, uint32_t val)
119{
120 write32((void *)addr, val);
121}
122
123static uint32_t read32p(uintptr_t addr)
124{
125 return read32((void *)addr);
126}
127
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100128static void sfence(void)
129{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100130 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100131}
132
133static inline u16 get_lane_offset(int slot, int rank, int lane)
134{
135 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
136 0x452 * (lane == 8);
137}
138
139static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
140{
141 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
142 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
143}
144
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100145static u32 gav_real(int line, u32 in)
146{
147 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
148 return in;
149}
150
151#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200152
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200153/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100154timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200155
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100156/* OK */
157static u16
158read_500(struct raminfo *info, int channel, u16 addr, int split)
159{
160 u32 val;
161 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200162 MCHBAR32(0x500 + (channel << 10)) = 0;
163 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
164 ;
165 MCHBAR32(0x500 + (channel << 10)) =
166 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
167 + 0xb88 - addr);
168 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
169 ;
170 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100171 return val & ((1 << split) - 1);
172}
173
174/* OK */
175static void
176write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
177 int flag)
178{
179 if (info->last_500_command[channel] == 0x80000000) {
180 info->last_500_command[channel] = 0x40000000;
181 write_500(info, channel, 0, 0xb61, 0, 0);
182 }
Felix Held04be2dd2018-07-29 04:53:22 +0200183 MCHBAR32(0x500 + (channel << 10)) = 0;
184 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
185 ;
186 MCHBAR32(0x504 + (channel << 10)) =
187 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
188 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200189 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200190 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100191}
192
Angel Ponsc10f8b22021-01-15 20:34:51 +0100193static void rmw_500(struct raminfo *info, int channel, u16 addr, int bits, u32 and, u32 or)
194{
195 const u32 val = read_500(info, channel, addr, bits) & and;
196 write_500(info, channel, val | or, addr, bits, 1);
197}
198
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100199static int rw_test(int rank)
200{
201 const u32 mask = 0xf00fc33c;
202 int ok = 0xff;
203 int i;
204 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800205 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100206 sfence();
207 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800208 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100209 sfence();
210 for (i = 0; i < 32; i++) {
211 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800212 write32p((rank << 28) | (i << 3), pat);
213 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100214 }
215 sfence();
216 for (i = 0; i < 32; i++) {
217 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
218 int j;
219 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800220 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100221 for (j = 0; j < 4; j++)
222 if (((val >> (j * 8)) & 0xff) != pat)
223 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800224 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100225 for (j = 0; j < 4; j++)
226 if (((val >> (j * 8)) & 0xff) != pat)
227 ok &= ~(16 << j);
228 }
229 sfence();
230 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800231 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100232 sfence();
233 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800234 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100235
236 return ok;
237}
238
239static void
240program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
241{
242 int lane;
243 for (lane = 0; lane < 8; lane++) {
244 write_500(info, channel,
245 base +
246 info->training.
247 lane_timings[2][channel][slot][rank][lane],
248 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
249 write_500(info, channel,
250 base +
251 info->training.
252 lane_timings[3][channel][slot][rank][lane],
253 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
254 }
255}
256
257static void write_26c(int channel, u16 si)
258{
Felix Held04be2dd2018-07-29 04:53:22 +0200259 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
260 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
261 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100262}
263
Angel Ponsc627dc92020-09-22 17:06:44 +0200264static void toggle_1d0_142_5ff(void)
265{
266 u32 reg32 = gav(read_1d0(0x142, 3));
267 if (reg32 & (1 << 1))
268 write_1d0(0, 0x142, 3, 1);
269
270 MCHBAR8(0x5ff) = 0x0;
271 MCHBAR8(0x5ff) = 0x80;
272 if (reg32 & (1 << 1))
273 write_1d0(0x2, 0x142, 3, 1);
274}
275
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100276static u32 get_580(int channel, u8 addr)
277{
278 u32 ret;
Angel Ponsc627dc92020-09-22 17:06:44 +0200279 toggle_1d0_142_5ff();
Felix Held04be2dd2018-07-29 04:53:22 +0200280 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
281 MCHBAR8_OR(0x580 + (channel << 10), 1);
282 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
283 ;
284 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100285 return ret;
286}
287
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100288#define RANK_SHIFT 28
289#define CHANNEL_SHIFT 10
290
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100291static void seq9(struct raminfo *info, int channel, int slot, int rank)
292{
293 int i, lane;
294
295 for (i = 0; i < 2; i++)
296 for (lane = 0; lane < 8; lane++)
297 write_500(info, channel,
298 info->training.lane_timings[i +
299 1][channel][slot]
300 [rank][lane], get_timing_register_addr(lane,
301 i + 1,
302 slot,
303 rank),
304 9, 0);
305
306 write_1d0(1, 0x103, 6, 1);
307 for (lane = 0; lane < 8; lane++)
308 write_500(info, channel,
309 info->training.
310 lane_timings[0][channel][slot][rank][lane],
311 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
312
313 for (i = 0; i < 2; i++) {
314 for (lane = 0; lane < 8; lane++)
315 write_500(info, channel,
316 info->training.lane_timings[i +
317 1][channel][slot]
318 [rank][lane], get_timing_register_addr(lane,
319 i + 1,
320 slot,
321 rank),
322 9, 0);
323 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
324 }
325
Angel Ponsc627dc92020-09-22 17:06:44 +0200326 toggle_1d0_142_5ff();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100327 write_1d0(0x2, 0x142, 3, 1);
Angel Ponsc627dc92020-09-22 17:06:44 +0200328
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100329 for (lane = 0; lane < 8; lane++) {
330 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
331 info->training.lane_timings[2][channel][slot][rank][lane] =
332 read_500(info, channel,
333 get_timing_register_addr(lane, 2, slot, rank), 9);
334 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
335 info->training.lane_timings[3][channel][slot][rank][lane] =
336 info->training.lane_timings[2][channel][slot][rank][lane] +
337 0x20;
338 }
339}
340
341static int count_ranks_in_channel(struct raminfo *info, int channel)
342{
343 int slot, rank;
344 int res = 0;
345 for (slot = 0; slot < NUM_SLOTS; slot++)
346 for (rank = 0; rank < NUM_SLOTS; rank++)
347 res += info->populated_ranks[channel][slot][rank];
348 return res;
349}
350
351static void
352config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
353{
354 int add;
355
356 write_1d0(0, 0x178, 7, 1);
357 seq9(info, channel, slot, rank);
358 program_timings(info, 0x80, channel, slot, rank);
359
360 if (channel == 0)
361 add = count_ranks_in_channel(info, 1);
362 else
363 add = 0;
364 if (!s3resume)
365 gav(rw_test(rank + add));
366 program_timings(info, 0x00, channel, slot, rank);
367 if (!s3resume)
368 gav(rw_test(rank + add));
369 if (!s3resume)
370 gav(rw_test(rank + add));
371 write_1d0(0, 0x142, 3, 1);
372 write_1d0(0, 0x103, 6, 1);
373
374 gav(get_580(channel, 0xc | (rank << 5)));
375 gav(read_1d0(0x142, 3));
376
Felix Held04be2dd2018-07-29 04:53:22 +0200377 MCHBAR8(0x5ff) = 0x0;
378 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100379}
380
Angel Ponsc10f8b22021-01-15 20:34:51 +0100381static void set_4cf(struct raminfo *info, int channel, u8 bit, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100382{
Angel Ponsc10f8b22021-01-15 20:34:51 +0100383 const u16 regtable[] = { 0x4cf, 0x659, 0x697 };
384
385 val &= 1;
386 for (int i = 0; i < ARRAY_SIZE(regtable); i++)
387 rmw_500(info, channel, regtable[i], 4, ~(1 << bit), val << bit);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100388}
389
390static void set_334(int zero)
391{
392 int j, k, channel;
393 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
394 u32 vd8[2][16];
395
396 for (channel = 0; channel < NUM_CHANNELS; channel++) {
397 for (j = 0; j < 4; j++) {
398 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
399 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
400 u16 c;
401 if ((j == 0 || j == 3) && zero)
402 c = 0;
403 else if (j == 3)
404 c = 0x5f;
405 else
406 c = 0x5f5f;
407
408 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200409 MCHBAR32(0x138 + 8 * k) =
410 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100411 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200412 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100413 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200414 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100415 }
416
Felix Held22ca8cb2018-07-29 05:09:44 +0200417 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
418 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200419 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
420 zero ? 0 : (0x18191819 & lmask);
421 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
422 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
423 zero ? 0 : (a & lmask);
424 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
425 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100426 }
427 }
428
Felix Held04be2dd2018-07-29 04:53:22 +0200429 MCHBAR32_OR(0x130, 1);
430 while (MCHBAR8(0x130) & 1)
431 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100432}
433
Angel Pons244f4552021-01-15 20:41:36 +0100434static void rmw_1d0(u16 addr, u32 and, u32 or, int split)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100435{
436 u32 v;
437 v = read_1d0(addr, split);
Angel Pons244f4552021-01-15 20:41:36 +0100438 write_1d0((v & and) | or, addr, split, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100439}
440
441static int find_highest_bit_set(u16 val)
442{
443 int i;
444 for (i = 15; i >= 0; i--)
445 if (val & (1 << i))
446 return i;
447 return -1;
448}
449
450static int find_lowest_bit_set32(u32 val)
451{
452 int i;
453 for (i = 0; i < 32; i++)
454 if (val & (1 << i))
455 return i;
456 return -1;
457}
458
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100459enum {
460 DEVICE_TYPE = 2,
461 MODULE_TYPE = 3,
462 DENSITY = 4,
463 RANKS_AND_DQ = 7,
464 MEMORY_BUS_WIDTH = 8,
465 TIMEBASE_DIVIDEND = 10,
466 TIMEBASE_DIVISOR = 11,
467 CYCLETIME = 12,
468
469 CAS_LATENCIES_LSB = 14,
470 CAS_LATENCIES_MSB = 15,
471 CAS_LATENCY_TIME = 16,
472 THERMAL_AND_REFRESH = 31,
473 REFERENCE_RAW_CARD_USED = 62,
474 RANK1_ADDRESS_MAPPING = 63
475};
476
477static void calculate_timings(struct raminfo *info)
478{
Martin Roth468d02c2019-10-23 21:44:42 -0600479 unsigned int cycletime;
480 unsigned int cas_latency_time;
481 unsigned int supported_cas_latencies;
482 unsigned int channel, slot;
483 unsigned int clock_speed_index;
484 unsigned int min_cas_latency;
485 unsigned int cas_latency;
486 unsigned int max_clock_index;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100487
488 /* Find common CAS latency */
489 supported_cas_latencies = 0x3fe;
490 for (channel = 0; channel < NUM_CHANNELS; channel++)
491 for (slot = 0; slot < NUM_SLOTS; slot++)
492 if (info->populated_ranks[channel][slot][0])
493 supported_cas_latencies &=
494 2 *
495 (info->
496 spd[channel][slot][CAS_LATENCIES_LSB] |
497 (info->
498 spd[channel][slot][CAS_LATENCIES_MSB] <<
499 8));
500
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100501 max_clock_index = MIN(3, info->max_supported_clock_speed_index);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100502
503 cycletime = min_cycletime[max_clock_index];
504 cas_latency_time = min_cas_latency_time[max_clock_index];
505
506 for (channel = 0; channel < NUM_CHANNELS; channel++)
507 for (slot = 0; slot < NUM_SLOTS; slot++)
508 if (info->populated_ranks[channel][slot][0]) {
Martin Roth468d02c2019-10-23 21:44:42 -0600509 unsigned int timebase;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100510 timebase =
511 1000 *
512 info->
513 spd[channel][slot][TIMEBASE_DIVIDEND] /
514 info->spd[channel][slot][TIMEBASE_DIVISOR];
515 cycletime =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100516 MAX(cycletime,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100517 timebase *
518 info->spd[channel][slot][CYCLETIME]);
519 cas_latency_time =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100520 MAX(cas_latency_time,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100521 timebase *
522 info->
523 spd[channel][slot][CAS_LATENCY_TIME]);
524 }
Jacob Garber3c193822019-06-10 18:23:32 -0600525 if (cycletime > min_cycletime[0])
526 die("RAM init: Decoded SPD DRAM freq is slower than the controller minimum!");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100527 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
528 if (cycletime == min_cycletime[clock_speed_index])
529 break;
530 if (cycletime > min_cycletime[clock_speed_index]) {
531 clock_speed_index--;
532 cycletime = min_cycletime[clock_speed_index];
533 break;
534 }
535 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100536 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100537 cas_latency = 0;
538 while (supported_cas_latencies) {
539 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
540 if (cas_latency <= min_cas_latency)
541 break;
542 supported_cas_latencies &=
543 ~(1 << find_highest_bit_set(supported_cas_latencies));
544 }
545
546 if (cas_latency != min_cas_latency && clock_speed_index)
547 clock_speed_index--;
548
549 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
550 die("Couldn't configure DRAM");
551 info->clock_speed_index = clock_speed_index;
552 info->cas_latency = cas_latency;
553}
554
555static void program_base_timings(struct raminfo *info)
556{
Martin Roth468d02c2019-10-23 21:44:42 -0600557 unsigned int channel;
558 unsigned int slot, rank, lane;
559 unsigned int extended_silicon_revision;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100560 int i;
561
562 extended_silicon_revision = info->silicon_revision;
563 if (info->silicon_revision == 0)
564 for (channel = 0; channel < NUM_CHANNELS; channel++)
565 for (slot = 0; slot < NUM_SLOTS; slot++)
566 if ((info->
567 spd[channel][slot][MODULE_TYPE] & 0xF) ==
568 3)
569 extended_silicon_revision = 4;
570
571 for (channel = 0; channel < NUM_CHANNELS; channel++) {
572 for (slot = 0; slot < NUM_SLOTS; slot++)
573 for (rank = 0; rank < NUM_SLOTS; rank++) {
574 int card_timing_2;
575 if (!info->populated_ranks[channel][slot][rank])
576 continue;
577
578 for (lane = 0; lane < 9; lane++) {
579 int tm_reg;
580 int card_timing;
581
582 card_timing = 0;
583 if ((info->
584 spd[channel][slot][MODULE_TYPE] &
585 0xF) == 3) {
586 int reference_card;
587 reference_card =
588 info->
589 spd[channel][slot]
590 [REFERENCE_RAW_CARD_USED] &
591 0x1f;
592 if (reference_card == 3)
593 card_timing =
594 u16_ffd1188[0][lane]
595 [info->
596 clock_speed_index];
597 if (reference_card == 5)
598 card_timing =
599 u16_ffd1188[1][lane]
600 [info->
601 clock_speed_index];
602 }
603
604 info->training.
605 lane_timings[0][channel][slot][rank]
606 [lane] =
607 u8_FFFD1218[info->
608 clock_speed_index];
609 info->training.
610 lane_timings[1][channel][slot][rank]
611 [lane] = 256;
612
613 for (tm_reg = 2; tm_reg < 4; tm_reg++)
614 info->training.
615 lane_timings[tm_reg]
616 [channel][slot][rank][lane]
617 =
618 u8_FFFD1240[channel]
619 [extended_silicon_revision]
620 [lane][2 * slot +
621 rank][info->
622 clock_speed_index]
623 + info->max4048[channel]
624 +
625 u8_FFFD0C78[channel]
626 [extended_silicon_revision]
627 [info->
628 mode4030[channel]][slot]
629 [rank][info->
630 clock_speed_index]
631 + card_timing;
632 for (tm_reg = 0; tm_reg < 4; tm_reg++)
633 write_500(info, channel,
634 info->training.
635 lane_timings[tm_reg]
636 [channel][slot][rank]
637 [lane],
638 get_timing_register_addr
639 (lane, tm_reg, slot,
640 rank), 9, 0);
641 }
642
643 card_timing_2 = 0;
644 if (!(extended_silicon_revision != 4
645 || (info->
646 populated_ranks_mask[channel] & 5) ==
647 5)) {
648 if ((info->
649 spd[channel][slot]
650 [REFERENCE_RAW_CARD_USED] & 0x1F)
651 == 3)
652 card_timing_2 =
653 u16_FFFE0EB8[0][info->
654 clock_speed_index];
655 if ((info->
656 spd[channel][slot]
657 [REFERENCE_RAW_CARD_USED] & 0x1F)
658 == 5)
659 card_timing_2 =
660 u16_FFFE0EB8[1][info->
661 clock_speed_index];
662 }
663
664 for (i = 0; i < 3; i++)
665 write_500(info, channel,
666 (card_timing_2 +
667 info->max4048[channel]
668 +
669 u8_FFFD0EF8[channel]
670 [extended_silicon_revision]
671 [info->
672 mode4030[channel]][info->
673 clock_speed_index]),
674 u16_fffd0c50[i][slot][rank],
675 8, 1);
676 write_500(info, channel,
677 (info->max4048[channel] +
678 u8_FFFD0C78[channel]
679 [extended_silicon_revision][info->
680 mode4030
681 [channel]]
682 [slot][rank][info->
683 clock_speed_index]),
684 u16_fffd0c70[slot][rank], 7, 1);
685 }
686 if (!info->populated_ranks_mask[channel])
687 continue;
688 for (i = 0; i < 3; i++)
689 write_500(info, channel,
690 (info->max4048[channel] +
691 info->avg4044[channel]
692 +
693 u8_FFFD17E0[channel]
694 [extended_silicon_revision][info->
695 mode4030
696 [channel]][info->
697 clock_speed_index]),
698 u16_fffd0c68[i], 8, 1);
699 }
700}
701
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100702/* The time of clock cycle in ps. */
703static unsigned int cycle_ps(struct raminfo *info)
704{
705 return 2 * halfcycle_ps(info);
706}
707
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100708/* Frequency in 0.1 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600709static unsigned int frequency_01(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100710{
711 return 100 * frequency_11(info) / 9;
712}
713
Martin Roth468d02c2019-10-23 21:44:42 -0600714static unsigned int ps_to_halfcycles(struct raminfo *info, unsigned int ps)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100715{
716 return (frequency_11(info) * 2) * ps / 900000;
717}
718
Martin Roth468d02c2019-10-23 21:44:42 -0600719static unsigned int ns_to_cycles(struct raminfo *info, unsigned int ns)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100720{
721 return (frequency_11(info)) * ns / 900;
722}
723
724static void compute_derived_timings(struct raminfo *info)
725{
Martin Roth468d02c2019-10-23 21:44:42 -0600726 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100727 int extended_silicon_revision;
728 int some_delay_1_ps;
729 int some_delay_2_ps;
730 int some_delay_2_halfcycles_ceil;
731 int some_delay_2_halfcycles_floor;
732 int some_delay_3_ps;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100733 int some_delay_3_ps_rounded;
734 int some_delay_1_cycle_ceil;
735 int some_delay_1_cycle_floor;
736
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100737 some_delay_3_ps_rounded = 0;
738 extended_silicon_revision = info->silicon_revision;
739 if (!info->silicon_revision)
740 for (channel = 0; channel < NUM_CHANNELS; channel++)
741 for (slot = 0; slot < NUM_SLOTS; slot++)
742 if ((info->
743 spd[channel][slot][MODULE_TYPE] & 0xF) ==
744 3)
745 extended_silicon_revision = 4;
746 if (info->board_lane_delay[7] < 5)
747 info->board_lane_delay[7] = 5;
748 info->revision_flag_1 = 2;
749 if (info->silicon_revision == 2 || info->silicon_revision == 3)
750 info->revision_flag_1 = 0;
751 if (info->revision < 16)
752 info->revision_flag_1 = 0;
753
754 if (info->revision < 8)
755 info->revision_flag_1 = 0;
756 if (info->revision >= 8 && (info->silicon_revision == 0
757 || info->silicon_revision == 1))
758 some_delay_2_ps = 735;
759 else
760 some_delay_2_ps = 750;
761
762 if (info->revision >= 0x10 && (info->silicon_revision == 0
763 || info->silicon_revision == 1))
764 some_delay_1_ps = 3929;
765 else
766 some_delay_1_ps = 3490;
767
768 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
769 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
770 if (some_delay_1_ps % cycle_ps(info))
771 some_delay_1_cycle_ceil++;
772 else
773 some_delay_1_cycle_floor--;
774 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
775 if (info->revision_flag_1)
776 some_delay_2_ps = halfcycle_ps(info) >> 6;
777 some_delay_2_ps +=
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100778 MAX(some_delay_1_ps - 30,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100779 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
780 375;
781 some_delay_3_ps =
782 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
783 if (info->revision_flag_1) {
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200784 if (some_delay_3_ps >= 150) {
785 const int some_delay_3_halfcycles =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100786 (some_delay_3_ps << 6) / halfcycle_ps(info);
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200787 some_delay_3_ps_rounded =
788 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
789 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100790 }
791 some_delay_2_halfcycles_ceil =
792 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
793 2 * (some_delay_1_cycle_ceil - 1);
794 if (info->revision_flag_1 && some_delay_3_ps < 150)
795 some_delay_2_halfcycles_ceil++;
796 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
797 if (info->revision < 0x10)
798 some_delay_2_halfcycles_floor =
799 some_delay_2_halfcycles_ceil - 1;
800 if (!info->revision_flag_1)
801 some_delay_2_halfcycles_floor++;
802 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
803 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
804 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
805 || (info->populated_ranks[1][0][0]
806 && info->populated_ranks[1][1][0]))
807 info->max_slots_used_in_channel = 2;
808 else
809 info->max_slots_used_in_channel = 1;
810 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200811 MCHBAR32(0x244 + (channel << 10)) =
812 ((info->revision < 8) ? 1 : 0x200) |
813 ((2 - info->max_slots_used_in_channel) << 17) |
814 (channel << 21) |
815 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100816 if (info->max_slots_used_in_channel == 1) {
817 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
818 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
819 } else {
820 info->mode4030[0] = ((count_ranks_in_channel(info, 0) == 1) || (count_ranks_in_channel(info, 0) == 2)) ? 2 : 3; /* 2 if 1 or 2 ranks */
821 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
822 || (count_ranks_in_channel(info, 1) ==
823 2)) ? 2 : 3;
824 }
825 for (channel = 0; channel < NUM_CHANNELS; channel++) {
826 int max_of_unk;
827 int min_of_unk_2;
828
829 int i, count;
830 int sum;
831
832 if (!info->populated_ranks_mask[channel])
833 continue;
834
835 max_of_unk = 0;
836 min_of_unk_2 = 32767;
837
838 sum = 0;
839 count = 0;
840 for (i = 0; i < 3; i++) {
841 int unk1;
842 if (info->revision < 8)
843 unk1 =
844 u8_FFFD1891[0][channel][info->
845 clock_speed_index]
846 [i];
847 else if (!
848 (info->revision >= 0x10
849 || info->revision_flag_1))
850 unk1 =
851 u8_FFFD1891[1][channel][info->
852 clock_speed_index]
853 [i];
854 else
855 unk1 = 0;
856 for (slot = 0; slot < NUM_SLOTS; slot++)
857 for (rank = 0; rank < NUM_RANKS; rank++) {
858 int a = 0;
859 int b = 0;
860
861 if (!info->
862 populated_ranks[channel][slot]
863 [rank])
864 continue;
865 if (extended_silicon_revision == 4
866 && (info->
867 populated_ranks_mask[channel] &
868 5) != 5) {
869 if ((info->
870 spd[channel][slot]
871 [REFERENCE_RAW_CARD_USED] &
872 0x1F) == 3) {
873 a = u16_ffd1178[0]
874 [info->
875 clock_speed_index];
876 b = u16_fe0eb8[0][info->
877 clock_speed_index];
878 } else
879 if ((info->
880 spd[channel][slot]
881 [REFERENCE_RAW_CARD_USED]
882 & 0x1F) == 5) {
883 a = u16_ffd1178[1]
884 [info->
885 clock_speed_index];
886 b = u16_fe0eb8[1][info->
887 clock_speed_index];
888 }
889 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100890 min_of_unk_2 = MIN(min_of_unk_2, a);
891 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100892 if (rank == 0) {
893 sum += a;
894 count++;
895 }
896 {
897 int t;
898 t = b +
899 u8_FFFD0EF8[channel]
900 [extended_silicon_revision]
901 [info->
902 mode4030[channel]][info->
903 clock_speed_index];
904 if (unk1 >= t)
905 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100906 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100907 unk1 - t);
908 }
909 }
910 {
911 int t =
912 u8_FFFD17E0[channel]
913 [extended_silicon_revision][info->
914 mode4030
915 [channel]]
916 [info->clock_speed_index] + min_of_unk_2;
917 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100918 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100919 }
920 }
921
Jacob Garber64fb4a32019-06-10 17:29:18 -0600922 if (count == 0)
923 die("No memory ranks found for channel %u\n", channel);
924
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100925 info->avg4044[channel] = sum / count;
926 info->max4048[channel] = max_of_unk;
927 }
928}
929
930static void jedec_read(struct raminfo *info,
931 int channel, int slot, int rank,
932 int total_rank, u8 addr3, unsigned int value)
933{
934 /* Handle mirrored mapping. */
935 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +0200936 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
937 ((addr3 >> 1) & 0x10);
938 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
939 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100940
941 /* Handle mirrored mapping. */
942 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
943 value =
944 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
945 << 1);
946
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800947 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100948
Felix Held04be2dd2018-07-29 04:53:22 +0200949 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
950 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100951
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800952 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100953}
954
955enum {
956 MR1_RZQ12 = 512,
957 MR1_RZQ2 = 64,
958 MR1_RZQ4 = 4,
959 MR1_ODS34OHM = 2
960};
961
962enum {
963 MR0_BT_INTERLEAVED = 8,
964 MR0_DLL_RESET_ON = 256
965};
966
967enum {
968 MR2_RTT_WR_DISABLED = 0,
969 MR2_RZQ2 = 1 << 10
970};
971
972static void jedec_init(struct raminfo *info)
973{
974 int write_recovery;
975 int channel, slot, rank;
976 int total_rank;
977 int dll_on;
978 int self_refresh_temperature;
979 int auto_self_refresh;
980
981 auto_self_refresh = 1;
982 self_refresh_temperature = 1;
983 if (info->board_lane_delay[3] <= 10) {
984 if (info->board_lane_delay[3] <= 8)
985 write_recovery = info->board_lane_delay[3] - 4;
986 else
987 write_recovery = 5;
988 } else {
989 write_recovery = 6;
990 }
991 FOR_POPULATED_RANKS {
992 auto_self_refresh &=
993 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
994 self_refresh_temperature &=
995 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
996 }
997 if (auto_self_refresh == 1)
998 self_refresh_temperature = 0;
999
1000 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1001 || (info->populated_ranks[0][0][0]
1002 && info->populated_ranks[0][1][0])
1003 || (info->populated_ranks[1][0][0]
1004 && info->populated_ranks[1][1][0]));
1005
1006 total_rank = 0;
1007
1008 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1009 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1010 int rzq_reg58e;
1011
1012 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1013 rzq_reg58e = 64;
1014 rtt = MR1_RZQ2;
1015 if (info->clock_speed_index != 0) {
1016 rzq_reg58e = 4;
1017 if (info->populated_ranks_mask[channel] == 3)
1018 rtt = MR1_RZQ4;
1019 }
1020 } else {
1021 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1022 rtt = MR1_RZQ12;
1023 rzq_reg58e = 64;
1024 rtt_wr = MR2_RZQ2;
1025 } else {
1026 rzq_reg58e = 4;
1027 rtt = MR1_RZQ4;
1028 }
1029 }
1030
Felix Held04be2dd2018-07-29 04:53:22 +02001031 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1032 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1033 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1034 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1035 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001036
1037 for (slot = 0; slot < NUM_SLOTS; slot++)
1038 for (rank = 0; rank < NUM_RANKS; rank++)
1039 if (info->populated_ranks[channel][slot][rank]) {
1040 jedec_read(info, channel, slot, rank,
1041 total_rank, 0x28,
1042 rtt_wr | (info->
1043 clock_speed_index
1044 << 3)
1045 | (auto_self_refresh << 6) |
1046 (self_refresh_temperature <<
1047 7));
1048 jedec_read(info, channel, slot, rank,
1049 total_rank, 0x38, 0);
1050 jedec_read(info, channel, slot, rank,
1051 total_rank, 0x18,
1052 rtt | MR1_ODS34OHM);
1053 jedec_read(info, channel, slot, rank,
1054 total_rank, 6,
1055 (dll_on << 12) |
1056 (write_recovery << 9)
1057 | ((info->cas_latency - 4) <<
1058 4) | MR0_BT_INTERLEAVED |
1059 MR0_DLL_RESET_ON);
1060 total_rank++;
1061 }
1062 }
1063}
1064
1065static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1066{
Martin Roth468d02c2019-10-23 21:44:42 -06001067 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001068 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1069 unsigned int channel_0_non_interleaved;
1070
1071 FOR_ALL_RANKS {
1072 if (info->populated_ranks[channel][slot][rank]) {
1073 total_mb[channel] +=
1074 pre_jedec ? 256 : (256 << info->
1075 density[channel][slot] >> info->
1076 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001077 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1078 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1079 (info->is_x16_module[channel][slot] |
1080 ((info->density[channel][slot] + 1) << 1))) |
1081 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001082 }
Felix Held04be2dd2018-07-29 04:53:22 +02001083 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1084 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001085 }
1086
1087 info->total_memory_mb = total_mb[0] + total_mb[1];
1088
1089 info->interleaved_part_mb =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001090 pre_jedec ? 0 : 2 * MIN(total_mb[0], total_mb[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001091 info->non_interleaved_part_mb =
1092 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1093 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001094 MCHBAR32(0x100) = channel_0_non_interleaved |
1095 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001096 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001097 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001098}
1099
1100static void program_board_delay(struct raminfo *info)
1101{
1102 int cas_latency_shift;
1103 int some_delay_ns;
1104 int some_delay_3_half_cycles;
1105
Martin Roth468d02c2019-10-23 21:44:42 -06001106 unsigned int channel, i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001107 int high_multiplier;
1108 int lane_3_delay;
1109 int cas_latency_derived;
1110
1111 high_multiplier = 0;
1112 some_delay_ns = 200;
1113 some_delay_3_half_cycles = 4;
1114 cas_latency_shift = info->silicon_revision == 0
1115 || info->silicon_revision == 1 ? 1 : 0;
1116 if (info->revision < 8) {
1117 some_delay_ns = 600;
1118 cas_latency_shift = 0;
1119 }
1120 {
1121 int speed_bit;
1122 speed_bit =
1123 ((info->clock_speed_index > 1
1124 || (info->silicon_revision != 2
1125 && info->silicon_revision != 3))) ^ (info->revision >=
1126 0x10);
1127 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1128 3, 1);
1129 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1130 3, 1);
1131 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1132 && (info->silicon_revision == 2
1133 || info->silicon_revision == 3))
Angel Pons244f4552021-01-15 20:41:36 +01001134 rmw_1d0(0x116, 5, 2, 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001135 }
Felix Held04be2dd2018-07-29 04:53:22 +02001136 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1137 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001138
Felix Held04be2dd2018-07-29 04:53:22 +02001139 MCHBAR8(0x124) = info->board_lane_delay[4] +
1140 ((frequency_01(info) + 999) / 1000);
1141 MCHBAR16(0x125) = 0x1360;
1142 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001143 if (info->fsb_frequency < frequency_11(info) / 2) {
Martin Roth468d02c2019-10-23 21:44:42 -06001144 unsigned int some_delay_2_half_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001145 high_multiplier = 1;
1146 some_delay_2_half_cycles = ps_to_halfcycles(info,
1147 ((3 *
1148 fsbcycle_ps(info))
1149 >> 1) +
1150 (halfcycle_ps(info)
1151 *
1152 reg178_min[info->
1153 clock_speed_index]
1154 >> 6)
1155 +
1156 4 *
1157 halfcycle_ps(info)
1158 + 2230);
1159 some_delay_3_half_cycles =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001160 MIN((some_delay_2_half_cycles +
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001161 (frequency_11(info) * 2) * (28 -
1162 some_delay_2_half_cycles) /
1163 (frequency_11(info) * 2 -
1164 4 * (info->fsb_frequency))) >> 3, 7);
1165 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001166 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001167 some_delay_3_half_cycles = 3;
1168 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001169 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1170 MCHBAR32(0x224 + (channel << 10)) =
1171 (info->max_slots_used_in_channel - 1) |
1172 ((info->cas_latency - 5 - info->clock_speed_index)
1173 << 21) | ((info->max_slots_used_in_channel +
1174 info->cas_latency - cas_latency_shift - 4) << 16) |
1175 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1176 ((info->cas_latency - info->clock_speed_index +
1177 info->max_slots_used_in_channel - 6) << 8);
1178 MCHBAR32(0x228 + (channel << 10)) =
1179 info->max_slots_used_in_channel;
1180 MCHBAR8(0x239 + (channel << 10)) = 32;
1181 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1182 (some_delay_3_half_cycles << 25) | 0x840000;
1183 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1184 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1185 MCHBAR32(0x24c + (channel << 10)) =
1186 ((!!info->clock_speed_index) << 17) |
1187 (((2 + info->clock_speed_index -
1188 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001189
Felix Held04be2dd2018-07-29 04:53:22 +02001190 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1191 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1192 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001193
1194 write_500(info, channel,
1195 ((!info->populated_ranks[channel][1][1])
1196 | (!info->populated_ranks[channel][1][0] << 1)
1197 | (!info->populated_ranks[channel][0][1] << 2)
1198 | (!info->populated_ranks[channel][0][0] << 3)),
1199 0x4c9, 4, 1);
1200 }
1201
Felix Held22ca8cb2018-07-29 05:09:44 +02001202 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001203 {
1204 u8 freq_divisor = 2;
1205 if (info->fsb_frequency == frequency_11(info))
1206 freq_divisor = 3;
1207 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1208 freq_divisor = 1;
1209 else
1210 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001211 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001212 }
1213
1214 if (info->board_lane_delay[3] <= 10) {
1215 if (info->board_lane_delay[3] <= 8)
1216 lane_3_delay = info->board_lane_delay[3];
1217 else
1218 lane_3_delay = 10;
1219 } else {
1220 lane_3_delay = 12;
1221 }
1222 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1223 if (info->clock_speed_index > 1)
1224 cas_latency_derived++;
1225 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001226 MCHBAR32(0x240 + (channel << 10)) =
1227 ((info->clock_speed_index == 0) * 0x11000) |
1228 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1229 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001230 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1231 0x609, 6, 1);
1232 write_500(info, channel,
1233 info->clock_speed_index + 2 * info->cas_latency - 7,
1234 0x601, 6, 1);
1235
Felix Held04be2dd2018-07-29 04:53:22 +02001236 MCHBAR32(0x250 + (channel << 10)) =
1237 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1238 (info->board_lane_delay[7] << 2) |
1239 (info->board_lane_delay[4] << 16) |
1240 (info->board_lane_delay[1] << 25) |
1241 (info->board_lane_delay[1] << 29) | 1;
1242 MCHBAR32(0x254 + (channel << 10)) =
1243 (info->board_lane_delay[1] >> 3) |
1244 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1245 0x80 | (info->board_lane_delay[6] << 1) |
1246 (info->board_lane_delay[2] << 28) |
1247 (cas_latency_derived << 16) | 0x4700000;
1248 MCHBAR32(0x258 + (channel << 10)) =
1249 ((info->board_lane_delay[5] + info->clock_speed_index +
1250 9) << 12) | ((info->clock_speed_index -
1251 info->cas_latency + 12) << 8) |
1252 (info->board_lane_delay[2] << 17) |
1253 (info->board_lane_delay[4] << 24) | 0x47;
1254 MCHBAR32(0x25c + (channel << 10)) =
1255 (info->board_lane_delay[1] << 1) |
1256 (info->board_lane_delay[0] << 8) | 0x1da50000;
1257 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1258 MCHBAR8(0x5f8 + (channel << 10)) =
1259 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001260 }
1261
1262 program_modules_memory_map(info, 1);
1263
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001264 MCHBAR16(0x610) = (MIN(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
Felix Held04be2dd2018-07-29 04:53:22 +02001265 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1266 MCHBAR16_OR(0x612, 0x100);
1267 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001268 for (i = 0; i < 8; i++) {
Angel Pons67573372020-07-22 16:56:00 +02001269 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001270 (info->total_memory_mb - 64) | !i | 2);
Angel Pons67573372020-07-22 16:56:00 +02001271 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001272 }
1273}
1274
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001275#define DEFAULT_PCI_MMIO_SIZE 2048
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001276
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001277static void program_total_memory_map(struct raminfo *info)
1278{
Angel Pons9333b742020-07-22 16:04:15 +02001279 unsigned int tom, tolud, touud;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001280 unsigned int quickpath_reserved;
Angel Pons9333b742020-07-22 16:04:15 +02001281 unsigned int remap_base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001282 unsigned int uma_base_igd;
1283 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001284 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001285 int memory_remap;
1286 unsigned int memory_map[8];
1287 int i;
1288 unsigned int current_limit;
1289 unsigned int tseg_base;
1290 int uma_size_igd = 0, uma_size_gtt = 0;
1291
1292 memset(memory_map, 0, sizeof(memory_map));
1293
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001294 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001295 u16 t = pci_read_config16(NORTHBRIDGE, GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001296 gav(t);
1297 const int uma_sizes_gtt[16] =
1298 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1299 /* Igd memory */
1300 const int uma_sizes_igd[16] = {
1301 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1302 256, 512
1303 };
1304
1305 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1306 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1307 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001308
Angel Ponse24f97c2021-04-02 22:42:53 +02001309 mmio_size = DEFAULT_PCI_MMIO_SIZE;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001310
Angel Pons9333b742020-07-22 16:04:15 +02001311 tom = info->total_memory_mb;
1312 if (tom == 4096)
1313 tom = 4032;
1314 touud = ALIGN_DOWN(tom - info->memory_reserved_for_heci_mb, 64);
1315 tolud = ALIGN_DOWN(MIN(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
1316 , touud), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001317 memory_remap = 0;
Angel Pons9333b742020-07-22 16:04:15 +02001318 if (touud - tolud > 64) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001319 memory_remap = 1;
Angel Pons9333b742020-07-22 16:04:15 +02001320 remap_base = MAX(4096, touud);
1321 touud = touud - tolud + 4096;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001322 }
Angel Pons9333b742020-07-22 16:04:15 +02001323 if (touud > 4096)
1324 memory_map[2] = touud | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001325 quickpath_reserved = 0;
1326
Angel Pons3ab19b32020-07-22 16:29:54 +02001327 u32 t = pci_read_config32(QPI_SAD, 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001328
Jacob Garber975a7e32019-06-10 16:32:47 -06001329 gav(t);
1330
1331 if (t & 0x800) {
1332 u32 shift = t >> 20;
1333 if (shift == 0)
1334 die("Quickpath value is 0\n");
1335 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001336 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001337
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001338 if (memory_remap)
Angel Pons9333b742020-07-22 16:04:15 +02001339 touud -= quickpath_reserved;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001340
Angel Pons9333b742020-07-22 16:04:15 +02001341 uma_base_igd = tolud - uma_size_igd;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001342 uma_base_gtt = uma_base_igd - uma_size_gtt;
1343 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1344 if (!memory_remap)
1345 tseg_base -= quickpath_reserved;
1346 tseg_base = ALIGN_DOWN(tseg_base, 8);
1347
Angel Pons16fe1e02020-07-22 16:12:33 +02001348 pci_write_config16(NORTHBRIDGE, TOLUD, tolud << 4);
1349 pci_write_config16(NORTHBRIDGE, TOM, tom >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001350 if (memory_remap) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001351 pci_write_config16(NORTHBRIDGE, REMAPBASE, remap_base >> 6);
1352 pci_write_config16(NORTHBRIDGE, REMAPLIMIT, (touud - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001353 }
Angel Pons16fe1e02020-07-22 16:12:33 +02001354 pci_write_config16(NORTHBRIDGE, TOUUD, touud);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001355
1356 if (info->uma_enabled) {
Angel Pons16fe1e02020-07-22 16:12:33 +02001357 pci_write_config32(NORTHBRIDGE, IGD_BASE, uma_base_igd << 20);
1358 pci_write_config32(NORTHBRIDGE, GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001359 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001360 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001361
1362 current_limit = 0;
1363 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1364 memory_map[1] = 4096;
1365 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001366 current_limit = MAX(current_limit, memory_map[i] & ~1);
Angel Pons67573372020-07-22 16:56:00 +02001367 pci_write_config32(QPI_SAD, SAD_DRAM_RULE(i),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001368 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1369 1, 64) | 2);
Angel Pons67573372020-07-22 16:56:00 +02001370 pci_write_config32(QPI_SAD, SAD_INTERLEAVE_LIST(i), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001371 }
1372}
1373
1374static void collect_system_info(struct raminfo *info)
1375{
1376 u32 capid0[3];
1377 int i;
Martin Roth468d02c2019-10-23 21:44:42 -06001378 unsigned int channel;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001379
Angel Ponsb600d412021-01-16 16:33:48 +01001380 for (i = 0; i < 3; i++) {
1381 capid0[i] = pci_read_config32(NORTHBRIDGE, CAPID0 | (i << 2));
1382 printk(BIOS_DEBUG, "CAPID0[%d] = 0x%08x\n", i, capid0[i]);
1383 }
1384 info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID);
1385 printk(BIOS_DEBUG, "Revision ID: 0x%x\n", info->revision);
1386 printk(BIOS_DEBUG, "Device ID: 0x%x\n", pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID));
1387
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001388 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1389
1390 if ((capid0[1] >> 11) & 1)
1391 info->uma_enabled = 0;
1392 else
1393 gav(info->uma_enabled =
Angel Pons16fe1e02020-07-22 16:12:33 +02001394 pci_read_config8(NORTHBRIDGE, DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001395 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1396 info->silicon_revision = 0;
1397
1398 if (capid0[2] & 2) {
1399 info->silicon_revision = 0;
1400 info->max_supported_clock_speed_index = 2;
1401 for (channel = 0; channel < NUM_CHANNELS; channel++)
1402 if (info->populated_ranks[channel][0][0]
1403 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1404 3) {
1405 info->silicon_revision = 2;
1406 info->max_supported_clock_speed_index = 1;
1407 }
1408 } else {
1409 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1410 case 1:
1411 case 2:
1412 info->silicon_revision = 3;
1413 break;
1414 case 3:
1415 info->silicon_revision = 0;
1416 break;
1417 case 0:
1418 info->silicon_revision = 2;
1419 break;
1420 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001421 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001422 case 0x40:
1423 info->silicon_revision = 0;
1424 break;
1425 case 0x48:
1426 info->silicon_revision = 1;
1427 break;
1428 }
1429 }
1430}
1431
1432static void write_training_data(struct raminfo *info)
1433{
1434 int tm, channel, slot, rank, lane;
1435 if (info->revision < 8)
1436 return;
1437
1438 for (tm = 0; tm < 4; tm++)
1439 for (channel = 0; channel < NUM_CHANNELS; channel++)
1440 for (slot = 0; slot < NUM_SLOTS; slot++)
1441 for (rank = 0; rank < NUM_RANKS; rank++)
1442 for (lane = 0; lane < 9; lane++)
1443 write_500(info, channel,
1444 info->
1445 cached_training->
1446 lane_timings[tm]
1447 [channel][slot][rank]
1448 [lane],
1449 get_timing_register_addr
1450 (lane, tm, slot,
1451 rank), 9, 0);
1452 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1453 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1454}
1455
1456static void dump_timings(struct raminfo *info)
1457{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001458 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001459 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001460 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001461 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001462 slot, rank);
1463 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001464 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001465 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001466 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001467 read_500(info, channel,
1468 get_timing_register_addr
1469 (lane, i, slot, rank),
1470 9),
1471 info->training.
1472 lane_timings[i][channel][slot][rank]
1473 [lane]);
1474 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001475 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001476 }
1477 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001478 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001479 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001480 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001481 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001482}
1483
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001484/* Read timings and other registers that need to be restored verbatim and
1485 put them to CBMEM.
1486 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001487static void save_timings(struct raminfo *info)
1488{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001489 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001490 int channel, slot, rank, lane, i;
1491
1492 train = info->training;
1493 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1494 for (i = 0; i < 4; i++)
1495 train.lane_timings[i][channel][slot][rank][lane] =
1496 read_500(info, channel,
1497 get_timing_register_addr(lane, i, slot,
1498 rank), 9);
1499 train.reg_178 = read_1d0(0x178, 7);
1500 train.reg_10b = read_1d0(0x10b, 6);
1501
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001502 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1503 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001504 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001505 train.reg274265[channel][0] = reg32 >> 16;
1506 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001507 train.reg274265[channel][2] =
1508 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001509 }
Felix Held04be2dd2018-07-29 04:53:22 +02001510 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1511 train.reg_6dc = MCHBAR32(0x6dc);
1512 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001513
Arthur Heymansb3282092019-04-14 17:53:28 +02001514 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1515 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001516
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001517 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001518 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1519 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001520}
1521
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001522static const struct ram_training *get_cached_training(void)
1523{
Shelley Chenad9cd682020-07-23 16:10:52 -07001524 return mrc_cache_current_mmap_leak(MRC_TRAINING_DATA,
1525 MRC_CACHE_VERSION,
1526 NULL);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001527}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001528
1529/* FIXME: add timeout. */
1530static void wait_heci_ready(void)
1531{
Felix Held04be2dd2018-07-29 04:53:22 +02001532 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1533 ;
Angel Ponseb537932020-09-14 19:18:11 +02001534
1535 write32((DEFAULT_HECIBAR + 0x4), (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001536}
1537
1538/* FIXME: add timeout. */
1539static void wait_heci_cb_avail(int len)
1540{
1541 union {
1542 struct mei_csr csr;
1543 u32 raw;
1544 } csr;
1545
Felix Held22ca8cb2018-07-29 05:09:44 +02001546 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1547 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001548
Angel Ponseb537932020-09-14 19:18:11 +02001549 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001550 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Angel Ponseb537932020-09-14 19:18:11 +02001551 } while (len > csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
1552 csr.csr.buffer_read_ptr));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001553}
1554
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001555static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001556{
1557 int len = (head->length + 3) / 4;
1558 int i;
1559
1560 wait_heci_cb_avail(len + 1);
1561
1562 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001563 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001564 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001565 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001566
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001567 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1568 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001569}
1570
Angel Ponseb537932020-09-14 19:18:11 +02001571static void send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001572{
1573 struct mei_header head;
1574 int maxlen;
1575
1576 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001577 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001578
1579 while (len) {
1580 int cur = len;
1581 if (cur > maxlen) {
1582 cur = maxlen;
1583 head.is_complete = 0;
1584 } else
1585 head.is_complete = 1;
1586 head.length = cur;
1587 head.reserved = 0;
1588 head.client_address = clientaddress;
1589 head.host_address = hostaddress;
1590 send_heci_packet(&head, (u32 *) msg);
1591 len -= cur;
1592 msg += cur;
1593 }
1594}
1595
1596/* FIXME: Add timeout. */
Angel Ponseb537932020-09-14 19:18:11 +02001597static int recv_heci_packet(struct mei_header *head, u32 *packet, u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001598{
1599 union {
1600 struct mei_csr csr;
1601 u32 raw;
1602 } csr;
1603 int i = 0;
1604
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001605 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001606 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001607 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Angel Ponseb537932020-09-14 19:18:11 +02001608 } while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr);
1609
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001610 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001611 if (!head->length) {
Angel Ponseb537932020-09-14 19:18:11 +02001612 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001613 *packet_size = 0;
1614 return 0;
1615 }
Angel Ponseb537932020-09-14 19:18:11 +02001616 if (head->length + 4 > 4 * csr.csr.buffer_depth || head->length > *packet_size) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001617 *packet_size = 0;
1618 return -1;
1619 }
1620
Angel Ponseb537932020-09-14 19:18:11 +02001621 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001622 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Angel Ponseb537932020-09-14 19:18:11 +02001623 } while (((head->length + 3) >> 2) >
1624 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001625
1626 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001627 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001628 *packet_size = head->length;
1629 if (!csr.csr.ready)
1630 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001631 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001632 return 0;
1633}
1634
Angel Ponsb1821892020-09-14 19:29:53 +02001635union uma_reply {
1636 struct {
1637 u8 group_id;
1638 u8 command;
1639 u8 reserved;
1640 u8 result;
1641 u8 field2;
1642 u8 unk3[0x48 - 4 - 1];
1643 };
1644 u32 dwords[0x48 / sizeof(u32)];
1645} __packed;
1646
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001647/* FIXME: Add timeout. */
Angel Ponsb1821892020-09-14 19:29:53 +02001648static int recv_heci_message(union uma_reply *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001649{
1650 struct mei_header head;
1651 int current_position;
1652
1653 current_position = 0;
1654 while (1) {
1655 u32 current_size;
1656 current_size = *message_size - current_position;
1657 if (recv_heci_packet
Angel Ponsb1821892020-09-14 19:29:53 +02001658 (&head, &message->dwords[current_position / sizeof(u32)],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001659 &current_size) == -1)
1660 break;
1661 if (!current_size)
1662 break;
1663 current_position += current_size;
1664 if (head.is_complete) {
1665 *message_size = current_position;
1666 return 0;
1667 }
1668
1669 if (current_position >= *message_size)
1670 break;
1671 }
1672 *message_size = 0;
1673 return -1;
1674}
1675
Angel Pons55f11e22020-09-14 19:06:53 +02001676static void send_heci_uma_message(const u64 heci_uma_addr, const unsigned int heci_uma_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001677{
Angel Ponsb1821892020-09-14 19:29:53 +02001678 union uma_reply reply;
Elyes HAOUASe1d1fe42020-06-17 14:04:45 +02001679
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001680 struct uma_message {
1681 u8 group_id;
1682 u8 cmd;
1683 u8 reserved;
1684 u8 result;
1685 u32 c2;
1686 u64 heci_uma_addr;
Angel Ponseb537932020-09-14 19:18:11 +02001687 u32 heci_uma_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001688 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001689 } __packed msg = {
Angel Ponseb537932020-09-14 19:18:11 +02001690 .group_id = 0,
1691 .cmd = MKHI_SET_UMA,
1692 .reserved = 0,
1693 .result = 0,
1694 .c2 = 0x82,
1695 .heci_uma_addr = heci_uma_addr,
1696 .heci_uma_size = heci_uma_size,
1697 .c3 = 0,
1698 };
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001699 u32 reply_size;
1700
Angel Ponseb537932020-09-14 19:18:11 +02001701 send_heci_message((u8 *) &msg, sizeof(msg), 0, 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001702
1703 reply_size = sizeof(reply);
Angel Ponsb1821892020-09-14 19:29:53 +02001704 if (recv_heci_message(&reply, &reply_size) == -1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001705 return;
1706
1707 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1708 die("HECI init failed\n");
1709}
1710
1711static void setup_heci_uma(struct raminfo *info)
1712{
Angel Pons44479962021-02-24 23:08:27 +01001713 if (!info->memory_reserved_for_heci_mb || !(pci_read_config32(HECIDEV, 0x40) & 0x20))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001714 return;
1715
Angel Pons36592bf2020-09-14 18:52:44 +02001716 const u64 heci_uma_addr =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001717 ((u64)
Angel Ponseb537932020-09-14 19:18:11 +02001718 ((((u64)pci_read_config16(NORTHBRIDGE, TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001719 info->memory_reserved_for_heci_mb)) << 20;
1720
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001721 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001722 if (info->memory_reserved_for_heci_mb) {
Angel Pons3b264d02020-09-15 00:25:49 +02001723 DMIBAR32(DMIVC0RCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001724 RCBA32(0x14) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001725 DMIBAR32(DMIVC1RCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001726 RCBA32(0x20) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001727 DMIBAR32(DMIVCPRCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001728 RCBA32(0x30) &= ~0x80;
Angel Pons3b264d02020-09-15 00:25:49 +02001729 DMIBAR32(DMIVCMRCTL) &= ~0x80;
Angel Ponsee7fb342021-01-28 14:11:55 +01001730 RCBA32(0x40) &= ~0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001731
Angel Ponsee7fb342021-01-28 14:11:55 +01001732 RCBA32(0x40) = 0x87000080; // OK
Angel Pons3b264d02020-09-15 00:25:49 +02001733 DMIBAR32(DMIVCMRCTL) = 0x87000080; // OK
Angel Ponseb537932020-09-14 19:18:11 +02001734
Angel Ponsee7fb342021-01-28 14:11:55 +01001735 while ((RCBA16(0x46) & 2) && DMIBAR16(DMIVCMRSTS) & VCMNP)
Felix Held04be2dd2018-07-29 04:53:22 +02001736 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001737 }
1738
Felix Held04be2dd2018-07-29 04:53:22 +02001739 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001740
Angel Pons55f11e22020-09-14 19:06:53 +02001741 send_heci_uma_message(heci_uma_addr, info->memory_reserved_for_heci_mb);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001742
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001743 pci_write_config32(HECIDEV, 0x10, 0x0);
1744 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001745}
1746
1747static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1748{
1749 int ranks_in_channel;
1750 ranks_in_channel = info->populated_ranks[channel][0][0]
1751 + info->populated_ranks[channel][0][1]
1752 + info->populated_ranks[channel][1][0]
1753 + info->populated_ranks[channel][1][1];
1754
1755 /* empty channel */
1756 if (ranks_in_channel == 0)
1757 return 1;
1758
1759 if (ranks_in_channel != ranks)
1760 return 0;
1761 /* single slot */
1762 if (info->populated_ranks[channel][0][0] !=
1763 info->populated_ranks[channel][1][0])
1764 return 1;
1765 if (info->populated_ranks[channel][0][1] !=
1766 info->populated_ranks[channel][1][1])
1767 return 1;
1768 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1769 return 0;
1770 if (info->density[channel][0] != info->density[channel][1])
1771 return 0;
1772 return 1;
1773}
1774
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001775static void read_4090(struct raminfo *info)
1776{
1777 int i, channel, slot, rank, lane;
1778 for (i = 0; i < 2; i++)
1779 for (slot = 0; slot < NUM_SLOTS; slot++)
1780 for (rank = 0; rank < NUM_RANKS; rank++)
1781 for (lane = 0; lane < 9; lane++)
1782 info->training.
1783 lane_timings[0][i][slot][rank][lane]
1784 = 32;
1785
1786 for (i = 1; i < 4; i++)
1787 for (channel = 0; channel < NUM_CHANNELS; channel++)
1788 for (slot = 0; slot < NUM_SLOTS; slot++)
1789 for (rank = 0; rank < NUM_RANKS; rank++)
1790 for (lane = 0; lane < 9; lane++) {
1791 info->training.
1792 lane_timings[i][channel]
1793 [slot][rank][lane] =
1794 read_500(info, channel,
1795 get_timing_register_addr
1796 (lane, i, slot,
1797 rank), 9)
1798 + (i == 1) * 11; // !!!!
1799 }
1800
1801}
1802
1803static u32 get_etalon2(int flip, u32 addr)
1804{
1805 const u16 invmask[] = {
1806 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1807 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1808 };
1809 u32 ret;
1810 u32 comp4 = addr / 480;
1811 addr %= 480;
1812 u32 comp1 = addr & 0xf;
1813 u32 comp2 = (addr >> 4) & 1;
1814 u32 comp3 = addr >> 5;
1815
1816 if (comp4)
1817 ret = 0x1010101 << (comp4 - 1);
1818 else
1819 ret = 0;
1820 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1821 ret = ~ret;
1822
1823 return ret;
1824}
1825
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001826static void disable_cache_region(void)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001827{
1828 msr_t msr = {.lo = 0, .hi = 0 };
1829
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001830 wrmsr(MTRR_PHYS_BASE(3), msr);
1831 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001832}
1833
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001834static void enable_cache_region(unsigned int base, unsigned int size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001835{
1836 msr_t msr;
1837 msr.lo = base | MTRR_TYPE_WRPROT;
1838 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001839 wrmsr(MTRR_PHYS_BASE(3), msr);
1840 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001841 & 0xffffffff);
1842 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001843 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001844}
1845
1846static void flush_cache(u32 start, u32 size)
1847{
1848 u32 end;
1849 u32 addr;
1850
1851 end = start + (ALIGN_DOWN(size + 4096, 4096));
1852 for (addr = start; addr < end; addr += 64)
Patrick Rudolph819c2062019-11-29 19:27:37 +01001853 clflush((void *)(uintptr_t)addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001854}
1855
1856static void clear_errors(void)
1857{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001858 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001859}
1860
1861static void write_testing(struct raminfo *info, int totalrank, int flip)
1862{
1863 int nwrites = 0;
1864 /* in 8-byte units. */
1865 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001866 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001867
Patrick Rudolph819c2062019-11-29 19:27:37 +01001868 base = (u8 *)(uintptr_t)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001869 for (offset = 0; offset < 9 * 480; offset += 2) {
1870 write32(base + offset * 8, get_etalon2(flip, offset));
1871 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1872 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
1873 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
1874 nwrites += 4;
1875 if (nwrites >= 320) {
1876 clear_errors();
1877 nwrites = 0;
1878 }
1879 }
1880}
1881
1882static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
1883{
1884 u8 failmask = 0;
1885 int i;
1886 int comp1, comp2, comp3;
1887 u32 failxor[2] = { 0, 0 };
1888
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001889 enable_cache_region((total_rank << 28), 1728 * 5 * 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001890
1891 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
1892 for (comp1 = 0; comp1 < 4; comp1++)
1893 for (comp2 = 0; comp2 < 60; comp2++) {
1894 u32 re[4];
1895 u32 curroffset =
1896 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
1897 read128((total_rank << 28) | (curroffset << 3),
1898 (u64 *) re);
1899 failxor[0] |=
1900 get_etalon2(flip, curroffset) ^ re[0];
1901 failxor[1] |=
1902 get_etalon2(flip, curroffset) ^ re[1];
1903 failxor[0] |=
1904 get_etalon2(flip, curroffset | 1) ^ re[2];
1905 failxor[1] |=
1906 get_etalon2(flip, curroffset | 1) ^ re[3];
1907 }
1908 for (i = 0; i < 8; i++)
1909 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
1910 failmask |= 1 << i;
1911 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01001912 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001913 flush_cache((total_rank << 28), 1728 * 5 * 4);
1914 return failmask;
1915}
1916
1917const u32 seed1[0x18] = {
1918 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
1919 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
1920 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
1921 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
1922 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
1923 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
1924};
1925
1926static u32 get_seed2(int a, int b)
1927{
1928 const u32 seed2[5] = {
1929 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
1930 0x5b6db6db,
1931 };
1932 u32 r;
1933 r = seed2[(a + (a >= 10)) / 5];
1934 return b ? ~r : r;
1935}
1936
1937static int make_shift(int comp2, int comp5, int x)
1938{
1939 const u8 seed3[32] = {
1940 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1941 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
1942 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
1943 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
1944 };
1945
1946 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
1947}
1948
1949static u32 get_etalon(int flip, u32 addr)
1950{
1951 u32 mask_byte = 0;
1952 int comp1 = (addr >> 1) & 1;
1953 int comp2 = (addr >> 3) & 0x1f;
1954 int comp3 = (addr >> 8) & 0xf;
1955 int comp4 = (addr >> 12) & 0xf;
1956 int comp5 = (addr >> 16) & 0x1f;
1957 u32 mask_bit = ~(0x10001 << comp3);
1958 u32 part1;
1959 u32 part2;
1960 int byte;
1961
1962 part2 =
1963 ((seed1[comp5] >>
1964 make_shift(comp2, comp5,
1965 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
1966 part1 =
1967 ((seed1[comp5] >>
1968 make_shift(comp2, comp5,
1969 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
1970
1971 for (byte = 0; byte < 4; byte++)
1972 if ((get_seed2(comp5, comp4) >>
1973 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
1974 mask_byte |= 0xff << (8 * byte);
1975
1976 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
1977 (comp3 + 16));
1978}
1979
1980static void
1981write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
1982 char flip)
1983{
1984 int i;
1985 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001986 write32p((totalrank << 28) | (region << 25) | (block << 16) |
1987 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001988}
1989
1990static u8
1991check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
1992 char flip)
1993{
1994 u8 failmask = 0;
1995 u32 failxor[2];
1996 int i;
1997 int comp1, comp2, comp3;
1998
1999 failxor[0] = 0;
2000 failxor[1] = 0;
2001
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002002 enable_cache_region(totalrank << 28, 134217728);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002003 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2004 for (comp1 = 0; comp1 < 16; comp1++)
2005 for (comp2 = 0; comp2 < 64; comp2++) {
2006 u32 addr =
2007 (totalrank << 28) | (region << 25) | (block
2008 << 16)
2009 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2010 2);
2011 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002012 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002013 }
2014 for (i = 0; i < 8; i++)
2015 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2016 failmask |= 1 << i;
2017 }
Arthur Heymanse7dd3802019-11-25 12:09:33 +01002018 disable_cache_region();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002019 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2020 return failmask;
2021}
2022
2023static int check_bounded(unsigned short *vals, u16 bound)
2024{
2025 int i;
2026
2027 for (i = 0; i < 8; i++)
2028 if (vals[i] < bound)
2029 return 0;
2030 return 1;
2031}
2032
2033enum state {
2034 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2035};
2036
2037static int validate_state(enum state *in)
2038{
2039 int i;
2040 for (i = 0; i < 8; i++)
2041 if (in[i] != COMPLETE)
2042 return 0;
2043 return 1;
2044}
2045
2046static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002047do_fsm(enum state *state, u16 *counter,
2048 u8 fail_mask, int margin, int uplimit,
2049 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002050{
2051 int lane;
2052
2053 for (lane = 0; lane < 8; lane++) {
2054 int is_fail = (fail_mask >> lane) & 1;
2055 switch (state[lane]) {
2056 case BEFORE_USABLE:
2057 if (!is_fail) {
2058 counter[lane] = 1;
2059 state[lane] = AT_USABLE;
2060 break;
2061 }
2062 counter[lane] = 0;
2063 state[lane] = BEFORE_USABLE;
2064 break;
2065 case AT_USABLE:
2066 if (!is_fail) {
2067 ++counter[lane];
2068 if (counter[lane] >= margin) {
2069 state[lane] = AT_MARGIN;
2070 res_low[lane] = val - margin + 1;
2071 break;
2072 }
2073 state[lane] = 1;
2074 break;
2075 }
2076 counter[lane] = 0;
2077 state[lane] = BEFORE_USABLE;
2078 break;
2079 case AT_MARGIN:
2080 if (is_fail) {
2081 state[lane] = COMPLETE;
2082 res_high[lane] = val - 1;
2083 } else {
2084 counter[lane]++;
2085 state[lane] = AT_MARGIN;
2086 if (val == uplimit) {
2087 state[lane] = COMPLETE;
2088 res_high[lane] = uplimit;
2089 }
2090 }
2091 break;
2092 case COMPLETE:
2093 break;
2094 }
2095 }
2096}
2097
2098static void
2099train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2100 u8 total_rank, u8 reg_178, int first_run, int niter,
2101 timing_bounds_t * timings)
2102{
2103 int lane;
2104 enum state state[8];
2105 u16 count[8];
2106 u8 lower_usable[8];
2107 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002108 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002109 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002110 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002111
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002112 for (i = 0; i < 8; i++)
2113 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002114
2115 if (!first_run) {
2116 int is_all_ok = 1;
2117 for (lane = 0; lane < 8; lane++)
2118 if (timings[reg_178][channel][slot][rank][lane].
2119 smallest ==
2120 timings[reg_178][channel][slot][rank][lane].
2121 largest) {
2122 timings[reg_178][channel][slot][rank][lane].
2123 smallest = 0;
2124 timings[reg_178][channel][slot][rank][lane].
2125 largest = 0;
2126 is_all_ok = 0;
2127 }
2128 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002129 for (i = 0; i < 8; i++)
2130 state[i] = COMPLETE;
2131 }
2132 }
2133
2134 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2135 u8 failmask = 0;
2136 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2137 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2138 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002139 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002140 do_fsm(state, count, failmask, 5, 47, lower_usable,
2141 upper_usable, reg1b3);
2142 }
2143
2144 if (reg1b3) {
2145 write_1d0(0, 0x1b3, 6, 1);
2146 write_1d0(0, 0x1a3, 6, 1);
2147 for (lane = 0; lane < 8; lane++) {
2148 if (state[lane] == COMPLETE) {
2149 timings[reg_178][channel][slot][rank][lane].
2150 smallest =
2151 lower_usable[lane] +
2152 (info->training.
2153 lane_timings[0][channel][slot][rank][lane]
2154 & 0x3F) - 32;
2155 timings[reg_178][channel][slot][rank][lane].
2156 largest =
2157 upper_usable[lane] +
2158 (info->training.
2159 lane_timings[0][channel][slot][rank][lane]
2160 & 0x3F) - 32;
2161 }
2162 }
2163 }
2164
2165 if (!first_run) {
2166 for (lane = 0; lane < 8; lane++)
2167 if (state[lane] == COMPLETE) {
2168 write_500(info, channel,
2169 timings[reg_178][channel][slot][rank]
2170 [lane].smallest,
2171 get_timing_register_addr(lane, 0,
2172 slot, rank),
2173 9, 1);
2174 write_500(info, channel,
2175 timings[reg_178][channel][slot][rank]
2176 [lane].smallest +
2177 info->training.
2178 lane_timings[1][channel][slot][rank]
2179 [lane]
2180 -
2181 info->training.
2182 lane_timings[0][channel][slot][rank]
2183 [lane], get_timing_register_addr(lane,
2184 1,
2185 slot,
2186 rank),
2187 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002188 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002189 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002190 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002191
2192 do {
2193 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002194 for (i = 0; i < niter; i++) {
2195 if (failmask == 0xFF)
2196 break;
2197 failmask |=
2198 check_testing_type2(info, total_rank, 2, i,
2199 0);
2200 failmask |=
2201 check_testing_type2(info, total_rank, 3, i,
2202 1);
2203 }
Felix Held04be2dd2018-07-29 04:53:22 +02002204 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002205 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002206 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002207 if ((1 << lane) & failmask) {
2208 if (timings[reg_178][channel]
2209 [slot][rank][lane].
2210 largest <=
2211 timings[reg_178][channel]
2212 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002213 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002214 [lane] = -1;
2215 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002216 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002217 [lane] = 0;
2218 timings[reg_178]
2219 [channel][slot]
2220 [rank][lane].
2221 smallest++;
2222 write_500(info, channel,
2223 timings
2224 [reg_178]
2225 [channel]
2226 [slot][rank]
2227 [lane].
2228 smallest,
2229 get_timing_register_addr
2230 (lane, 0,
2231 slot, rank),
2232 9, 1);
2233 write_500(info, channel,
2234 timings
2235 [reg_178]
2236 [channel]
2237 [slot][rank]
2238 [lane].
2239 smallest +
2240 info->
2241 training.
2242 lane_timings
2243 [1][channel]
2244 [slot][rank]
2245 [lane]
2246 -
2247 info->
2248 training.
2249 lane_timings
2250 [0][channel]
2251 [slot][rank]
2252 [lane],
2253 get_timing_register_addr
2254 (lane, 1,
2255 slot, rank),
2256 9, 1);
2257 }
2258 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002259 num_successfully_checked[lane]
2260 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002261 }
2262 }
Felix Held04be2dd2018-07-29 04:53:22 +02002263 while (!check_bounded(num_successfully_checked, 2))
2264 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002265
2266 for (lane = 0; lane < 8; lane++)
2267 if (state[lane] == COMPLETE) {
2268 write_500(info, channel,
2269 timings[reg_178][channel][slot][rank]
2270 [lane].largest,
2271 get_timing_register_addr(lane, 0,
2272 slot, rank),
2273 9, 1);
2274 write_500(info, channel,
2275 timings[reg_178][channel][slot][rank]
2276 [lane].largest +
2277 info->training.
2278 lane_timings[1][channel][slot][rank]
2279 [lane]
2280 -
2281 info->training.
2282 lane_timings[0][channel][slot][rank]
2283 [lane], get_timing_register_addr(lane,
2284 1,
2285 slot,
2286 rank),
2287 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002288 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002289 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002290 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002291
2292 do {
2293 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002294 for (i = 0; i < niter; i++) {
2295 if (failmask == 0xFF)
2296 break;
2297 failmask |=
2298 check_testing_type2(info, total_rank, 2, i,
2299 0);
2300 failmask |=
2301 check_testing_type2(info, total_rank, 3, i,
2302 1);
2303 }
2304
Felix Held04be2dd2018-07-29 04:53:22 +02002305 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002306 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002307 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002308 if ((1 << lane) & failmask) {
2309 if (timings[reg_178][channel]
2310 [slot][rank][lane].
2311 largest <=
2312 timings[reg_178][channel]
2313 [slot][rank][lane].
2314 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002315 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002316 [lane] = -1;
2317 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002318 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002319 [lane] = 0;
2320 timings[reg_178]
2321 [channel][slot]
2322 [rank][lane].
2323 largest--;
2324 write_500(info, channel,
2325 timings
2326 [reg_178]
2327 [channel]
2328 [slot][rank]
2329 [lane].
2330 largest,
2331 get_timing_register_addr
2332 (lane, 0,
2333 slot, rank),
2334 9, 1);
2335 write_500(info, channel,
2336 timings
2337 [reg_178]
2338 [channel]
2339 [slot][rank]
2340 [lane].
2341 largest +
2342 info->
2343 training.
2344 lane_timings
2345 [1][channel]
2346 [slot][rank]
2347 [lane]
2348 -
2349 info->
2350 training.
2351 lane_timings
2352 [0][channel]
2353 [slot][rank]
2354 [lane],
2355 get_timing_register_addr
2356 (lane, 1,
2357 slot, rank),
2358 9, 1);
2359 }
2360 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002361 num_successfully_checked[lane]
2362 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002363 }
2364 }
2365 }
Felix Held04be2dd2018-07-29 04:53:22 +02002366 while (!check_bounded(num_successfully_checked, 3))
2367 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002368
2369 for (lane = 0; lane < 8; lane++) {
2370 write_500(info, channel,
2371 info->training.
2372 lane_timings[0][channel][slot][rank][lane],
2373 get_timing_register_addr(lane, 0, slot, rank),
2374 9, 1);
2375 write_500(info, channel,
2376 info->training.
2377 lane_timings[1][channel][slot][rank][lane],
2378 get_timing_register_addr(lane, 1, slot, rank),
2379 9, 1);
2380 if (timings[reg_178][channel][slot][rank][lane].
2381 largest <=
2382 timings[reg_178][channel][slot][rank][lane].
2383 smallest) {
2384 timings[reg_178][channel][slot][rank][lane].
2385 largest = 0;
2386 timings[reg_178][channel][slot][rank][lane].
2387 smallest = 0;
2388 }
2389 }
2390 }
2391}
2392
2393static void set_10b(struct raminfo *info, u8 val)
2394{
2395 int channel;
2396 int slot, rank;
2397 int lane;
2398
2399 if (read_1d0(0x10b, 6) == val)
2400 return;
2401
2402 write_1d0(val, 0x10b, 6, 1);
2403
2404 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2405 u16 reg_500;
2406 reg_500 = read_500(info, channel,
2407 get_timing_register_addr(lane, 0, slot,
2408 rank), 9);
2409 if (val == 1) {
2410 if (lut16[info->clock_speed_index] <= reg_500)
2411 reg_500 -= lut16[info->clock_speed_index];
2412 else
2413 reg_500 = 0;
2414 } else {
2415 reg_500 += lut16[info->clock_speed_index];
2416 }
2417 write_500(info, channel, reg_500,
2418 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2419 }
2420}
2421
2422static void set_ecc(int onoff)
2423{
2424 int channel;
2425 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2426 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002427 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002428 if (onoff)
2429 t |= 1;
2430 else
2431 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002432 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002433 }
2434}
2435
2436static void set_178(u8 val)
2437{
2438 if (val >= 31)
2439 val = val - 31;
2440 else
2441 val = 63 - val;
2442
2443 write_1d0(2 * val, 0x178, 7, 1);
2444}
2445
2446static void
2447write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2448 int type)
2449{
2450 int lane;
2451
2452 for (lane = 0; lane < 8; lane++)
2453 write_500(info, channel,
2454 info->training.
2455 lane_timings[type][channel][slot][rank][lane],
2456 get_timing_register_addr(lane, type, slot, rank), 9,
2457 0);
2458}
2459
2460static void
2461try_timing_offsets(struct raminfo *info, int channel,
2462 int slot, int rank, int totalrank)
2463{
2464 u16 count[8];
2465 enum state state[8];
2466 u8 lower_usable[8], upper_usable[8];
2467 int lane;
2468 int i;
2469 int flip = 1;
2470 int timing_offset;
2471
2472 for (i = 0; i < 8; i++)
2473 state[i] = BEFORE_USABLE;
2474
2475 memset(count, 0, sizeof(count));
2476
2477 for (lane = 0; lane < 8; lane++)
2478 write_500(info, channel,
2479 info->training.
2480 lane_timings[2][channel][slot][rank][lane] + 32,
2481 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2482
2483 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2484 timing_offset++) {
2485 u8 failmask;
2486 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2487 failmask = 0;
2488 for (i = 0; i < 2 && failmask != 0xff; i++) {
2489 flip = !flip;
2490 write_testing(info, totalrank, flip);
2491 failmask |= check_testing(info, totalrank, flip);
2492 }
2493 do_fsm(state, count, failmask, 10, 63, lower_usable,
2494 upper_usable, timing_offset);
2495 }
2496 write_1d0(0, 0x1bb, 6, 1);
2497 dump_timings(info);
2498 if (!validate_state(state))
2499 die("Couldn't discover DRAM timings (1)\n");
2500
2501 for (lane = 0; lane < 8; lane++) {
2502 u8 bias = 0;
2503
2504 if (info->silicon_revision) {
2505 int usable_length;
2506
2507 usable_length = upper_usable[lane] - lower_usable[lane];
2508 if (usable_length >= 20) {
2509 bias = usable_length / 2 - 10;
2510 if (bias >= 2)
2511 bias = 2;
2512 }
2513 }
2514 write_500(info, channel,
2515 info->training.
2516 lane_timings[2][channel][slot][rank][lane] +
2517 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2518 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2519 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2520 info->training.lane_timings[2][channel][slot][rank][lane] +
2521 lower_usable[lane];
2522 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2523 info->training.lane_timings[2][channel][slot][rank][lane] +
2524 upper_usable[lane];
2525 info->training.timing2_offset[channel][slot][rank][lane] =
2526 info->training.lane_timings[2][channel][slot][rank][lane];
2527 }
2528}
2529
2530static u8
2531choose_training(struct raminfo *info, int channel, int slot, int rank,
2532 int lane, timing_bounds_t * timings, u8 center_178)
2533{
2534 u16 central_weight;
2535 u16 side_weight;
2536 unsigned int sum = 0, count = 0;
2537 u8 span;
2538 u8 lower_margin, upper_margin;
2539 u8 reg_178;
2540 u8 result;
2541
2542 span = 12;
2543 central_weight = 20;
2544 side_weight = 20;
2545 if (info->silicon_revision == 1 && channel == 1) {
2546 central_weight = 5;
2547 side_weight = 20;
2548 if ((info->
2549 populated_ranks_mask[1] ^ (info->
2550 populated_ranks_mask[1] >> 2)) &
2551 1)
2552 span = 18;
2553 }
2554 if ((info->populated_ranks_mask[0] & 5) == 5) {
2555 central_weight = 20;
2556 side_weight = 20;
2557 }
2558 if (info->clock_speed_index >= 2
2559 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2560 if (info->silicon_revision == 1) {
2561 switch (channel) {
2562 case 0:
2563 if (lane == 1) {
2564 central_weight = 10;
2565 side_weight = 20;
2566 }
2567 break;
2568 case 1:
2569 if (lane == 6) {
2570 side_weight = 5;
2571 central_weight = 20;
2572 }
2573 break;
2574 }
2575 }
2576 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2577 side_weight = 5;
2578 central_weight = 20;
2579 }
2580 }
2581 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2582 reg_178 += span) {
2583 u8 smallest;
2584 u8 largest;
2585 largest = timings[reg_178][channel][slot][rank][lane].largest;
2586 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2587 if (largest - smallest + 1 >= 5) {
2588 unsigned int weight;
2589 if (reg_178 == center_178)
2590 weight = central_weight;
2591 else
2592 weight = side_weight;
2593 sum += weight * (largest + smallest);
2594 count += weight;
2595 }
2596 }
2597 dump_timings(info);
2598 if (count == 0)
2599 die("Couldn't discover DRAM timings (2)\n");
2600 result = sum / (2 * count);
2601 lower_margin =
2602 result - timings[center_178][channel][slot][rank][lane].smallest;
2603 upper_margin =
2604 timings[center_178][channel][slot][rank][lane].largest - result;
2605 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002606 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002607 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002608 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002609 return result;
2610}
2611
2612#define STANDARD_MIN_MARGIN 5
2613
2614static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2615{
2616 u16 margin[64];
2617 int lane, rank, slot, channel;
2618 u8 reg178;
2619 int count = 0, sum = 0;
2620
2621 for (reg178 = reg178_min[info->clock_speed_index];
2622 reg178 < reg178_max[info->clock_speed_index];
2623 reg178 += reg178_step[info->clock_speed_index]) {
2624 margin[reg178] = -1;
2625 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2626 int curmargin =
2627 timings[reg178][channel][slot][rank][lane].largest -
2628 timings[reg178][channel][slot][rank][lane].
2629 smallest + 1;
2630 if (curmargin < margin[reg178])
2631 margin[reg178] = curmargin;
2632 }
2633 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2634 u16 weight;
2635 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2636 sum += weight * reg178;
2637 count += weight;
2638 }
2639 }
2640 dump_timings(info);
2641 if (count == 0)
2642 die("Couldn't discover DRAM timings (3)\n");
2643
2644 u8 threshold;
2645
2646 for (threshold = 30; threshold >= 5; threshold--) {
2647 int usable_length = 0;
2648 int smallest_fount = 0;
2649 for (reg178 = reg178_min[info->clock_speed_index];
2650 reg178 < reg178_max[info->clock_speed_index];
2651 reg178 += reg178_step[info->clock_speed_index])
2652 if (margin[reg178] >= threshold) {
2653 usable_length +=
2654 reg178_step[info->clock_speed_index];
2655 info->training.reg178_largest =
2656 reg178 -
2657 2 * reg178_step[info->clock_speed_index];
2658
2659 if (!smallest_fount) {
2660 smallest_fount = 1;
2661 info->training.reg178_smallest =
2662 reg178 +
2663 reg178_step[info->
2664 clock_speed_index];
2665 }
2666 }
2667 if (usable_length >= 0x21)
2668 break;
2669 }
2670
2671 return sum / count;
2672}
2673
2674static int check_cached_sanity(struct raminfo *info)
2675{
2676 int lane;
2677 int slot, rank;
2678 int channel;
2679
2680 if (!info->cached_training)
2681 return 0;
2682
2683 for (channel = 0; channel < NUM_CHANNELS; channel++)
2684 for (slot = 0; slot < NUM_SLOTS; slot++)
2685 for (rank = 0; rank < NUM_RANKS; rank++)
2686 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2687 u16 cached_value, estimation_value;
2688 cached_value =
2689 info->cached_training->
2690 lane_timings[1][channel][slot][rank]
2691 [lane];
2692 if (cached_value >= 0x18
2693 && cached_value <= 0x1E7) {
2694 estimation_value =
2695 info->training.
2696 lane_timings[1][channel]
2697 [slot][rank][lane];
2698 if (estimation_value <
2699 cached_value - 24)
2700 return 0;
2701 if (estimation_value >
2702 cached_value + 24)
2703 return 0;
2704 }
2705 }
2706 return 1;
2707}
2708
2709static int try_cached_training(struct raminfo *info)
2710{
2711 u8 saved_243[2];
2712 u8 tm;
2713
2714 int channel, slot, rank, lane;
2715 int flip = 1;
2716 int i, j;
2717
2718 if (!check_cached_sanity(info))
2719 return 0;
2720
2721 info->training.reg178_center = info->cached_training->reg178_center;
2722 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2723 info->training.reg178_largest = info->cached_training->reg178_largest;
2724 memcpy(&info->training.timing_bounds,
2725 &info->cached_training->timing_bounds,
2726 sizeof(info->training.timing_bounds));
2727 memcpy(&info->training.timing_offset,
2728 &info->cached_training->timing_offset,
2729 sizeof(info->training.timing_offset));
2730
2731 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002732 saved_243[0] = MCHBAR8(0x243);
2733 saved_243[1] = MCHBAR8(0x643);
2734 MCHBAR8(0x243) = saved_243[0] | 2;
2735 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002736 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002737 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002738 if (read_1d0(0x10b, 6) & 1)
2739 set_10b(info, 0);
2740 for (tm = 0; tm < 2; tm++) {
2741 int totalrank;
2742
2743 set_178(tm ? info->cached_training->reg178_largest : info->
2744 cached_training->reg178_smallest);
2745
2746 totalrank = 0;
2747 /* Check timing ranges. With i == 0 we check smallest one and with
2748 i == 1 the largest bound. With j == 0 we check that on the bound
2749 it still works whereas with j == 1 we check that just outside of
2750 bound we fail.
2751 */
2752 FOR_POPULATED_RANKS_BACKWARDS {
2753 for (i = 0; i < 2; i++) {
2754 for (lane = 0; lane < 8; lane++) {
2755 write_500(info, channel,
2756 info->cached_training->
2757 timing2_bounds[channel][slot]
2758 [rank][lane][i],
2759 get_timing_register_addr(lane,
2760 3,
2761 slot,
2762 rank),
2763 9, 1);
2764
2765 if (!i)
2766 write_500(info, channel,
2767 info->
2768 cached_training->
2769 timing2_offset
2770 [channel][slot][rank]
2771 [lane],
2772 get_timing_register_addr
2773 (lane, 2, slot, rank),
2774 9, 1);
2775 write_500(info, channel,
2776 i ? info->cached_training->
2777 timing_bounds[tm][channel]
2778 [slot][rank][lane].
2779 largest : info->
2780 cached_training->
2781 timing_bounds[tm][channel]
2782 [slot][rank][lane].smallest,
2783 get_timing_register_addr(lane,
2784 0,
2785 slot,
2786 rank),
2787 9, 1);
2788 write_500(info, channel,
2789 info->cached_training->
2790 timing_offset[channel][slot]
2791 [rank][lane] +
2792 (i ? info->cached_training->
2793 timing_bounds[tm][channel]
2794 [slot][rank][lane].
2795 largest : info->
2796 cached_training->
2797 timing_bounds[tm][channel]
2798 [slot][rank][lane].
2799 smallest) - 64,
2800 get_timing_register_addr(lane,
2801 1,
2802 slot,
2803 rank),
2804 9, 1);
2805 }
2806 for (j = 0; j < 2; j++) {
2807 u8 failmask;
2808 u8 expected_failmask;
2809 char reg1b3;
2810
2811 reg1b3 = (j == 1) + 4;
2812 reg1b3 =
2813 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2814 write_1d0(reg1b3, 0x1bb, 6, 1);
2815 write_1d0(reg1b3, 0x1b3, 6, 1);
2816 write_1d0(reg1b3, 0x1a3, 6, 1);
2817
2818 flip = !flip;
2819 write_testing(info, totalrank, flip);
2820 failmask =
2821 check_testing(info, totalrank,
2822 flip);
2823 expected_failmask =
2824 j == 0 ? 0x00 : 0xff;
2825 if (failmask != expected_failmask)
2826 goto fail;
2827 }
2828 }
2829 totalrank++;
2830 }
2831 }
2832
2833 set_178(info->cached_training->reg178_center);
2834 if (info->use_ecc)
2835 set_ecc(1);
2836 write_training_data(info);
2837 write_1d0(0, 322, 3, 1);
2838 info->training = *info->cached_training;
2839
2840 write_1d0(0, 0x1bb, 6, 1);
2841 write_1d0(0, 0x1b3, 6, 1);
2842 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002843 MCHBAR8(0x243) = saved_243[0];
2844 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002845
2846 return 1;
2847
2848fail:
2849 FOR_POPULATED_RANKS {
2850 write_500_timings_type(info, channel, slot, rank, 1);
2851 write_500_timings_type(info, channel, slot, rank, 2);
2852 write_500_timings_type(info, channel, slot, rank, 3);
2853 }
2854
2855 write_1d0(0, 0x1bb, 6, 1);
2856 write_1d0(0, 0x1b3, 6, 1);
2857 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002858 MCHBAR8(0x243) = saved_243[0];
2859 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002860
2861 return 0;
2862}
2863
2864static void do_ram_training(struct raminfo *info)
2865{
2866 u8 saved_243[2];
2867 int totalrank = 0;
2868 u8 reg_178;
2869 int niter;
2870
Matthias Gazzaridfa51252018-05-19 00:44:20 +02002871 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002872 int lane, rank, slot, channel;
2873 u8 reg178_center;
2874
2875 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002876 saved_243[0] = MCHBAR8(0x243);
2877 saved_243[1] = MCHBAR8(0x643);
2878 MCHBAR8(0x243) = saved_243[0] | 2;
2879 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002880 switch (info->clock_speed_index) {
2881 case 0:
2882 niter = 5;
2883 break;
2884 case 1:
2885 niter = 10;
2886 break;
2887 default:
2888 niter = 19;
2889 break;
2890 }
2891 set_ecc(0);
2892
2893 FOR_POPULATED_RANKS_BACKWARDS {
2894 int i;
2895
2896 write_500_timings_type(info, channel, slot, rank, 0);
2897
2898 write_testing(info, totalrank, 0);
2899 for (i = 0; i < niter; i++) {
2900 write_testing_type2(info, totalrank, 2, i, 0);
2901 write_testing_type2(info, totalrank, 3, i, 1);
2902 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002903 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002904 totalrank++;
2905 }
2906
2907 if (reg178_min[info->clock_speed_index] <
2908 reg178_max[info->clock_speed_index])
2909 memset(timings[reg178_min[info->clock_speed_index]], 0,
2910 sizeof(timings[0]) *
2911 (reg178_max[info->clock_speed_index] -
2912 reg178_min[info->clock_speed_index]));
2913 for (reg_178 = reg178_min[info->clock_speed_index];
2914 reg_178 < reg178_max[info->clock_speed_index];
2915 reg_178 += reg178_step[info->clock_speed_index]) {
2916 totalrank = 0;
2917 set_178(reg_178);
2918 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
2919 for (slot = 0; slot < NUM_SLOTS; slot++)
2920 for (rank = 0; rank < NUM_RANKS; rank++) {
2921 memset(&timings[reg_178][channel][slot]
2922 [rank][0].smallest, 0, 16);
2923 if (info->
2924 populated_ranks[channel][slot]
2925 [rank]) {
2926 train_ram_at_178(info, channel,
2927 slot, rank,
2928 totalrank,
2929 reg_178, 1,
2930 niter,
2931 timings);
2932 totalrank++;
2933 }
2934 }
2935 }
2936
2937 reg178_center = choose_reg178(info, timings);
2938
2939 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2940 info->training.timing_bounds[0][channel][slot][rank][lane].
2941 smallest =
2942 timings[info->training.
2943 reg178_smallest][channel][slot][rank][lane].
2944 smallest;
2945 info->training.timing_bounds[0][channel][slot][rank][lane].
2946 largest =
2947 timings[info->training.
2948 reg178_smallest][channel][slot][rank][lane].largest;
2949 info->training.timing_bounds[1][channel][slot][rank][lane].
2950 smallest =
2951 timings[info->training.
2952 reg178_largest][channel][slot][rank][lane].smallest;
2953 info->training.timing_bounds[1][channel][slot][rank][lane].
2954 largest =
2955 timings[info->training.
2956 reg178_largest][channel][slot][rank][lane].largest;
2957 info->training.timing_offset[channel][slot][rank][lane] =
2958 info->training.lane_timings[1][channel][slot][rank][lane]
2959 -
2960 info->training.lane_timings[0][channel][slot][rank][lane] +
2961 64;
2962 }
2963
2964 if (info->silicon_revision == 1
2965 && (info->
2966 populated_ranks_mask[1] ^ (info->
2967 populated_ranks_mask[1] >> 2)) & 1) {
2968 int ranks_after_channel1;
2969
2970 totalrank = 0;
2971 for (reg_178 = reg178_center - 18;
2972 reg_178 <= reg178_center + 18; reg_178 += 18) {
2973 totalrank = 0;
2974 set_178(reg_178);
2975 for (slot = 0; slot < NUM_SLOTS; slot++)
2976 for (rank = 0; rank < NUM_RANKS; rank++) {
2977 if (info->
2978 populated_ranks[1][slot][rank]) {
2979 train_ram_at_178(info, 1, slot,
2980 rank,
2981 totalrank,
2982 reg_178, 0,
2983 niter,
2984 timings);
2985 totalrank++;
2986 }
2987 }
2988 }
2989 ranks_after_channel1 = totalrank;
2990
2991 for (reg_178 = reg178_center - 12;
2992 reg_178 <= reg178_center + 12; reg_178 += 12) {
2993 totalrank = ranks_after_channel1;
2994 set_178(reg_178);
2995 for (slot = 0; slot < NUM_SLOTS; slot++)
2996 for (rank = 0; rank < NUM_RANKS; rank++)
2997 if (info->
2998 populated_ranks[0][slot][rank]) {
2999 train_ram_at_178(info, 0, slot,
3000 rank,
3001 totalrank,
3002 reg_178, 0,
3003 niter,
3004 timings);
3005 totalrank++;
3006 }
3007
3008 }
3009 } else {
3010 for (reg_178 = reg178_center - 12;
3011 reg_178 <= reg178_center + 12; reg_178 += 12) {
3012 totalrank = 0;
3013 set_178(reg_178);
3014 FOR_POPULATED_RANKS_BACKWARDS {
3015 train_ram_at_178(info, channel, slot, rank,
3016 totalrank, reg_178, 0, niter,
3017 timings);
3018 totalrank++;
3019 }
3020 }
3021 }
3022
3023 set_178(reg178_center);
3024 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3025 u16 tm0;
3026
3027 tm0 =
3028 choose_training(info, channel, slot, rank, lane, timings,
3029 reg178_center);
3030 write_500(info, channel, tm0,
3031 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3032 write_500(info, channel,
3033 tm0 +
3034 info->training.
3035 lane_timings[1][channel][slot][rank][lane] -
3036 info->training.
3037 lane_timings[0][channel][slot][rank][lane],
3038 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3039 }
3040
3041 totalrank = 0;
3042 FOR_POPULATED_RANKS_BACKWARDS {
3043 try_timing_offsets(info, channel, slot, rank, totalrank);
3044 totalrank++;
3045 }
Felix Held04be2dd2018-07-29 04:53:22 +02003046 MCHBAR8(0x243) = saved_243[0];
3047 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003048 write_1d0(0, 0x142, 3, 1);
3049 info->training.reg178_center = reg178_center;
3050}
3051
3052static void ram_training(struct raminfo *info)
3053{
3054 u16 saved_fc4;
3055
Felix Held04be2dd2018-07-29 04:53:22 +02003056 saved_fc4 = MCHBAR16(0xfc4);
3057 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003058
3059 if (info->revision >= 8)
3060 read_4090(info);
3061
3062 if (!try_cached_training(info))
3063 do_ram_training(info);
3064 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3065 && info->clock_speed_index < 2)
3066 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003067 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003068}
3069
Angel Pons7a87c922021-01-15 22:50:41 +01003070u16 get_max_timing(struct raminfo *info, int channel)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003071{
3072 int slot, rank, lane;
3073 u16 ret = 0;
3074
Felix Held04be2dd2018-07-29 04:53:22 +02003075 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003076 return 384;
3077
3078 if (info->revision < 8)
3079 return 256;
3080
3081 for (slot = 0; slot < NUM_SLOTS; slot++)
3082 for (rank = 0; rank < NUM_RANKS; rank++)
3083 if (info->populated_ranks[channel][slot][rank])
3084 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003085 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003086 get_timing_register_addr
3087 (lane, 0, slot,
3088 rank), 9));
3089 return ret;
3090}
3091
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003092static void dmi_setup(void)
3093{
Angel Ponsd071c4d2020-09-14 23:51:35 +02003094 gav(DMIBAR8(0x254));
3095 DMIBAR8(0x254) = 0x1;
3096 DMIBAR16(0x1b8) = 0x18f2;
Felix Heldf83d80b2018-07-29 05:30:30 +02003097 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003098
Angel Ponsd071c4d2020-09-14 23:51:35 +02003099 DMIBAR32(0xd68) |= 0x08000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003100
3101 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3102 DEFAULT_GPIOBASE | 0x38);
3103 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3104}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003105
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003106void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003107{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003108 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003109 u16 ggc;
3110 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003111
Felix Held04be2dd2018-07-29 04:53:22 +02003112 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003113 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3114 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003115 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003116 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003117 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003118
3119 dmi_setup();
3120
Felix Held04be2dd2018-07-29 04:53:22 +02003121 MCHBAR16(0x1170) = 0xa880;
3122 MCHBAR8(0x11c1) = 0x1;
3123 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003124 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003125
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003126 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3127 /* 0 for 32MB */
3128 gfxsize = 0;
3129 }
3130
3131 ggc = 0xb00 | ((gfxsize + 5) << 4);
3132
Angel Pons16fe1e02020-07-22 16:12:33 +02003133 pci_write_config16(NORTHBRIDGE, GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003134
3135 u16 deven;
Angel Pons16fe1e02020-07-22 16:12:33 +02003136 deven = pci_read_config16(NORTHBRIDGE, DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003137
3138 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003139 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003140 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003141 MCHBAR16_OR(0x2c30, 0x200);
3142 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003143 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Angel Ponsaaea66a2020-09-15 00:41:14 +02003144 pci_read_config8(GMA, MSAC); // = 0x2
3145 pci_write_config8(GMA, MSAC, 0x2);
Angel Ponsee7fb342021-01-28 14:11:55 +01003146 RCBA8(0x2318);
3147 RCBA8(0x2318) = 0x47;
3148 RCBA8(0x2320);
3149 RCBA8(0x2320) = 0xfc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003150 }
3151
Felix Heldf83d80b2018-07-29 05:30:30 +02003152 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003153
Angel Pons16fe1e02020-07-22 16:12:33 +02003154 pci_write_config16(NORTHBRIDGE, GGC, ggc);
Angel Ponsee7fb342021-01-28 14:11:55 +01003155 gav(RCBA32(0x3428));
3156 RCBA32(0x3428) = 0x1d;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003157}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003158
Angel Pons26681912021-01-15 21:36:28 +01003159static u8 get_bits_420(const u32 reg32)
3160{
3161 u8 val = 0;
3162 val |= (reg32 >> 4) & (1 << 0);
3163 val |= (reg32 >> 2) & (1 << 1);
3164 val |= (reg32 >> 0) & (1 << 2);
3165 return val;
3166}
3167
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003168void raminit(const int s3resume, const u8 *spd_addrmap)
3169{
Martin Roth468d02c2019-10-23 21:44:42 -06003170 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003171 struct raminfo info;
3172 u8 x2ca8;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003173 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003174
Felix Held04be2dd2018-07-29 04:53:22 +02003175 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003176
3177 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3178
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003179 memset(&info, 0x5a, sizeof(info));
3180
3181 info.last_500_command[0] = 0;
3182 info.last_500_command[1] = 0;
3183
3184 info.fsb_frequency = 135 * 2;
3185 info.board_lane_delay[0] = 0x14;
3186 info.board_lane_delay[1] = 0x07;
3187 info.board_lane_delay[2] = 0x07;
3188 info.board_lane_delay[3] = 0x08;
3189 info.board_lane_delay[4] = 0x56;
3190 info.board_lane_delay[5] = 0x04;
3191 info.board_lane_delay[6] = 0x04;
3192 info.board_lane_delay[7] = 0x05;
3193 info.board_lane_delay[8] = 0x10;
3194
3195 info.training.reg_178 = 0;
3196 info.training.reg_10b = 0;
3197
Angel Ponsa3868292021-01-15 22:10:13 +01003198 /* Wait for some bit, maybe TXT clear. */
3199 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
3200 ;
3201
3202 /* Wait for ME to be ready */
Angel Pons44479962021-02-24 23:08:27 +01003203 if (intel_early_me_init() == 0)
3204 info.memory_reserved_for_heci_mb = intel_early_me_uma_size();
3205 else
3206 info.memory_reserved_for_heci_mb = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003207
3208 /* before SPD */
3209 timestamp_add_now(101);
3210
Felix Held29a9c072018-07-29 01:34:45 +02003211 if (!s3resume || 1) { // possible error
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003212 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3213
3214 info.use_ecc = 1;
3215 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003216 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003217 int v;
3218 int try;
3219 int addr;
3220 const u8 useful_addresses[] = {
3221 DEVICE_TYPE,
3222 MODULE_TYPE,
3223 DENSITY,
3224 RANKS_AND_DQ,
3225 MEMORY_BUS_WIDTH,
3226 TIMEBASE_DIVIDEND,
3227 TIMEBASE_DIVISOR,
3228 CYCLETIME,
3229 CAS_LATENCIES_LSB,
3230 CAS_LATENCIES_MSB,
3231 CAS_LATENCY_TIME,
3232 0x11, 0x12, 0x13, 0x14, 0x15,
3233 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3234 0x1c, 0x1d,
3235 THERMAL_AND_REFRESH,
3236 0x20,
3237 REFERENCE_RAW_CARD_USED,
3238 RANK1_ADDRESS_MAPPING,
3239 0x75, 0x76, 0x77, 0x78,
3240 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3241 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3242 0x85, 0x86, 0x87, 0x88,
3243 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3244 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3245 0x95
3246 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003247 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003248 continue;
3249 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003250 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003251 DEVICE_TYPE);
3252 if (v >= 0)
3253 break;
3254 }
3255 if (v < 0)
3256 continue;
3257 for (addr = 0;
3258 addr <
Patrick Georgi6b688f52021-02-12 13:49:11 +01003259 ARRAY_SIZE(useful_addresses); addr++)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003260 gav(info.
3261 spd[channel][0][useful_addresses
3262 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003263 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003264 useful_addresses
3265 [addr]));
3266 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3267 die("Only DDR3 is supported");
3268
3269 v = info.spd[channel][0][RANKS_AND_DQ];
3270 info.populated_ranks[channel][0][0] = 1;
3271 info.populated_ranks[channel][0][1] =
3272 ((v >> 3) & 7);
3273 if (((v >> 3) & 7) > 1)
3274 die("At most 2 ranks are supported");
3275 if ((v & 7) == 0 || (v & 7) > 2)
3276 die("Only x8 and x16 modules are supported");
3277 if ((info.
3278 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3279 && (info.
3280 spd[channel][slot][MODULE_TYPE] & 0xF)
3281 != 3)
3282 die("Registered memory is not supported");
3283 info.is_x16_module[channel][0] = (v & 7) - 1;
3284 info.density[channel][slot] =
3285 info.spd[channel][slot][DENSITY] & 0xF;
3286 if (!
3287 (info.
3288 spd[channel][slot][MEMORY_BUS_WIDTH] &
3289 0x18))
3290 info.use_ecc = 0;
3291 }
3292
3293 gav(0x55);
3294
3295 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3296 int v = 0;
3297 for (slot = 0; slot < NUM_SLOTS; slot++)
3298 for (rank = 0; rank < NUM_RANKS; rank++)
3299 v |= info.
3300 populated_ranks[channel][slot][rank]
3301 << (2 * slot + rank);
3302 info.populated_ranks_mask[channel] = v;
3303 }
3304
3305 gav(0x55);
3306
Angel Pons16fe1e02020-07-22 16:12:33 +02003307 gav(pci_read_config32(NORTHBRIDGE, CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003308 }
3309
3310 /* after SPD */
3311 timestamp_add_now(102);
3312
Felix Held04be2dd2018-07-29 04:53:22 +02003313 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003314
3315 collect_system_info(&info);
3316 calculate_timings(&info);
3317
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003318 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003319 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003320 if (x2ca8 == 0 && (reg8 & 0x80)) {
3321 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3322 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3323 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3324 */
3325
3326 /* Clear bit7. */
3327
3328 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3329 (reg8 & ~(1 << 7)));
3330
3331 printk(BIOS_INFO,
3332 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003333 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003334 }
3335 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003336
3337 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003338 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3339 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003340
3341 compute_derived_timings(&info);
3342
Angel Pons56823f52021-01-16 11:27:33 +01003343 early_quickpath_init(&info, x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003344
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003345 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003346
Angel Pons7a87c922021-01-15 22:50:41 +01003347 if (x2ca8 == 0)
3348 late_quickpath_init(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003349
Angel Ponsc627dc92020-09-22 17:06:44 +02003350 MCHBAR32_OR(0x2c80, (1 << 24));
3351 MCHBAR32(0x1804) = MCHBAR32(0x1c04) & ~(1 << 27);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003352
Angel Ponsc627dc92020-09-22 17:06:44 +02003353 MCHBAR8(0x2ca8); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003354
3355 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003356 MCHBAR8_AND(0x2ca8, ~3);
3357 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003358 /* This issues a CPU reset without resetting the platform */
3359 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02003360 /* Write back the S3 state to PM1_CNT to let the reset CPU
3361 know it also needs to take the s3 path. */
3362 if (s3resume)
3363 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
3364 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02003365 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01003366 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003367 }
Angel Pons7a87c922021-01-15 22:50:41 +01003368
Angel Ponsc627dc92020-09-22 17:06:44 +02003369 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003370
Angel Ponsc627dc92020-09-22 17:06:44 +02003371 MCHBAR32_AND(0x2c80, ~(1 << 24));
3372
Angel Pons9addda32020-07-22 18:37:32 +02003373 pci_write_config32(QPI_NON_CORE, MAX_RTIDS, 0x20220);
Angel Ponsc627dc92020-09-22 17:06:44 +02003374
3375 {
3376 u8 x2c20 = (MCHBAR16(0x2c20) >> 8) & 3;
3377 u16 x2c10 = MCHBAR16(0x2c10);
3378 u16 value = MCHBAR16(0x2c00);
3379 if (x2c20 == 0 && (x2c10 & 0x300) == 0)
3380 value |= (1 << 7);
3381 else
3382 value &= ~(1 << 0);
3383
3384 MCHBAR16(0x2c00) = value;
3385 }
3386
3387 udelay(1000); // !!!!
3388
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003389 write_1d0(0, 0x33d, 0, 0);
3390 write_500(&info, 0, 0, 0xb61, 0, 0);
3391 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003392 MCHBAR32(0x1a30) = 0x0;
3393 MCHBAR32(0x1a34) = 0x0;
3394 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
3395 (info.populated_ranks[0][0][0] * 0xa0);
3396 MCHBAR16(0x616) = 0x26a;
3397 MCHBAR32(0x134) = 0x856000;
3398 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02003399 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
3400 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003401 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02003402 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
3403 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003404 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003405 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02003406 MCHBAR16(0x360 + (channel << 10)) = 0x909;
3407 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02003408 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
3409 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
3410 MCHBAR32(0x324 + (channel << 10)) = 0x0;
3411 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
3412 MCHBAR16(0x352 + (channel << 10)) = 0x505;
3413 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
3414 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
3415 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
3416 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
3417 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003418 }
3419
3420 write_1d0(0x4, 0x151, 4, 1);
3421 write_1d0(0, 0x142, 3, 1);
3422 rdmsr(0x1ac); // !!!!
3423 write_500(&info, 1, 1, 0x6b3, 4, 1);
3424 write_500(&info, 1, 1, 0x6cf, 4, 1);
3425
Angel Pons244f4552021-01-15 20:41:36 +01003426 rmw_1d0(0x21c, 0x38, 0, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003427
3428 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
3429 populated_ranks[0]
3430 [0][0]) << 0),
3431 0x1d1, 3, 1);
3432 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003433 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
3434 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003435 }
3436
3437 set_334(0);
3438
3439 program_base_timings(&info);
3440
Felix Held04be2dd2018-07-29 04:53:22 +02003441 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003442
3443 write_1d0(0x2, 0x1d5, 2, 1);
3444 write_1d0(0x20, 0x166, 7, 1);
3445 write_1d0(0x0, 0xeb, 3, 1);
3446 write_1d0(0x0, 0xf3, 6, 1);
3447
Angel Pons3d357562021-01-16 14:46:45 +01003448 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3449 u8 a = 0;
3450 if (info.populated_ranks[channel][0][1] && info.clock_speed_index > 1)
3451 a = 3;
3452 if (info.silicon_revision == 0 || info.silicon_revision == 1)
3453 a = 3;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003454
Angel Pons3d357562021-01-16 14:46:45 +01003455 for (lane = 0; lane < 9; lane++) {
3456 const u16 addr = 0x125 + get_lane_offset(0, 0, lane);
3457 rmw_500(&info, channel, addr, 6, 0xf, a);
3458 }
3459 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003460
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003461 if (s3resume) {
3462 if (info.cached_training == NULL) {
3463 u32 reg32;
3464 printk(BIOS_ERR,
3465 "Couldn't find training data. Rebooting\n");
3466 reg32 = inl(DEFAULT_PMBASE + 0x04);
3467 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003468 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003469 }
3470 int tm;
3471 info.training = *info.cached_training;
3472 for (tm = 0; tm < 4; tm++)
3473 for (channel = 0; channel < NUM_CHANNELS; channel++)
3474 for (slot = 0; slot < NUM_SLOTS; slot++)
3475 for (rank = 0; rank < NUM_RANKS; rank++)
3476 for (lane = 0; lane < 9; lane++)
3477 write_500(&info,
3478 channel,
3479 info.training.
3480 lane_timings
3481 [tm][channel]
3482 [slot][rank]
3483 [lane],
3484 get_timing_register_addr
3485 (lane, tm,
3486 slot, rank),
3487 9, 0);
3488 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
3489 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
3490 }
3491
Felix Heldf83d80b2018-07-29 05:30:30 +02003492 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02003493 MCHBAR32(0x1f0) = 0x1d000200;
Angel Ponsc627dc92020-09-22 17:06:44 +02003494 MCHBAR8_OR(0x1f0, 0x1);
3495 while (MCHBAR8(0x1f0) & 1)
3496 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003497
3498 program_board_delay(&info);
3499
Felix Held04be2dd2018-07-29 04:53:22 +02003500 MCHBAR8(0x5ff) = 0x0;
3501 MCHBAR8(0x5ff) = 0x80;
3502 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003503
Felix Held04be2dd2018-07-29 04:53:22 +02003504 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02003505 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02003506 ;
Angel Ponsc627dc92020-09-22 17:06:44 +02003507
3508 rmw_1d0(0x14b, 0x47, 0x30, 7);
3509 rmw_1d0(0xd6, 0x38, 7, 6);
3510 rmw_1d0(0x328, 0x38, 7, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003511
3512 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003513 set_4cf(&info, channel, 1, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003514
Angel Ponsc627dc92020-09-22 17:06:44 +02003515 rmw_1d0(0x116, 0xe, 0, 4);
3516 rmw_1d0(0xae, 0x3e, 0, 6);
3517 rmw_1d0(0x300, 0x3e, 0, 6);
3518 MCHBAR16_AND(0x356, 0x7fff);
3519 MCHBAR16_AND(0x756, 0x7fff);
Felix Held04be2dd2018-07-29 04:53:22 +02003520 MCHBAR32_AND(0x140, ~0x07000000);
3521 MCHBAR32_AND(0x138, ~0x07000000);
3522 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01003523 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02003524 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01003525 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003526
Angel Pons26681912021-01-15 21:36:28 +01003527 u8 value_a1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003528 {
Angel Pons26681912021-01-15 21:36:28 +01003529 const u8 val_xa1 = get_bits_420(read_1d0(0xa1, 6)); // = 0x1cf4040 // !!!!
3530 const u8 val_2f3 = get_bits_420(read_1d0(0x2f3, 6)); // = 0x10a4040 // !!!!
3531 value_a1 = val_xa1;
3532 rmw_1d0(0x320, 0x38, val_2f3, 6);
3533 rmw_1d0(0x14b, 0x78, val_xa1, 7);
3534 rmw_1d0(0xce, 0x38, val_xa1, 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003535 }
3536
3537 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003538 set_4cf(&info, channel, 1, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003539
Angel Pons244f4552021-01-15 20:41:36 +01003540 rmw_1d0(0x116, 0xe, 1, 4); // = 0x4040432 // !!!!
Angel Pons26681912021-01-15 21:36:28 +01003541 {
3542 if ((MCHBAR32(0x144) & 0x1f) < 0x13)
3543 value_a1 += 2;
3544 else
3545 value_a1 += 1;
3546
3547 if (value_a1 > 7)
3548 value_a1 = 7;
3549
3550 write_1d0(2, 0xae, 6, 1);
3551 write_1d0(2, 0x300, 6, 1);
3552 write_1d0(value_a1, 0x121, 3, 1);
3553 rmw_1d0(0xd6, 0x38, 4, 6);
3554 rmw_1d0(0x328, 0x38, 4, 6);
3555 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003556
3557 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003558 set_4cf(&info, channel, 2, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003559
Felix Held04be2dd2018-07-29 04:53:22 +02003560 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
3561 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02003562 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02003563 ;
Angel Ponsc627dc92020-09-22 17:06:44 +02003564
3565 {
Angel Pons26681912021-01-15 21:36:28 +01003566 const u8 val_xa1 = get_bits_420(read_1d0(0xa1, 6));
Angel Ponsc627dc92020-09-22 17:06:44 +02003567 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
3568 rmw_1d0(0x21c, 0x38, 0, 6);
Angel Pons26681912021-01-15 21:36:28 +01003569 rmw_1d0(0x14b, 0x78, val_xa1, 7);
Angel Ponsc627dc92020-09-22 17:06:44 +02003570 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003571
3572 for (channel = 0; channel < NUM_CHANNELS; channel++)
Angel Ponsc10f8b22021-01-15 20:34:51 +01003573 set_4cf(&info, channel, 2, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003574
3575 set_334(1);
3576
Felix Held04be2dd2018-07-29 04:53:22 +02003577 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003578
3579 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3580 write_500(&info, channel,
3581 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
3582 1);
3583 write_500(&info, channel, 0x3, 0x69b, 2, 1);
3584 }
Felix Held04be2dd2018-07-29 04:53:22 +02003585 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
3586 MCHBAR16(0x6c0) = 0x14a0;
3587 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
3588 MCHBAR16(0x232) = 0x8;
3589 /* 0x40004 or 0 depending on ? */
3590 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
3591 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
3592 MCHBAR32(0x128) = 0x2150d05;
3593 MCHBAR8(0x12c) = 0x1f;
3594 MCHBAR8(0x12d) = 0x56;
3595 MCHBAR8(0x12e) = 0x31;
3596 MCHBAR8(0x12f) = 0x0;
3597 MCHBAR8(0x271) = 0x2;
3598 MCHBAR8(0x671) = 0x2;
3599 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003600 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02003601 MCHBAR32(0x294 + (channel << 10)) =
3602 (info.populated_ranks_mask[channel] & 3) << 16;
3603 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
3604 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003605 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02003606 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
3607 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003608
3609 if (!s3resume)
3610 jedec_init(&info);
3611
3612 int totalrank = 0;
3613 for (channel = 0; channel < NUM_CHANNELS; channel++)
3614 for (slot = 0; slot < NUM_SLOTS; slot++)
3615 for (rank = 0; rank < NUM_RANKS; rank++)
3616 if (info.populated_ranks[channel][slot][rank]) {
3617 jedec_read(&info, channel, slot, rank,
3618 totalrank, 0xa, 0x400);
3619 totalrank++;
3620 }
3621
Felix Held04be2dd2018-07-29 04:53:22 +02003622 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003623
Angel Ponsc627dc92020-09-22 17:06:44 +02003624 MCHBAR8_AND_OR(0x271, 0xcf, 0xe);
3625 MCHBAR8_AND_OR(0x671, 0xcf, 0xe);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003626
3627 if (!s3resume) {
3628 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003629 MCHBAR32(0x294 + (channel << 10)) =
3630 (info.populated_ranks_mask[channel] & 3) << 16;
3631 MCHBAR16(0x298 + (channel << 10)) =
3632 info.populated_ranks[channel][0][0] |
3633 (info.populated_ranks[channel][0][1] << 5);
3634 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003635 }
Felix Heldf83d80b2018-07-29 05:30:30 +02003636 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003637
3638 {
3639 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02003640 a = MCHBAR8(0x243);
3641 b = MCHBAR8(0x643);
3642 MCHBAR8(0x243) = a | 2;
3643 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003644 }
3645
3646 write_1d0(7, 0x19b, 3, 1);
3647 write_1d0(7, 0x1c0, 3, 1);
3648 write_1d0(4, 0x1c6, 4, 1);
3649 write_1d0(4, 0x1cc, 4, 1);
Angel Ponsc627dc92020-09-22 17:06:44 +02003650 rmw_1d0(0x151, 0xf, 0x4, 4);
Felix Held04be2dd2018-07-29 04:53:22 +02003651 MCHBAR32(0x584) = 0xfffff;
3652 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003653
3654 for (channel = 0; channel < NUM_CHANNELS; channel++)
3655 for (slot = 0; slot < NUM_SLOTS; slot++)
3656 for (rank = 0; rank < NUM_RANKS; rank++)
3657 if (info.
3658 populated_ranks[channel][slot]
3659 [rank])
3660 config_rank(&info, s3resume,
3661 channel, slot,
3662 rank);
3663
Felix Held04be2dd2018-07-29 04:53:22 +02003664 MCHBAR8(0x243) = 0x1;
3665 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003666 }
3667
3668 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003669 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003670 write_26c(0, 0x820);
3671 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02003672 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003673 /* end */
3674
3675 if (s3resume) {
3676 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003677 MCHBAR32(0x294 + (channel << 10)) =
3678 (info.populated_ranks_mask[channel] & 3) << 16;
3679 MCHBAR16(0x298 + (channel << 10)) =
3680 info.populated_ranks[channel][0][0] |
3681 (info.populated_ranks[channel][0][1] << 5);
3682 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003683 }
Felix Heldf83d80b2018-07-29 05:30:30 +02003684 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003685 }
3686
Felix Held04be2dd2018-07-29 04:53:22 +02003687 MCHBAR32_AND(0xfa4, ~0x01000002);
3688 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003689
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003690 /* Before training. */
3691 timestamp_add_now(103);
3692
3693 if (!s3resume)
3694 ram_training(&info);
3695
3696 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02003697 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003698
3699 dump_timings(&info);
3700
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003701 program_modules_memory_map(&info, 0);
3702 program_total_memory_map(&info);
3703
3704 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02003705 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003706 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02003707 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003708 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02003709 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003710 else
Felix Held04be2dd2018-07-29 04:53:22 +02003711 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003712
Felix Held04be2dd2018-07-29 04:53:22 +02003713 MCHBAR32_AND(0xfac, ~0x80000000);
3714 MCHBAR32(0xfb4) = 0x4800;
3715 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
3716 MCHBAR32(0xe94) = 0x7ffff;
3717 MCHBAR32(0xfc0) = 0x80002040;
3718 MCHBAR32(0xfc4) = 0x701246;
3719 MCHBAR8_AND(0xfc8, ~0x70);
3720 MCHBAR32_OR(0xe5c, 0x1000000);
3721 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
3722 MCHBAR32(0x50) = 0x700b0;
3723 MCHBAR32(0x3c) = 0x10;
3724 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
3725 MCHBAR8_OR(0xff4, 0x2);
3726 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003727
Felix Held04be2dd2018-07-29 04:53:22 +02003728 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
3729 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
3730 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003731
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003732 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
3733 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
3734 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003735
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003736 {
3737 u32 eax;
3738
3739 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02003740 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
3741 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
3742 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003743 }
3744
3745 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003746 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003747 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02003748 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003749 else
Felix Held04be2dd2018-07-29 04:53:22 +02003750 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003751
Felix Held04be2dd2018-07-29 04:53:22 +02003752 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003753
Felix Held04be2dd2018-07-29 04:53:22 +02003754 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003755 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02003756 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003757 else
Felix Held04be2dd2018-07-29 04:53:22 +02003758 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003759 }
3760
Felix Held04be2dd2018-07-29 04:53:22 +02003761 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003762
3763 {
3764 u8 al;
3765 al = 0xd;
3766 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
3767 al += 2;
3768 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02003769 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003770 }
3771
3772 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02003773 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
3774 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
3775 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
3776 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003777 }
3778 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003779 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02003780 reg1c = EPBAR32(EPVC1RCAP); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003781 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Angel Pons3b264d02020-09-15 00:25:49 +02003782 EPBAR32(EPVC1RCAP) = reg1c; // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02003783 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003784 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02003785 MCHBAR8_OR(0x1210, 2);
3786 MCHBAR32(0x1200) = 0x8800440;
3787 MCHBAR32(0x1204) = 0x53ff0453;
3788 MCHBAR32(0x1208) = 0x19002043;
3789 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003790
3791 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02003792 MCHBAR16(0x1214) = 0x220;
3793 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003794 }
3795
Felix Held04be2dd2018-07-29 04:53:22 +02003796 MCHBAR8_OR(0x1214, 0x4);
3797 MCHBAR8(0x120c) = 0x1;
3798 MCHBAR8(0x1218) = 0x3;
3799 MCHBAR8(0x121a) = 0x3;
3800 MCHBAR8(0x121c) = 0x3;
3801 MCHBAR16(0xc14) = 0x0;
3802 MCHBAR16(0xc20) = 0x0;
3803 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003804
3805 /* revision dependent here. */
3806
Felix Held04be2dd2018-07-29 04:53:22 +02003807 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003808
3809 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02003810 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003811
Felix Held04be2dd2018-07-29 04:53:22 +02003812 MCHBAR16_OR(0x1230, 0x8000);
3813 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003814
3815 u8 bl, ebpb;
3816 u16 reg_1020;
3817
Felix Held04be2dd2018-07-29 04:53:22 +02003818 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
3819 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003820
Felix Held04be2dd2018-07-29 04:53:22 +02003821 MCHBAR32(0x1000) = 0x100;
3822 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003823
3824 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003825 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003826 bl = reg_1020 >> 8;
3827 ebpb = reg_1020 & 0xff;
3828 } else {
3829 ebpb = 0;
3830 bl = 8;
3831 }
3832
3833 rdmsr(0x1a2);
3834
Felix Held04be2dd2018-07-29 04:53:22 +02003835 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003836
Felix Held04be2dd2018-07-29 04:53:22 +02003837 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003838
Felix Held04be2dd2018-07-29 04:53:22 +02003839 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003840
Felix Held04be2dd2018-07-29 04:53:22 +02003841 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003842 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003843 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
3844 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003845 }
3846
3847 setup_heci_uma(&info);
3848
3849 if (info.uma_enabled) {
3850 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02003851 MCHBAR32_OR(0x11b0, 0x4000);
3852 MCHBAR32_OR(0x11b4, 0x4000);
3853 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003854
Felix Held04be2dd2018-07-29 04:53:22 +02003855 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
3856 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
3857 MCHBAR16_OR(0x1170, 0x1000);
3858
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003859 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02003860
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003861 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02003862 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02003863 ;
3864 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003865 }
3866
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003867 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3868 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003869 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02003870 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003871
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003872 udelay(1000);
3873 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003874 cbmem_wasnot_inited = cbmem_recovery(s3resume);
3875
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003876 if (!s3resume)
3877 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003878 if (s3resume && cbmem_wasnot_inited) {
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003879 printk(BIOS_ERR, "Failed S3 resume.\n");
Kyösti Mälkkie1aa9832019-03-23 10:00:31 +02003880 ram_check_nodie(1 * MiB);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003881
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003882 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003883 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003884 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003885}