blob: 7735522da94ccb6c10e758bde69b6eb355fbe2fc [file] [log] [blame]
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013 Vladimir Serbinenko.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010015 */
16
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010017#include <console/console.h>
Elyes HAOUASba9b5042019-12-19 07:47:52 +010018#include <commonlib/helpers.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010019#include <string.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010020#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020021#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020022#include <device/pci_ops.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010023#include <cpu/x86/msr.h>
24#include <cbmem.h>
Elyes HAOUASd45f3382019-04-28 18:04:35 +020025#include <cf9_reset.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010026#include <ip_checksum.h>
Kyösti Mälkkicbf95712020-01-05 08:05:45 +020027#include <option.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010028#include <device/pci_def.h>
Patrick Rudolph266a1f72016-06-09 18:13:34 +020029#include <device/device.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010030#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010031#include <spd.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010032#include <timestamp.h>
33#include <cpu/x86/mtrr.h>
34#include <cpu/intel/speedstep.h>
35#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010036#include <mrc_cache.h>
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020037#include <southbridge/intel/ibexpeak/me.h>
Arthur Heymans2878c0b2019-10-14 18:42:00 +020038#include <southbridge/intel/common/pmbase.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010039#include <delay.h>
Elyes HAOUAS51401c32019-05-15 21:09:30 +020040#include <types.h>
41
42#include "chip.h"
43#include "nehalem.h"
44#include "raminit.h"
Angel Pons18a55cd2019-08-14 20:46:00 +020045#include "raminit_tables.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010046
47#define NORTHBRIDGE PCI_DEV(0, 0, 0)
48#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
49#define GMA PCI_DEV (0, 0x2, 0x0)
50#define HECIDEV PCI_DEV(0, 0x16, 0)
51#define HECIBAR 0x10
52
53#define FOR_ALL_RANKS \
54 for (channel = 0; channel < NUM_CHANNELS; channel++) \
55 for (slot = 0; slot < NUM_SLOTS; slot++) \
56 for (rank = 0; rank < NUM_RANKS; rank++)
57
58#define FOR_POPULATED_RANKS \
59 for (channel = 0; channel < NUM_CHANNELS; channel++) \
60 for (slot = 0; slot < NUM_SLOTS; slot++) \
61 for (rank = 0; rank < NUM_RANKS; rank++) \
62 if (info->populated_ranks[channel][slot][rank])
63
64#define FOR_POPULATED_RANKS_BACKWARDS \
65 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
66 for (slot = 0; slot < NUM_SLOTS; slot++) \
67 for (rank = 0; rank < NUM_RANKS; rank++) \
68 if (info->populated_ranks[channel][slot][rank])
69
70/* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */
71typedef struct {
72 u8 smallest;
73 u8 largest;
74} timing_bounds_t[2][2][2][9];
75
Arthur Heymansdc71e252018-01-29 10:14:48 +010076#define MRC_CACHE_VERSION 1
77
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010078struct ram_training {
79 /* [TM][CHANNEL][SLOT][RANK][LANE] */
80 u16 lane_timings[4][2][2][2][9];
81 u16 reg_178;
82 u16 reg_10b;
83
84 u8 reg178_center;
85 u8 reg178_smallest;
86 u8 reg178_largest;
87 timing_bounds_t timing_bounds[2];
88 u16 timing_offset[2][2][2][9];
89 u16 timing2_offset[2][2][2][9];
90 u16 timing2_bounds[2][2][2][9][2];
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +010091 u8 reg274265[2][3]; /* [CHANNEL][REGISTER] */
92 u8 reg2ca9_bit0;
93 u32 reg_6dc;
94 u32 reg_6e8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010095};
96
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010097#include <lib.h> /* Prototypes */
98
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010099
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100100static void clflush(u32 addr)
101{
102 asm volatile ("clflush (%0)"::"r" (addr));
103}
104
105typedef struct _u128 {
106 u64 lo;
107 u64 hi;
108} u128;
109
110static void read128(u32 addr, u64 * out)
111{
112 u128 ret;
113 u128 stor;
114 asm volatile ("movdqu %%xmm0, %0\n"
115 "movdqa (%2), %%xmm0\n"
116 "movdqu %%xmm0, %1\n"
117 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
118 out[0] = ret.lo;
119 out[1] = ret.hi;
120}
121
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100122/* OK */
123static void write_1d0(u32 val, u16 addr, int bits, int flag)
124{
Felix Held04be2dd2018-07-29 04:53:22 +0200125 MCHBAR32(0x1d0) = 0;
126 while (MCHBAR32(0x1d0) & 0x800000)
127 ;
128 MCHBAR32(0x1d4) =
129 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
130 MCHBAR32(0x1d0) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200131 while (MCHBAR32(0x1d0) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200132 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100133}
134
135/* OK */
136static u16 read_1d0(u16 addr, int split)
137{
138 u32 val;
Felix Held04be2dd2018-07-29 04:53:22 +0200139 MCHBAR32(0x1d0) = 0;
140 while (MCHBAR32(0x1d0) & 0x800000)
141 ;
142 MCHBAR32(0x1d0) =
143 0x80000000 | (((MCHBAR8(0x246) >> 2) & 3) + 0x361 - addr);
144 while (MCHBAR32(0x1d0) & 0x800000)
145 ;
146 val = MCHBAR32(0x1d8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100147 write_1d0(0, 0x33d, 0, 0);
148 write_1d0(0, 0x33d, 0, 0);
149 val &= ((1 << split) - 1);
150 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
151 return val;
152}
153
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800154static void write32p(uintptr_t addr, uint32_t val)
155{
156 write32((void *)addr, val);
157}
158
159static uint32_t read32p(uintptr_t addr)
160{
161 return read32((void *)addr);
162}
163
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100164static void sfence(void)
165{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100166 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100167}
168
169static inline u16 get_lane_offset(int slot, int rank, int lane)
170{
171 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
172 0x452 * (lane == 8);
173}
174
175static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
176{
177 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
178 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
179}
180
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100181static u32 gav_real(int line, u32 in)
182{
183 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
184 return in;
185}
186
187#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200188
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100189struct raminfo {
190 u16 clock_speed_index; /* clock_speed (REAL, not DDR) / 133.(3) - 3 */
191 u16 fsb_frequency; /* in 1.(1)/2 MHz. */
192 u8 is_x16_module[2][2]; /* [CHANNEL][SLOT] */
193 u8 density[2][2]; /* [CHANNEL][SLOT] */
194 u8 populated_ranks[2][2][2]; /* [CHANNEL][SLOT][RANK] */
195 int rank_start[2][2][2];
196 u8 cas_latency;
197 u8 board_lane_delay[9];
198 u8 use_ecc;
199 u8 revision;
200 u8 max_supported_clock_speed_index;
201 u8 uma_enabled;
202 u8 spd[2][2][151]; /* [CHANNEL][SLOT][BYTE] */
203 u8 silicon_revision;
204 u8 populated_ranks_mask[2];
205 u8 max_slots_used_in_channel;
206 u8 mode4030[2];
207 u16 avg4044[2];
208 u16 max4048[2];
Martin Roth468d02c2019-10-23 21:44:42 -0600209 unsigned int total_memory_mb;
210 unsigned int interleaved_part_mb;
211 unsigned int non_interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100212
213 u32 heci_bar;
214 u64 heci_uma_addr;
Martin Roth468d02c2019-10-23 21:44:42 -0600215 unsigned int memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100216
217 struct ram_training training;
218 u32 last_500_command[2];
219
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100220 u32 delay46_ps[2];
221 u32 delay54_ps[2];
222 u8 revision_flag_1;
223 u8 some_delay_1_cycle_floor;
224 u8 some_delay_2_halfcycles_ceil;
225 u8 some_delay_3_ps_rounded;
226
227 const struct ram_training *cached_training;
228};
229
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200230/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100231timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200232
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100233static void
234write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
235 int flag);
236
237/* OK */
238static u16
239read_500(struct raminfo *info, int channel, u16 addr, int split)
240{
241 u32 val;
242 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200243 MCHBAR32(0x500 + (channel << 10)) = 0;
244 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
245 ;
246 MCHBAR32(0x500 + (channel << 10)) =
247 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
248 + 0xb88 - addr);
249 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
250 ;
251 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100252 return val & ((1 << split) - 1);
253}
254
255/* OK */
256static void
257write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
258 int flag)
259{
260 if (info->last_500_command[channel] == 0x80000000) {
261 info->last_500_command[channel] = 0x40000000;
262 write_500(info, channel, 0, 0xb61, 0, 0);
263 }
Felix Held04be2dd2018-07-29 04:53:22 +0200264 MCHBAR32(0x500 + (channel << 10)) = 0;
265 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
266 ;
267 MCHBAR32(0x504 + (channel << 10)) =
268 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
269 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200270 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200271 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100272}
273
274static int rw_test(int rank)
275{
276 const u32 mask = 0xf00fc33c;
277 int ok = 0xff;
278 int i;
279 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800280 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100281 sfence();
282 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800283 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100284 sfence();
285 for (i = 0; i < 32; i++) {
286 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800287 write32p((rank << 28) | (i << 3), pat);
288 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100289 }
290 sfence();
291 for (i = 0; i < 32; i++) {
292 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
293 int j;
294 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800295 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100296 for (j = 0; j < 4; j++)
297 if (((val >> (j * 8)) & 0xff) != pat)
298 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800299 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100300 for (j = 0; j < 4; j++)
301 if (((val >> (j * 8)) & 0xff) != pat)
302 ok &= ~(16 << j);
303 }
304 sfence();
305 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800306 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100307 sfence();
308 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800309 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100310
311 return ok;
312}
313
314static void
315program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
316{
317 int lane;
318 for (lane = 0; lane < 8; lane++) {
319 write_500(info, channel,
320 base +
321 info->training.
322 lane_timings[2][channel][slot][rank][lane],
323 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
324 write_500(info, channel,
325 base +
326 info->training.
327 lane_timings[3][channel][slot][rank][lane],
328 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
329 }
330}
331
332static void write_26c(int channel, u16 si)
333{
Felix Held04be2dd2018-07-29 04:53:22 +0200334 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
335 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
336 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100337}
338
339static u32 get_580(int channel, u8 addr)
340{
341 u32 ret;
342 gav(read_1d0(0x142, 3));
Felix Held04be2dd2018-07-29 04:53:22 +0200343 MCHBAR8(0x5ff) = 0x0;
344 MCHBAR8(0x5ff) = 0x80;
345 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
346 MCHBAR8_OR(0x580 + (channel << 10), 1);
347 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
348 ;
349 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100350 return ret;
351}
352
353const int cached_config = 0;
354
355#define NUM_CHANNELS 2
356#define NUM_SLOTS 2
357#define NUM_RANKS 2
358#define RANK_SHIFT 28
359#define CHANNEL_SHIFT 10
360
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100361static void seq9(struct raminfo *info, int channel, int slot, int rank)
362{
363 int i, lane;
364
365 for (i = 0; i < 2; i++)
366 for (lane = 0; lane < 8; lane++)
367 write_500(info, channel,
368 info->training.lane_timings[i +
369 1][channel][slot]
370 [rank][lane], get_timing_register_addr(lane,
371 i + 1,
372 slot,
373 rank),
374 9, 0);
375
376 write_1d0(1, 0x103, 6, 1);
377 for (lane = 0; lane < 8; lane++)
378 write_500(info, channel,
379 info->training.
380 lane_timings[0][channel][slot][rank][lane],
381 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
382
383 for (i = 0; i < 2; i++) {
384 for (lane = 0; lane < 8; lane++)
385 write_500(info, channel,
386 info->training.lane_timings[i +
387 1][channel][slot]
388 [rank][lane], get_timing_register_addr(lane,
389 i + 1,
390 slot,
391 rank),
392 9, 0);
393 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
394 }
395
396 gav(read_1d0(0x142, 3)); // = 0x10408118
Felix Held04be2dd2018-07-29 04:53:22 +0200397 MCHBAR8(0x5ff) = 0x0;
398 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100399 write_1d0(0x2, 0x142, 3, 1);
400 for (lane = 0; lane < 8; lane++) {
401 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
402 info->training.lane_timings[2][channel][slot][rank][lane] =
403 read_500(info, channel,
404 get_timing_register_addr(lane, 2, slot, rank), 9);
405 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
406 info->training.lane_timings[3][channel][slot][rank][lane] =
407 info->training.lane_timings[2][channel][slot][rank][lane] +
408 0x20;
409 }
410}
411
412static int count_ranks_in_channel(struct raminfo *info, int channel)
413{
414 int slot, rank;
415 int res = 0;
416 for (slot = 0; slot < NUM_SLOTS; slot++)
417 for (rank = 0; rank < NUM_SLOTS; rank++)
418 res += info->populated_ranks[channel][slot][rank];
419 return res;
420}
421
422static void
423config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
424{
425 int add;
426
427 write_1d0(0, 0x178, 7, 1);
428 seq9(info, channel, slot, rank);
429 program_timings(info, 0x80, channel, slot, rank);
430
431 if (channel == 0)
432 add = count_ranks_in_channel(info, 1);
433 else
434 add = 0;
435 if (!s3resume)
436 gav(rw_test(rank + add));
437 program_timings(info, 0x00, channel, slot, rank);
438 if (!s3resume)
439 gav(rw_test(rank + add));
440 if (!s3resume)
441 gav(rw_test(rank + add));
442 write_1d0(0, 0x142, 3, 1);
443 write_1d0(0, 0x103, 6, 1);
444
445 gav(get_580(channel, 0xc | (rank << 5)));
446 gav(read_1d0(0x142, 3));
447
Felix Held04be2dd2018-07-29 04:53:22 +0200448 MCHBAR8(0x5ff) = 0x0;
449 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100450}
451
452static void set_4cf(struct raminfo *info, int channel, u8 val)
453{
454 gav(read_500(info, channel, 0x4cf, 4)); // = 0xc2300cf9
455 write_500(info, channel, val, 0x4cf, 4, 1);
456 gav(read_500(info, channel, 0x659, 4)); // = 0x80300839
457 write_500(info, channel, val, 0x659, 4, 1);
458 gav(read_500(info, channel, 0x697, 4)); // = 0x80300839
459 write_500(info, channel, val, 0x697, 4, 1);
460}
461
462static void set_334(int zero)
463{
464 int j, k, channel;
465 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
466 u32 vd8[2][16];
467
468 for (channel = 0; channel < NUM_CHANNELS; channel++) {
469 for (j = 0; j < 4; j++) {
470 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
471 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
472 u16 c;
473 if ((j == 0 || j == 3) && zero)
474 c = 0;
475 else if (j == 3)
476 c = 0x5f;
477 else
478 c = 0x5f5f;
479
480 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200481 MCHBAR32(0x138 + 8 * k) =
482 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100483 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200484 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100485 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200486 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100487 }
488
Felix Held22ca8cb2018-07-29 05:09:44 +0200489 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
490 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200491 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
492 zero ? 0 : (0x18191819 & lmask);
493 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
494 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
495 zero ? 0 : (a & lmask);
496 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
497 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100498 }
499 }
500
Felix Held04be2dd2018-07-29 04:53:22 +0200501 MCHBAR32_OR(0x130, 1);
502 while (MCHBAR8(0x130) & 1)
503 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100504}
505
506static void rmw_1d0(u16 addr, u32 and, u32 or, int split, int flag)
507{
508 u32 v;
509 v = read_1d0(addr, split);
510 write_1d0((v & and) | or, addr, split, flag);
511}
512
513static int find_highest_bit_set(u16 val)
514{
515 int i;
516 for (i = 15; i >= 0; i--)
517 if (val & (1 << i))
518 return i;
519 return -1;
520}
521
522static int find_lowest_bit_set32(u32 val)
523{
524 int i;
525 for (i = 0; i < 32; i++)
526 if (val & (1 << i))
527 return i;
528 return -1;
529}
530
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100531enum {
532 DEVICE_TYPE = 2,
533 MODULE_TYPE = 3,
534 DENSITY = 4,
535 RANKS_AND_DQ = 7,
536 MEMORY_BUS_WIDTH = 8,
537 TIMEBASE_DIVIDEND = 10,
538 TIMEBASE_DIVISOR = 11,
539 CYCLETIME = 12,
540
541 CAS_LATENCIES_LSB = 14,
542 CAS_LATENCIES_MSB = 15,
543 CAS_LATENCY_TIME = 16,
544 THERMAL_AND_REFRESH = 31,
545 REFERENCE_RAW_CARD_USED = 62,
546 RANK1_ADDRESS_MAPPING = 63
547};
548
549static void calculate_timings(struct raminfo *info)
550{
Martin Roth468d02c2019-10-23 21:44:42 -0600551 unsigned int cycletime;
552 unsigned int cas_latency_time;
553 unsigned int supported_cas_latencies;
554 unsigned int channel, slot;
555 unsigned int clock_speed_index;
556 unsigned int min_cas_latency;
557 unsigned int cas_latency;
558 unsigned int max_clock_index;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100559
560 /* Find common CAS latency */
561 supported_cas_latencies = 0x3fe;
562 for (channel = 0; channel < NUM_CHANNELS; channel++)
563 for (slot = 0; slot < NUM_SLOTS; slot++)
564 if (info->populated_ranks[channel][slot][0])
565 supported_cas_latencies &=
566 2 *
567 (info->
568 spd[channel][slot][CAS_LATENCIES_LSB] |
569 (info->
570 spd[channel][slot][CAS_LATENCIES_MSB] <<
571 8));
572
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100573 max_clock_index = MIN(3, info->max_supported_clock_speed_index);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100574
575 cycletime = min_cycletime[max_clock_index];
576 cas_latency_time = min_cas_latency_time[max_clock_index];
577
578 for (channel = 0; channel < NUM_CHANNELS; channel++)
579 for (slot = 0; slot < NUM_SLOTS; slot++)
580 if (info->populated_ranks[channel][slot][0]) {
Martin Roth468d02c2019-10-23 21:44:42 -0600581 unsigned int timebase;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100582 timebase =
583 1000 *
584 info->
585 spd[channel][slot][TIMEBASE_DIVIDEND] /
586 info->spd[channel][slot][TIMEBASE_DIVISOR];
587 cycletime =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100588 MAX(cycletime,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100589 timebase *
590 info->spd[channel][slot][CYCLETIME]);
591 cas_latency_time =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100592 MAX(cas_latency_time,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100593 timebase *
594 info->
595 spd[channel][slot][CAS_LATENCY_TIME]);
596 }
Jacob Garber3c193822019-06-10 18:23:32 -0600597 if (cycletime > min_cycletime[0])
598 die("RAM init: Decoded SPD DRAM freq is slower than the controller minimum!");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100599 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
600 if (cycletime == min_cycletime[clock_speed_index])
601 break;
602 if (cycletime > min_cycletime[clock_speed_index]) {
603 clock_speed_index--;
604 cycletime = min_cycletime[clock_speed_index];
605 break;
606 }
607 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100608 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100609 cas_latency = 0;
610 while (supported_cas_latencies) {
611 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
612 if (cas_latency <= min_cas_latency)
613 break;
614 supported_cas_latencies &=
615 ~(1 << find_highest_bit_set(supported_cas_latencies));
616 }
617
618 if (cas_latency != min_cas_latency && clock_speed_index)
619 clock_speed_index--;
620
621 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
622 die("Couldn't configure DRAM");
623 info->clock_speed_index = clock_speed_index;
624 info->cas_latency = cas_latency;
625}
626
627static void program_base_timings(struct raminfo *info)
628{
Martin Roth468d02c2019-10-23 21:44:42 -0600629 unsigned int channel;
630 unsigned int slot, rank, lane;
631 unsigned int extended_silicon_revision;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100632 int i;
633
634 extended_silicon_revision = info->silicon_revision;
635 if (info->silicon_revision == 0)
636 for (channel = 0; channel < NUM_CHANNELS; channel++)
637 for (slot = 0; slot < NUM_SLOTS; slot++)
638 if ((info->
639 spd[channel][slot][MODULE_TYPE] & 0xF) ==
640 3)
641 extended_silicon_revision = 4;
642
643 for (channel = 0; channel < NUM_CHANNELS; channel++) {
644 for (slot = 0; slot < NUM_SLOTS; slot++)
645 for (rank = 0; rank < NUM_SLOTS; rank++) {
646 int card_timing_2;
647 if (!info->populated_ranks[channel][slot][rank])
648 continue;
649
650 for (lane = 0; lane < 9; lane++) {
651 int tm_reg;
652 int card_timing;
653
654 card_timing = 0;
655 if ((info->
656 spd[channel][slot][MODULE_TYPE] &
657 0xF) == 3) {
658 int reference_card;
659 reference_card =
660 info->
661 spd[channel][slot]
662 [REFERENCE_RAW_CARD_USED] &
663 0x1f;
664 if (reference_card == 3)
665 card_timing =
666 u16_ffd1188[0][lane]
667 [info->
668 clock_speed_index];
669 if (reference_card == 5)
670 card_timing =
671 u16_ffd1188[1][lane]
672 [info->
673 clock_speed_index];
674 }
675
676 info->training.
677 lane_timings[0][channel][slot][rank]
678 [lane] =
679 u8_FFFD1218[info->
680 clock_speed_index];
681 info->training.
682 lane_timings[1][channel][slot][rank]
683 [lane] = 256;
684
685 for (tm_reg = 2; tm_reg < 4; tm_reg++)
686 info->training.
687 lane_timings[tm_reg]
688 [channel][slot][rank][lane]
689 =
690 u8_FFFD1240[channel]
691 [extended_silicon_revision]
692 [lane][2 * slot +
693 rank][info->
694 clock_speed_index]
695 + info->max4048[channel]
696 +
697 u8_FFFD0C78[channel]
698 [extended_silicon_revision]
699 [info->
700 mode4030[channel]][slot]
701 [rank][info->
702 clock_speed_index]
703 + card_timing;
704 for (tm_reg = 0; tm_reg < 4; tm_reg++)
705 write_500(info, channel,
706 info->training.
707 lane_timings[tm_reg]
708 [channel][slot][rank]
709 [lane],
710 get_timing_register_addr
711 (lane, tm_reg, slot,
712 rank), 9, 0);
713 }
714
715 card_timing_2 = 0;
716 if (!(extended_silicon_revision != 4
717 || (info->
718 populated_ranks_mask[channel] & 5) ==
719 5)) {
720 if ((info->
721 spd[channel][slot]
722 [REFERENCE_RAW_CARD_USED] & 0x1F)
723 == 3)
724 card_timing_2 =
725 u16_FFFE0EB8[0][info->
726 clock_speed_index];
727 if ((info->
728 spd[channel][slot]
729 [REFERENCE_RAW_CARD_USED] & 0x1F)
730 == 5)
731 card_timing_2 =
732 u16_FFFE0EB8[1][info->
733 clock_speed_index];
734 }
735
736 for (i = 0; i < 3; i++)
737 write_500(info, channel,
738 (card_timing_2 +
739 info->max4048[channel]
740 +
741 u8_FFFD0EF8[channel]
742 [extended_silicon_revision]
743 [info->
744 mode4030[channel]][info->
745 clock_speed_index]),
746 u16_fffd0c50[i][slot][rank],
747 8, 1);
748 write_500(info, channel,
749 (info->max4048[channel] +
750 u8_FFFD0C78[channel]
751 [extended_silicon_revision][info->
752 mode4030
753 [channel]]
754 [slot][rank][info->
755 clock_speed_index]),
756 u16_fffd0c70[slot][rank], 7, 1);
757 }
758 if (!info->populated_ranks_mask[channel])
759 continue;
760 for (i = 0; i < 3; i++)
761 write_500(info, channel,
762 (info->max4048[channel] +
763 info->avg4044[channel]
764 +
765 u8_FFFD17E0[channel]
766 [extended_silicon_revision][info->
767 mode4030
768 [channel]][info->
769 clock_speed_index]),
770 u16_fffd0c68[i], 8, 1);
771 }
772}
773
774static unsigned int fsbcycle_ps(struct raminfo *info)
775{
776 return 900000 / info->fsb_frequency;
777}
778
779/* The time of DDR transfer in ps. */
780static unsigned int halfcycle_ps(struct raminfo *info)
781{
782 return 3750 / (info->clock_speed_index + 3);
783}
784
785/* The time of clock cycle in ps. */
786static unsigned int cycle_ps(struct raminfo *info)
787{
788 return 2 * halfcycle_ps(info);
789}
790
791/* Frequency in 1.(1)=10/9 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600792static unsigned int frequency_11(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100793{
794 return (info->clock_speed_index + 3) * 120;
795}
796
797/* Frequency in 0.1 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600798static unsigned int frequency_01(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100799{
800 return 100 * frequency_11(info) / 9;
801}
802
Martin Roth468d02c2019-10-23 21:44:42 -0600803static unsigned int ps_to_halfcycles(struct raminfo *info, unsigned int ps)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100804{
805 return (frequency_11(info) * 2) * ps / 900000;
806}
807
Martin Roth468d02c2019-10-23 21:44:42 -0600808static unsigned int ns_to_cycles(struct raminfo *info, unsigned int ns)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100809{
810 return (frequency_11(info)) * ns / 900;
811}
812
813static void compute_derived_timings(struct raminfo *info)
814{
Martin Roth468d02c2019-10-23 21:44:42 -0600815 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100816 int extended_silicon_revision;
817 int some_delay_1_ps;
818 int some_delay_2_ps;
819 int some_delay_2_halfcycles_ceil;
820 int some_delay_2_halfcycles_floor;
821 int some_delay_3_ps;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100822 int some_delay_3_ps_rounded;
823 int some_delay_1_cycle_ceil;
824 int some_delay_1_cycle_floor;
825
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100826 some_delay_3_ps_rounded = 0;
827 extended_silicon_revision = info->silicon_revision;
828 if (!info->silicon_revision)
829 for (channel = 0; channel < NUM_CHANNELS; channel++)
830 for (slot = 0; slot < NUM_SLOTS; slot++)
831 if ((info->
832 spd[channel][slot][MODULE_TYPE] & 0xF) ==
833 3)
834 extended_silicon_revision = 4;
835 if (info->board_lane_delay[7] < 5)
836 info->board_lane_delay[7] = 5;
837 info->revision_flag_1 = 2;
838 if (info->silicon_revision == 2 || info->silicon_revision == 3)
839 info->revision_flag_1 = 0;
840 if (info->revision < 16)
841 info->revision_flag_1 = 0;
842
843 if (info->revision < 8)
844 info->revision_flag_1 = 0;
845 if (info->revision >= 8 && (info->silicon_revision == 0
846 || info->silicon_revision == 1))
847 some_delay_2_ps = 735;
848 else
849 some_delay_2_ps = 750;
850
851 if (info->revision >= 0x10 && (info->silicon_revision == 0
852 || info->silicon_revision == 1))
853 some_delay_1_ps = 3929;
854 else
855 some_delay_1_ps = 3490;
856
857 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
858 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
859 if (some_delay_1_ps % cycle_ps(info))
860 some_delay_1_cycle_ceil++;
861 else
862 some_delay_1_cycle_floor--;
863 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
864 if (info->revision_flag_1)
865 some_delay_2_ps = halfcycle_ps(info) >> 6;
866 some_delay_2_ps +=
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100867 MAX(some_delay_1_ps - 30,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100868 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
869 375;
870 some_delay_3_ps =
871 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
872 if (info->revision_flag_1) {
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200873 if (some_delay_3_ps >= 150) {
874 const int some_delay_3_halfcycles =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100875 (some_delay_3_ps << 6) / halfcycle_ps(info);
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200876 some_delay_3_ps_rounded =
877 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
878 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100879 }
880 some_delay_2_halfcycles_ceil =
881 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
882 2 * (some_delay_1_cycle_ceil - 1);
883 if (info->revision_flag_1 && some_delay_3_ps < 150)
884 some_delay_2_halfcycles_ceil++;
885 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
886 if (info->revision < 0x10)
887 some_delay_2_halfcycles_floor =
888 some_delay_2_halfcycles_ceil - 1;
889 if (!info->revision_flag_1)
890 some_delay_2_halfcycles_floor++;
891 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
892 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
893 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
894 || (info->populated_ranks[1][0][0]
895 && info->populated_ranks[1][1][0]))
896 info->max_slots_used_in_channel = 2;
897 else
898 info->max_slots_used_in_channel = 1;
899 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200900 MCHBAR32(0x244 + (channel << 10)) =
901 ((info->revision < 8) ? 1 : 0x200) |
902 ((2 - info->max_slots_used_in_channel) << 17) |
903 (channel << 21) |
904 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100905 if (info->max_slots_used_in_channel == 1) {
906 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
907 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
908 } else {
909 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 */
910 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
911 || (count_ranks_in_channel(info, 1) ==
912 2)) ? 2 : 3;
913 }
914 for (channel = 0; channel < NUM_CHANNELS; channel++) {
915 int max_of_unk;
916 int min_of_unk_2;
917
918 int i, count;
919 int sum;
920
921 if (!info->populated_ranks_mask[channel])
922 continue;
923
924 max_of_unk = 0;
925 min_of_unk_2 = 32767;
926
927 sum = 0;
928 count = 0;
929 for (i = 0; i < 3; i++) {
930 int unk1;
931 if (info->revision < 8)
932 unk1 =
933 u8_FFFD1891[0][channel][info->
934 clock_speed_index]
935 [i];
936 else if (!
937 (info->revision >= 0x10
938 || info->revision_flag_1))
939 unk1 =
940 u8_FFFD1891[1][channel][info->
941 clock_speed_index]
942 [i];
943 else
944 unk1 = 0;
945 for (slot = 0; slot < NUM_SLOTS; slot++)
946 for (rank = 0; rank < NUM_RANKS; rank++) {
947 int a = 0;
948 int b = 0;
949
950 if (!info->
951 populated_ranks[channel][slot]
952 [rank])
953 continue;
954 if (extended_silicon_revision == 4
955 && (info->
956 populated_ranks_mask[channel] &
957 5) != 5) {
958 if ((info->
959 spd[channel][slot]
960 [REFERENCE_RAW_CARD_USED] &
961 0x1F) == 3) {
962 a = u16_ffd1178[0]
963 [info->
964 clock_speed_index];
965 b = u16_fe0eb8[0][info->
966 clock_speed_index];
967 } else
968 if ((info->
969 spd[channel][slot]
970 [REFERENCE_RAW_CARD_USED]
971 & 0x1F) == 5) {
972 a = u16_ffd1178[1]
973 [info->
974 clock_speed_index];
975 b = u16_fe0eb8[1][info->
976 clock_speed_index];
977 }
978 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100979 min_of_unk_2 = MIN(min_of_unk_2, a);
980 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100981 if (rank == 0) {
982 sum += a;
983 count++;
984 }
985 {
986 int t;
987 t = b +
988 u8_FFFD0EF8[channel]
989 [extended_silicon_revision]
990 [info->
991 mode4030[channel]][info->
992 clock_speed_index];
993 if (unk1 >= t)
994 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100995 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100996 unk1 - t);
997 }
998 }
999 {
1000 int t =
1001 u8_FFFD17E0[channel]
1002 [extended_silicon_revision][info->
1003 mode4030
1004 [channel]]
1005 [info->clock_speed_index] + min_of_unk_2;
1006 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001007 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001008 }
1009 }
1010
Jacob Garber64fb4a32019-06-10 17:29:18 -06001011 if (count == 0)
1012 die("No memory ranks found for channel %u\n", channel);
1013
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001014 info->avg4044[channel] = sum / count;
1015 info->max4048[channel] = max_of_unk;
1016 }
1017}
1018
1019static void jedec_read(struct raminfo *info,
1020 int channel, int slot, int rank,
1021 int total_rank, u8 addr3, unsigned int value)
1022{
1023 /* Handle mirrored mapping. */
1024 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001025 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1026 ((addr3 >> 1) & 0x10);
1027 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1028 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001029
1030 /* Handle mirrored mapping. */
1031 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1032 value =
1033 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1034 << 1);
1035
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001036 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001037
Felix Held04be2dd2018-07-29 04:53:22 +02001038 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1039 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001040
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001041 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001042}
1043
1044enum {
1045 MR1_RZQ12 = 512,
1046 MR1_RZQ2 = 64,
1047 MR1_RZQ4 = 4,
1048 MR1_ODS34OHM = 2
1049};
1050
1051enum {
1052 MR0_BT_INTERLEAVED = 8,
1053 MR0_DLL_RESET_ON = 256
1054};
1055
1056enum {
1057 MR2_RTT_WR_DISABLED = 0,
1058 MR2_RZQ2 = 1 << 10
1059};
1060
1061static void jedec_init(struct raminfo *info)
1062{
1063 int write_recovery;
1064 int channel, slot, rank;
1065 int total_rank;
1066 int dll_on;
1067 int self_refresh_temperature;
1068 int auto_self_refresh;
1069
1070 auto_self_refresh = 1;
1071 self_refresh_temperature = 1;
1072 if (info->board_lane_delay[3] <= 10) {
1073 if (info->board_lane_delay[3] <= 8)
1074 write_recovery = info->board_lane_delay[3] - 4;
1075 else
1076 write_recovery = 5;
1077 } else {
1078 write_recovery = 6;
1079 }
1080 FOR_POPULATED_RANKS {
1081 auto_self_refresh &=
1082 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1083 self_refresh_temperature &=
1084 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1085 }
1086 if (auto_self_refresh == 1)
1087 self_refresh_temperature = 0;
1088
1089 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1090 || (info->populated_ranks[0][0][0]
1091 && info->populated_ranks[0][1][0])
1092 || (info->populated_ranks[1][0][0]
1093 && info->populated_ranks[1][1][0]));
1094
1095 total_rank = 0;
1096
1097 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1098 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1099 int rzq_reg58e;
1100
1101 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1102 rzq_reg58e = 64;
1103 rtt = MR1_RZQ2;
1104 if (info->clock_speed_index != 0) {
1105 rzq_reg58e = 4;
1106 if (info->populated_ranks_mask[channel] == 3)
1107 rtt = MR1_RZQ4;
1108 }
1109 } else {
1110 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1111 rtt = MR1_RZQ12;
1112 rzq_reg58e = 64;
1113 rtt_wr = MR2_RZQ2;
1114 } else {
1115 rzq_reg58e = 4;
1116 rtt = MR1_RZQ4;
1117 }
1118 }
1119
Felix Held04be2dd2018-07-29 04:53:22 +02001120 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1121 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1122 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1123 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1124 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001125
1126 for (slot = 0; slot < NUM_SLOTS; slot++)
1127 for (rank = 0; rank < NUM_RANKS; rank++)
1128 if (info->populated_ranks[channel][slot][rank]) {
1129 jedec_read(info, channel, slot, rank,
1130 total_rank, 0x28,
1131 rtt_wr | (info->
1132 clock_speed_index
1133 << 3)
1134 | (auto_self_refresh << 6) |
1135 (self_refresh_temperature <<
1136 7));
1137 jedec_read(info, channel, slot, rank,
1138 total_rank, 0x38, 0);
1139 jedec_read(info, channel, slot, rank,
1140 total_rank, 0x18,
1141 rtt | MR1_ODS34OHM);
1142 jedec_read(info, channel, slot, rank,
1143 total_rank, 6,
1144 (dll_on << 12) |
1145 (write_recovery << 9)
1146 | ((info->cas_latency - 4) <<
1147 4) | MR0_BT_INTERLEAVED |
1148 MR0_DLL_RESET_ON);
1149 total_rank++;
1150 }
1151 }
1152}
1153
1154static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1155{
Martin Roth468d02c2019-10-23 21:44:42 -06001156 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001157 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1158 unsigned int channel_0_non_interleaved;
1159
1160 FOR_ALL_RANKS {
1161 if (info->populated_ranks[channel][slot][rank]) {
1162 total_mb[channel] +=
1163 pre_jedec ? 256 : (256 << info->
1164 density[channel][slot] >> info->
1165 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001166 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1167 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1168 (info->is_x16_module[channel][slot] |
1169 ((info->density[channel][slot] + 1) << 1))) |
1170 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001171 }
Felix Held04be2dd2018-07-29 04:53:22 +02001172 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1173 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001174 }
1175
1176 info->total_memory_mb = total_mb[0] + total_mb[1];
1177
1178 info->interleaved_part_mb =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001179 pre_jedec ? 0 : 2 * MIN(total_mb[0], total_mb[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001180 info->non_interleaved_part_mb =
1181 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1182 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001183 MCHBAR32(0x100) = channel_0_non_interleaved |
1184 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001185 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001186 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001187}
1188
1189static void program_board_delay(struct raminfo *info)
1190{
1191 int cas_latency_shift;
1192 int some_delay_ns;
1193 int some_delay_3_half_cycles;
1194
Martin Roth468d02c2019-10-23 21:44:42 -06001195 unsigned int channel, i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001196 int high_multiplier;
1197 int lane_3_delay;
1198 int cas_latency_derived;
1199
1200 high_multiplier = 0;
1201 some_delay_ns = 200;
1202 some_delay_3_half_cycles = 4;
1203 cas_latency_shift = info->silicon_revision == 0
1204 || info->silicon_revision == 1 ? 1 : 0;
1205 if (info->revision < 8) {
1206 some_delay_ns = 600;
1207 cas_latency_shift = 0;
1208 }
1209 {
1210 int speed_bit;
1211 speed_bit =
1212 ((info->clock_speed_index > 1
1213 || (info->silicon_revision != 2
1214 && info->silicon_revision != 3))) ^ (info->revision >=
1215 0x10);
1216 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1217 3, 1);
1218 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1219 3, 1);
1220 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1221 && (info->silicon_revision == 2
1222 || info->silicon_revision == 3))
1223 rmw_1d0(0x116, 5, 2, 4, 1);
1224 }
Felix Held04be2dd2018-07-29 04:53:22 +02001225 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1226 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001227
Felix Held04be2dd2018-07-29 04:53:22 +02001228 MCHBAR8(0x124) = info->board_lane_delay[4] +
1229 ((frequency_01(info) + 999) / 1000);
1230 MCHBAR16(0x125) = 0x1360;
1231 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001232 if (info->fsb_frequency < frequency_11(info) / 2) {
Martin Roth468d02c2019-10-23 21:44:42 -06001233 unsigned int some_delay_2_half_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001234 high_multiplier = 1;
1235 some_delay_2_half_cycles = ps_to_halfcycles(info,
1236 ((3 *
1237 fsbcycle_ps(info))
1238 >> 1) +
1239 (halfcycle_ps(info)
1240 *
1241 reg178_min[info->
1242 clock_speed_index]
1243 >> 6)
1244 +
1245 4 *
1246 halfcycle_ps(info)
1247 + 2230);
1248 some_delay_3_half_cycles =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001249 MIN((some_delay_2_half_cycles +
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001250 (frequency_11(info) * 2) * (28 -
1251 some_delay_2_half_cycles) /
1252 (frequency_11(info) * 2 -
1253 4 * (info->fsb_frequency))) >> 3, 7);
1254 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001255 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001256 some_delay_3_half_cycles = 3;
1257 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001258 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1259 MCHBAR32(0x224 + (channel << 10)) =
1260 (info->max_slots_used_in_channel - 1) |
1261 ((info->cas_latency - 5 - info->clock_speed_index)
1262 << 21) | ((info->max_slots_used_in_channel +
1263 info->cas_latency - cas_latency_shift - 4) << 16) |
1264 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1265 ((info->cas_latency - info->clock_speed_index +
1266 info->max_slots_used_in_channel - 6) << 8);
1267 MCHBAR32(0x228 + (channel << 10)) =
1268 info->max_slots_used_in_channel;
1269 MCHBAR8(0x239 + (channel << 10)) = 32;
1270 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1271 (some_delay_3_half_cycles << 25) | 0x840000;
1272 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1273 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1274 MCHBAR32(0x24c + (channel << 10)) =
1275 ((!!info->clock_speed_index) << 17) |
1276 (((2 + info->clock_speed_index -
1277 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001278
Felix Held04be2dd2018-07-29 04:53:22 +02001279 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1280 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1281 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001282
1283 write_500(info, channel,
1284 ((!info->populated_ranks[channel][1][1])
1285 | (!info->populated_ranks[channel][1][0] << 1)
1286 | (!info->populated_ranks[channel][0][1] << 2)
1287 | (!info->populated_ranks[channel][0][0] << 3)),
1288 0x4c9, 4, 1);
1289 }
1290
Felix Held22ca8cb2018-07-29 05:09:44 +02001291 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001292 {
1293 u8 freq_divisor = 2;
1294 if (info->fsb_frequency == frequency_11(info))
1295 freq_divisor = 3;
1296 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1297 freq_divisor = 1;
1298 else
1299 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001300 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001301 }
1302
1303 if (info->board_lane_delay[3] <= 10) {
1304 if (info->board_lane_delay[3] <= 8)
1305 lane_3_delay = info->board_lane_delay[3];
1306 else
1307 lane_3_delay = 10;
1308 } else {
1309 lane_3_delay = 12;
1310 }
1311 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1312 if (info->clock_speed_index > 1)
1313 cas_latency_derived++;
1314 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001315 MCHBAR32(0x240 + (channel << 10)) =
1316 ((info->clock_speed_index == 0) * 0x11000) |
1317 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1318 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001319 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1320 0x609, 6, 1);
1321 write_500(info, channel,
1322 info->clock_speed_index + 2 * info->cas_latency - 7,
1323 0x601, 6, 1);
1324
Felix Held04be2dd2018-07-29 04:53:22 +02001325 MCHBAR32(0x250 + (channel << 10)) =
1326 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1327 (info->board_lane_delay[7] << 2) |
1328 (info->board_lane_delay[4] << 16) |
1329 (info->board_lane_delay[1] << 25) |
1330 (info->board_lane_delay[1] << 29) | 1;
1331 MCHBAR32(0x254 + (channel << 10)) =
1332 (info->board_lane_delay[1] >> 3) |
1333 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1334 0x80 | (info->board_lane_delay[6] << 1) |
1335 (info->board_lane_delay[2] << 28) |
1336 (cas_latency_derived << 16) | 0x4700000;
1337 MCHBAR32(0x258 + (channel << 10)) =
1338 ((info->board_lane_delay[5] + info->clock_speed_index +
1339 9) << 12) | ((info->clock_speed_index -
1340 info->cas_latency + 12) << 8) |
1341 (info->board_lane_delay[2] << 17) |
1342 (info->board_lane_delay[4] << 24) | 0x47;
1343 MCHBAR32(0x25c + (channel << 10)) =
1344 (info->board_lane_delay[1] << 1) |
1345 (info->board_lane_delay[0] << 8) | 0x1da50000;
1346 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1347 MCHBAR8(0x5f8 + (channel << 10)) =
1348 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001349 }
1350
1351 program_modules_memory_map(info, 1);
1352
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001353 MCHBAR16(0x610) = (MIN(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
Felix Held04be2dd2018-07-29 04:53:22 +02001354 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1355 MCHBAR16_OR(0x612, 0x100);
1356 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001357 for (i = 0; i < 8; i++) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001358 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0x80 + 4 * i,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001359 (info->total_memory_mb - 64) | !i | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001360 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0xc0 + 4 * i, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001361 }
1362}
1363
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001364#define DEFAULT_PCI_MMIO_SIZE 2048
1365#define HOST_BRIDGE PCI_DEVFN(0, 0)
1366
1367static unsigned int get_mmio_size(void)
1368{
1369 const struct device *dev;
1370 const struct northbridge_intel_nehalem_config *cfg = NULL;
1371
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001372 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001373 if (dev)
1374 cfg = dev->chip_info;
1375
1376 /* If this is zero, it just means devicetree.cb didn't set it */
1377 if (!cfg || cfg->pci_mmio_size == 0)
1378 return DEFAULT_PCI_MMIO_SIZE;
1379 else
1380 return cfg->pci_mmio_size;
1381}
1382
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001383#define BETTER_MEMORY_MAP 0
1384
1385static void program_total_memory_map(struct raminfo *info)
1386{
1387 unsigned int TOM, TOLUD, TOUUD;
1388 unsigned int quickpath_reserved;
1389 unsigned int REMAPbase;
1390 unsigned int uma_base_igd;
1391 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001392 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001393 int memory_remap;
1394 unsigned int memory_map[8];
1395 int i;
1396 unsigned int current_limit;
1397 unsigned int tseg_base;
1398 int uma_size_igd = 0, uma_size_gtt = 0;
1399
1400 memset(memory_map, 0, sizeof(memory_map));
1401
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001402 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001403 u16 t = pci_read_config16(NORTHBRIDGE, D0F0_GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001404 gav(t);
1405 const int uma_sizes_gtt[16] =
1406 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1407 /* Igd memory */
1408 const int uma_sizes_igd[16] = {
1409 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1410 256, 512
1411 };
1412
1413 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1414 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1415 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001416
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001417 mmio_size = get_mmio_size();
1418
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001419 TOM = info->total_memory_mb;
1420 if (TOM == 4096)
1421 TOM = 4032;
1422 TOUUD = ALIGN_DOWN(TOM - info->memory_reserved_for_heci_mb, 64);
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001423 TOLUD = ALIGN_DOWN(MIN(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
Elyes HAOUASa342f392018-10-17 10:56:26 +02001424 , TOUUD), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001425 memory_remap = 0;
1426 if (TOUUD - TOLUD > 64) {
1427 memory_remap = 1;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001428 REMAPbase = MAX(4096, TOUUD);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001429 TOUUD = TOUUD - TOLUD + 4096;
1430 }
1431 if (TOUUD > 4096)
1432 memory_map[2] = TOUUD | 1;
1433 quickpath_reserved = 0;
1434
Jacob Garber975a7e32019-06-10 16:32:47 -06001435 u32 t = pci_read_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001436
Jacob Garber975a7e32019-06-10 16:32:47 -06001437 gav(t);
1438
1439 if (t & 0x800) {
1440 u32 shift = t >> 20;
1441 if (shift == 0)
1442 die("Quickpath value is 0\n");
1443 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001444 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001445
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001446 if (memory_remap)
1447 TOUUD -= quickpath_reserved;
1448
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001449 uma_base_igd = TOLUD - uma_size_igd;
1450 uma_base_gtt = uma_base_igd - uma_size_gtt;
1451 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1452 if (!memory_remap)
1453 tseg_base -= quickpath_reserved;
1454 tseg_base = ALIGN_DOWN(tseg_base, 8);
1455
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001456 pci_write_config16(NORTHBRIDGE, D0F0_TOLUD, TOLUD << 4);
1457 pci_write_config16(NORTHBRIDGE, D0F0_TOM, TOM >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001458 if (memory_remap) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001459 pci_write_config16(NORTHBRIDGE, D0F0_REMAPBASE, REMAPbase >> 6);
1460 pci_write_config16(NORTHBRIDGE, D0F0_REMAPLIMIT, (TOUUD - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001461 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001462 pci_write_config16(NORTHBRIDGE, D0F0_TOUUD, TOUUD);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001463
1464 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001465 pci_write_config32(NORTHBRIDGE, D0F0_IGD_BASE, uma_base_igd << 20);
1466 pci_write_config32(NORTHBRIDGE, D0F0_GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001467 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001468 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001469
1470 current_limit = 0;
1471 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1472 memory_map[1] = 4096;
1473 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001474 current_limit = MAX(current_limit, memory_map[i] & ~1);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001475 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0x80,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001476 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1477 1, 64) | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001478 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0xc0, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001479 }
1480}
1481
1482static void collect_system_info(struct raminfo *info)
1483{
1484 u32 capid0[3];
1485 int i;
Martin Roth468d02c2019-10-23 21:44:42 -06001486 unsigned int channel;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001487
1488 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001489 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1490 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001491
1492 if (!info->heci_bar)
1493 gav(info->heci_bar =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001494 pci_read_config32(HECIDEV, HECIBAR) & 0xFFFFFFF8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001495 if (!info->memory_reserved_for_heci_mb) {
1496 /* Wait for ME to be ready */
1497 intel_early_me_init();
1498 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1499 }
1500
1501 for (i = 0; i < 3; i++)
1502 gav(capid0[i] =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001503 pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 | (i << 2)));
1504 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001505 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1506
1507 if ((capid0[1] >> 11) & 1)
1508 info->uma_enabled = 0;
1509 else
1510 gav(info->uma_enabled =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001511 pci_read_config8(NORTHBRIDGE, D0F0_DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001512 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1513 info->silicon_revision = 0;
1514
1515 if (capid0[2] & 2) {
1516 info->silicon_revision = 0;
1517 info->max_supported_clock_speed_index = 2;
1518 for (channel = 0; channel < NUM_CHANNELS; channel++)
1519 if (info->populated_ranks[channel][0][0]
1520 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1521 3) {
1522 info->silicon_revision = 2;
1523 info->max_supported_clock_speed_index = 1;
1524 }
1525 } else {
1526 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1527 case 1:
1528 case 2:
1529 info->silicon_revision = 3;
1530 break;
1531 case 3:
1532 info->silicon_revision = 0;
1533 break;
1534 case 0:
1535 info->silicon_revision = 2;
1536 break;
1537 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001538 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001539 case 0x40:
1540 info->silicon_revision = 0;
1541 break;
1542 case 0x48:
1543 info->silicon_revision = 1;
1544 break;
1545 }
1546 }
1547}
1548
1549static void write_training_data(struct raminfo *info)
1550{
1551 int tm, channel, slot, rank, lane;
1552 if (info->revision < 8)
1553 return;
1554
1555 for (tm = 0; tm < 4; tm++)
1556 for (channel = 0; channel < NUM_CHANNELS; channel++)
1557 for (slot = 0; slot < NUM_SLOTS; slot++)
1558 for (rank = 0; rank < NUM_RANKS; rank++)
1559 for (lane = 0; lane < 9; lane++)
1560 write_500(info, channel,
1561 info->
1562 cached_training->
1563 lane_timings[tm]
1564 [channel][slot][rank]
1565 [lane],
1566 get_timing_register_addr
1567 (lane, tm, slot,
1568 rank), 9, 0);
1569 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1570 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1571}
1572
1573static void dump_timings(struct raminfo *info)
1574{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001575 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001576 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001577 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001578 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001579 slot, rank);
1580 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001581 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001582 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001583 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001584 read_500(info, channel,
1585 get_timing_register_addr
1586 (lane, i, slot, rank),
1587 9),
1588 info->training.
1589 lane_timings[i][channel][slot][rank]
1590 [lane]);
1591 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001592 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001593 }
1594 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001595 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001596 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001597 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001598 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001599}
1600
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001601/* Read timings and other registers that need to be restored verbatim and
1602 put them to CBMEM.
1603 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001604static void save_timings(struct raminfo *info)
1605{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001606 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001607 int channel, slot, rank, lane, i;
1608
1609 train = info->training;
1610 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1611 for (i = 0; i < 4; i++)
1612 train.lane_timings[i][channel][slot][rank][lane] =
1613 read_500(info, channel,
1614 get_timing_register_addr(lane, i, slot,
1615 rank), 9);
1616 train.reg_178 = read_1d0(0x178, 7);
1617 train.reg_10b = read_1d0(0x10b, 6);
1618
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001619 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1620 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001621 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001622 train.reg274265[channel][0] = reg32 >> 16;
1623 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001624 train.reg274265[channel][2] =
1625 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001626 }
Felix Held04be2dd2018-07-29 04:53:22 +02001627 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1628 train.reg_6dc = MCHBAR32(0x6dc);
1629 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001630
Arthur Heymansb3282092019-04-14 17:53:28 +02001631 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1632 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001633
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001634 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001635 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1636 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001637}
1638
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001639static const struct ram_training *get_cached_training(void)
1640{
Arthur Heymansdc71e252018-01-29 10:14:48 +01001641 struct region_device rdev;
1642 if (mrc_cache_get_current(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1643 &rdev))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001644 return 0;
Arthur Heymansdc71e252018-01-29 10:14:48 +01001645 return (void *)rdev_mmap_full(&rdev);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001646}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001647
1648/* FIXME: add timeout. */
1649static void wait_heci_ready(void)
1650{
Felix Held04be2dd2018-07-29 04:53:22 +02001651 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1652 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001653 write32((DEFAULT_HECIBAR + 0x4),
1654 (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001655}
1656
1657/* FIXME: add timeout. */
1658static void wait_heci_cb_avail(int len)
1659{
1660 union {
1661 struct mei_csr csr;
1662 u32 raw;
1663 } csr;
1664
Felix Held22ca8cb2018-07-29 05:09:44 +02001665 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1666 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001667
1668 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001669 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001670 while (len >
1671 csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
Felix Held22ca8cb2018-07-29 05:09:44 +02001672 csr.csr.buffer_read_ptr))
1673 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001674}
1675
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001676static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001677{
1678 int len = (head->length + 3) / 4;
1679 int i;
1680
1681 wait_heci_cb_avail(len + 1);
1682
1683 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001684 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001685 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001686 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001687
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001688 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1689 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001690}
1691
1692static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001693send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001694{
1695 struct mei_header head;
1696 int maxlen;
1697
1698 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001699 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001700
1701 while (len) {
1702 int cur = len;
1703 if (cur > maxlen) {
1704 cur = maxlen;
1705 head.is_complete = 0;
1706 } else
1707 head.is_complete = 1;
1708 head.length = cur;
1709 head.reserved = 0;
1710 head.client_address = clientaddress;
1711 head.host_address = hostaddress;
1712 send_heci_packet(&head, (u32 *) msg);
1713 len -= cur;
1714 msg += cur;
1715 }
1716}
1717
1718/* FIXME: Add timeout. */
1719static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001720recv_heci_packet(struct raminfo *info, struct mei_header *head, u32 *packet,
1721 u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001722{
1723 union {
1724 struct mei_csr csr;
1725 u32 raw;
1726 } csr;
1727 int i = 0;
1728
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001729 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001730 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001731 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001732 }
Felix Held04be2dd2018-07-29 04:53:22 +02001733 while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr)
1734 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001735 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001736 if (!head->length) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001737 write32(DEFAULT_HECIBAR + 0x4,
1738 read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001739 *packet_size = 0;
1740 return 0;
1741 }
1742 if (head->length + 4 > 4 * csr.csr.buffer_depth
1743 || head->length > *packet_size) {
1744 *packet_size = 0;
1745 return -1;
1746 }
1747
1748 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001749 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Felix Held22ca8cb2018-07-29 05:09:44 +02001750 while (((head->length + 3) >> 2) >
1751 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr))
1752 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001753
1754 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001755 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001756 *packet_size = head->length;
1757 if (!csr.csr.ready)
1758 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001759 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001760 return 0;
1761}
1762
1763/* FIXME: Add timeout. */
1764static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001765recv_heci_message(struct raminfo *info, u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001766{
1767 struct mei_header head;
1768 int current_position;
1769
1770 current_position = 0;
1771 while (1) {
1772 u32 current_size;
1773 current_size = *message_size - current_position;
1774 if (recv_heci_packet
1775 (info, &head, message + (current_position >> 2),
1776 &current_size) == -1)
1777 break;
1778 if (!current_size)
1779 break;
1780 current_position += current_size;
1781 if (head.is_complete) {
1782 *message_size = current_position;
1783 return 0;
1784 }
1785
1786 if (current_position >= *message_size)
1787 break;
1788 }
1789 *message_size = 0;
1790 return -1;
1791}
1792
1793static void send_heci_uma_message(struct raminfo *info)
1794{
1795 struct uma_reply {
1796 u8 group_id;
1797 u8 command;
1798 u8 reserved;
1799 u8 result;
1800 u8 field2;
1801 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001802 } __packed reply;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001803 struct uma_message {
1804 u8 group_id;
1805 u8 cmd;
1806 u8 reserved;
1807 u8 result;
1808 u32 c2;
1809 u64 heci_uma_addr;
1810 u32 memory_reserved_for_heci_mb;
1811 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001812 } __packed msg = {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001813 0, MKHI_SET_UMA, 0, 0,
1814 0x82,
1815 info->heci_uma_addr, info->memory_reserved_for_heci_mb, 0};
1816 u32 reply_size;
1817
1818 send_heci_message((u8 *) & msg, sizeof(msg), 0, 7);
1819
1820 reply_size = sizeof(reply);
1821 if (recv_heci_message(info, (u32 *) & reply, &reply_size) == -1)
1822 return;
1823
1824 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1825 die("HECI init failed\n");
1826}
1827
1828static void setup_heci_uma(struct raminfo *info)
1829{
1830 u32 reg44;
1831
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001832 reg44 = pci_read_config32(HECIDEV, 0x44); // = 0x80010020
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001833 info->memory_reserved_for_heci_mb = 0;
1834 info->heci_uma_addr = 0;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001835 if (!((reg44 & 0x10000) && !(pci_read_config32(HECIDEV, 0x40) & 0x20)))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001836 return;
1837
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001838 info->heci_bar = pci_read_config32(HECIDEV, 0x10) & 0xFFFFFFF0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001839 info->memory_reserved_for_heci_mb = reg44 & 0x3f;
1840 info->heci_uma_addr =
1841 ((u64)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001842 ((((u64) pci_read_config16(NORTHBRIDGE, D0F0_TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001843 info->memory_reserved_for_heci_mb)) << 20;
1844
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001845 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001846 if (info->memory_reserved_for_heci_mb) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001847 write32(DEFAULT_DMIBAR + 0x14,
1848 read32(DEFAULT_DMIBAR + 0x14) & ~0x80);
1849 write32(DEFAULT_RCBA + 0x14,
1850 read32(DEFAULT_RCBA + 0x14) & ~0x80);
1851 write32(DEFAULT_DMIBAR + 0x20,
1852 read32(DEFAULT_DMIBAR + 0x20) & ~0x80);
1853 write32(DEFAULT_RCBA + 0x20,
1854 read32(DEFAULT_RCBA + 0x20) & ~0x80);
1855 write32(DEFAULT_DMIBAR + 0x2c,
1856 read32(DEFAULT_DMIBAR + 0x2c) & ~0x80);
1857 write32(DEFAULT_RCBA + 0x30,
1858 read32(DEFAULT_RCBA + 0x30) & ~0x80);
1859 write32(DEFAULT_DMIBAR + 0x38,
1860 read32(DEFAULT_DMIBAR + 0x38) & ~0x80);
1861 write32(DEFAULT_RCBA + 0x40,
1862 read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001863
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001864 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
1865 write32(DEFAULT_DMIBAR + 0x38, 0x87000080); // OK
Felix Held04be2dd2018-07-29 04:53:22 +02001866 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
1867 read16(DEFAULT_DMIBAR + 0x3e) & 2)
1868 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001869 }
1870
Felix Held04be2dd2018-07-29 04:53:22 +02001871 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001872
1873 send_heci_uma_message(info);
1874
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001875 pci_write_config32(HECIDEV, 0x10, 0x0);
1876 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001877
1878}
1879
1880static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1881{
1882 int ranks_in_channel;
1883 ranks_in_channel = info->populated_ranks[channel][0][0]
1884 + info->populated_ranks[channel][0][1]
1885 + info->populated_ranks[channel][1][0]
1886 + info->populated_ranks[channel][1][1];
1887
1888 /* empty channel */
1889 if (ranks_in_channel == 0)
1890 return 1;
1891
1892 if (ranks_in_channel != ranks)
1893 return 0;
1894 /* single slot */
1895 if (info->populated_ranks[channel][0][0] !=
1896 info->populated_ranks[channel][1][0])
1897 return 1;
1898 if (info->populated_ranks[channel][0][1] !=
1899 info->populated_ranks[channel][1][1])
1900 return 1;
1901 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1902 return 0;
1903 if (info->density[channel][0] != info->density[channel][1])
1904 return 0;
1905 return 1;
1906}
1907
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001908static void read_4090(struct raminfo *info)
1909{
1910 int i, channel, slot, rank, lane;
1911 for (i = 0; i < 2; i++)
1912 for (slot = 0; slot < NUM_SLOTS; slot++)
1913 for (rank = 0; rank < NUM_RANKS; rank++)
1914 for (lane = 0; lane < 9; lane++)
1915 info->training.
1916 lane_timings[0][i][slot][rank][lane]
1917 = 32;
1918
1919 for (i = 1; i < 4; i++)
1920 for (channel = 0; channel < NUM_CHANNELS; channel++)
1921 for (slot = 0; slot < NUM_SLOTS; slot++)
1922 for (rank = 0; rank < NUM_RANKS; rank++)
1923 for (lane = 0; lane < 9; lane++) {
1924 info->training.
1925 lane_timings[i][channel]
1926 [slot][rank][lane] =
1927 read_500(info, channel,
1928 get_timing_register_addr
1929 (lane, i, slot,
1930 rank), 9)
1931 + (i == 1) * 11; // !!!!
1932 }
1933
1934}
1935
1936static u32 get_etalon2(int flip, u32 addr)
1937{
1938 const u16 invmask[] = {
1939 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1940 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1941 };
1942 u32 ret;
1943 u32 comp4 = addr / 480;
1944 addr %= 480;
1945 u32 comp1 = addr & 0xf;
1946 u32 comp2 = (addr >> 4) & 1;
1947 u32 comp3 = addr >> 5;
1948
1949 if (comp4)
1950 ret = 0x1010101 << (comp4 - 1);
1951 else
1952 ret = 0;
1953 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1954 ret = ~ret;
1955
1956 return ret;
1957}
1958
1959static void disable_cache(void)
1960{
1961 msr_t msr = {.lo = 0, .hi = 0 };
1962
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001963 wrmsr(MTRR_PHYS_BASE(3), msr);
1964 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001965}
1966
1967static void enable_cache(unsigned int base, unsigned int size)
1968{
1969 msr_t msr;
1970 msr.lo = base | MTRR_TYPE_WRPROT;
1971 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001972 wrmsr(MTRR_PHYS_BASE(3), msr);
1973 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001974 & 0xffffffff);
1975 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001976 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001977}
1978
1979static void flush_cache(u32 start, u32 size)
1980{
1981 u32 end;
1982 u32 addr;
1983
1984 end = start + (ALIGN_DOWN(size + 4096, 4096));
1985 for (addr = start; addr < end; addr += 64)
1986 clflush(addr);
1987}
1988
1989static void clear_errors(void)
1990{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001991 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001992}
1993
1994static void write_testing(struct raminfo *info, int totalrank, int flip)
1995{
1996 int nwrites = 0;
1997 /* in 8-byte units. */
1998 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001999 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002000
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002001 base = (u8 *)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002002 for (offset = 0; offset < 9 * 480; offset += 2) {
2003 write32(base + offset * 8, get_etalon2(flip, offset));
2004 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
2005 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
2006 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
2007 nwrites += 4;
2008 if (nwrites >= 320) {
2009 clear_errors();
2010 nwrites = 0;
2011 }
2012 }
2013}
2014
2015static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
2016{
2017 u8 failmask = 0;
2018 int i;
2019 int comp1, comp2, comp3;
2020 u32 failxor[2] = { 0, 0 };
2021
2022 enable_cache((total_rank << 28), 1728 * 5 * 4);
2023
2024 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
2025 for (comp1 = 0; comp1 < 4; comp1++)
2026 for (comp2 = 0; comp2 < 60; comp2++) {
2027 u32 re[4];
2028 u32 curroffset =
2029 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
2030 read128((total_rank << 28) | (curroffset << 3),
2031 (u64 *) re);
2032 failxor[0] |=
2033 get_etalon2(flip, curroffset) ^ re[0];
2034 failxor[1] |=
2035 get_etalon2(flip, curroffset) ^ re[1];
2036 failxor[0] |=
2037 get_etalon2(flip, curroffset | 1) ^ re[2];
2038 failxor[1] |=
2039 get_etalon2(flip, curroffset | 1) ^ re[3];
2040 }
2041 for (i = 0; i < 8; i++)
2042 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2043 failmask |= 1 << i;
2044 }
2045 disable_cache();
2046 flush_cache((total_rank << 28), 1728 * 5 * 4);
2047 return failmask;
2048}
2049
2050const u32 seed1[0x18] = {
2051 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2052 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2053 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2054 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2055 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2056 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2057};
2058
2059static u32 get_seed2(int a, int b)
2060{
2061 const u32 seed2[5] = {
2062 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2063 0x5b6db6db,
2064 };
2065 u32 r;
2066 r = seed2[(a + (a >= 10)) / 5];
2067 return b ? ~r : r;
2068}
2069
2070static int make_shift(int comp2, int comp5, int x)
2071{
2072 const u8 seed3[32] = {
2073 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2074 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2075 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2076 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2077 };
2078
2079 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2080}
2081
2082static u32 get_etalon(int flip, u32 addr)
2083{
2084 u32 mask_byte = 0;
2085 int comp1 = (addr >> 1) & 1;
2086 int comp2 = (addr >> 3) & 0x1f;
2087 int comp3 = (addr >> 8) & 0xf;
2088 int comp4 = (addr >> 12) & 0xf;
2089 int comp5 = (addr >> 16) & 0x1f;
2090 u32 mask_bit = ~(0x10001 << comp3);
2091 u32 part1;
2092 u32 part2;
2093 int byte;
2094
2095 part2 =
2096 ((seed1[comp5] >>
2097 make_shift(comp2, comp5,
2098 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2099 part1 =
2100 ((seed1[comp5] >>
2101 make_shift(comp2, comp5,
2102 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2103
2104 for (byte = 0; byte < 4; byte++)
2105 if ((get_seed2(comp5, comp4) >>
2106 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2107 mask_byte |= 0xff << (8 * byte);
2108
2109 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2110 (comp3 + 16));
2111}
2112
2113static void
2114write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2115 char flip)
2116{
2117 int i;
2118 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002119 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2120 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002121}
2122
2123static u8
2124check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2125 char flip)
2126{
2127 u8 failmask = 0;
2128 u32 failxor[2];
2129 int i;
2130 int comp1, comp2, comp3;
2131
2132 failxor[0] = 0;
2133 failxor[1] = 0;
2134
2135 enable_cache(totalrank << 28, 134217728);
2136 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2137 for (comp1 = 0; comp1 < 16; comp1++)
2138 for (comp2 = 0; comp2 < 64; comp2++) {
2139 u32 addr =
2140 (totalrank << 28) | (region << 25) | (block
2141 << 16)
2142 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2143 2);
2144 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002145 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002146 }
2147 for (i = 0; i < 8; i++)
2148 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2149 failmask |= 1 << i;
2150 }
2151 disable_cache();
2152 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2153 return failmask;
2154}
2155
2156static int check_bounded(unsigned short *vals, u16 bound)
2157{
2158 int i;
2159
2160 for (i = 0; i < 8; i++)
2161 if (vals[i] < bound)
2162 return 0;
2163 return 1;
2164}
2165
2166enum state {
2167 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2168};
2169
2170static int validate_state(enum state *in)
2171{
2172 int i;
2173 for (i = 0; i < 8; i++)
2174 if (in[i] != COMPLETE)
2175 return 0;
2176 return 1;
2177}
2178
2179static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002180do_fsm(enum state *state, u16 *counter,
2181 u8 fail_mask, int margin, int uplimit,
2182 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002183{
2184 int lane;
2185
2186 for (lane = 0; lane < 8; lane++) {
2187 int is_fail = (fail_mask >> lane) & 1;
2188 switch (state[lane]) {
2189 case BEFORE_USABLE:
2190 if (!is_fail) {
2191 counter[lane] = 1;
2192 state[lane] = AT_USABLE;
2193 break;
2194 }
2195 counter[lane] = 0;
2196 state[lane] = BEFORE_USABLE;
2197 break;
2198 case AT_USABLE:
2199 if (!is_fail) {
2200 ++counter[lane];
2201 if (counter[lane] >= margin) {
2202 state[lane] = AT_MARGIN;
2203 res_low[lane] = val - margin + 1;
2204 break;
2205 }
2206 state[lane] = 1;
2207 break;
2208 }
2209 counter[lane] = 0;
2210 state[lane] = BEFORE_USABLE;
2211 break;
2212 case AT_MARGIN:
2213 if (is_fail) {
2214 state[lane] = COMPLETE;
2215 res_high[lane] = val - 1;
2216 } else {
2217 counter[lane]++;
2218 state[lane] = AT_MARGIN;
2219 if (val == uplimit) {
2220 state[lane] = COMPLETE;
2221 res_high[lane] = uplimit;
2222 }
2223 }
2224 break;
2225 case COMPLETE:
2226 break;
2227 }
2228 }
2229}
2230
2231static void
2232train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2233 u8 total_rank, u8 reg_178, int first_run, int niter,
2234 timing_bounds_t * timings)
2235{
2236 int lane;
2237 enum state state[8];
2238 u16 count[8];
2239 u8 lower_usable[8];
2240 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002241 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002242 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002243 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002244
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002245 for (i = 0; i < 8; i++)
2246 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002247
2248 if (!first_run) {
2249 int is_all_ok = 1;
2250 for (lane = 0; lane < 8; lane++)
2251 if (timings[reg_178][channel][slot][rank][lane].
2252 smallest ==
2253 timings[reg_178][channel][slot][rank][lane].
2254 largest) {
2255 timings[reg_178][channel][slot][rank][lane].
2256 smallest = 0;
2257 timings[reg_178][channel][slot][rank][lane].
2258 largest = 0;
2259 is_all_ok = 0;
2260 }
2261 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002262 for (i = 0; i < 8; i++)
2263 state[i] = COMPLETE;
2264 }
2265 }
2266
2267 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2268 u8 failmask = 0;
2269 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2270 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2271 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002272 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002273 do_fsm(state, count, failmask, 5, 47, lower_usable,
2274 upper_usable, reg1b3);
2275 }
2276
2277 if (reg1b3) {
2278 write_1d0(0, 0x1b3, 6, 1);
2279 write_1d0(0, 0x1a3, 6, 1);
2280 for (lane = 0; lane < 8; lane++) {
2281 if (state[lane] == COMPLETE) {
2282 timings[reg_178][channel][slot][rank][lane].
2283 smallest =
2284 lower_usable[lane] +
2285 (info->training.
2286 lane_timings[0][channel][slot][rank][lane]
2287 & 0x3F) - 32;
2288 timings[reg_178][channel][slot][rank][lane].
2289 largest =
2290 upper_usable[lane] +
2291 (info->training.
2292 lane_timings[0][channel][slot][rank][lane]
2293 & 0x3F) - 32;
2294 }
2295 }
2296 }
2297
2298 if (!first_run) {
2299 for (lane = 0; lane < 8; lane++)
2300 if (state[lane] == COMPLETE) {
2301 write_500(info, channel,
2302 timings[reg_178][channel][slot][rank]
2303 [lane].smallest,
2304 get_timing_register_addr(lane, 0,
2305 slot, rank),
2306 9, 1);
2307 write_500(info, channel,
2308 timings[reg_178][channel][slot][rank]
2309 [lane].smallest +
2310 info->training.
2311 lane_timings[1][channel][slot][rank]
2312 [lane]
2313 -
2314 info->training.
2315 lane_timings[0][channel][slot][rank]
2316 [lane], get_timing_register_addr(lane,
2317 1,
2318 slot,
2319 rank),
2320 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002321 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002322 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002323 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002324
2325 do {
2326 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002327 for (i = 0; i < niter; i++) {
2328 if (failmask == 0xFF)
2329 break;
2330 failmask |=
2331 check_testing_type2(info, total_rank, 2, i,
2332 0);
2333 failmask |=
2334 check_testing_type2(info, total_rank, 3, i,
2335 1);
2336 }
Felix Held04be2dd2018-07-29 04:53:22 +02002337 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002338 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002339 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002340 if ((1 << lane) & failmask) {
2341 if (timings[reg_178][channel]
2342 [slot][rank][lane].
2343 largest <=
2344 timings[reg_178][channel]
2345 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002346 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002347 [lane] = -1;
2348 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002349 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002350 [lane] = 0;
2351 timings[reg_178]
2352 [channel][slot]
2353 [rank][lane].
2354 smallest++;
2355 write_500(info, channel,
2356 timings
2357 [reg_178]
2358 [channel]
2359 [slot][rank]
2360 [lane].
2361 smallest,
2362 get_timing_register_addr
2363 (lane, 0,
2364 slot, rank),
2365 9, 1);
2366 write_500(info, channel,
2367 timings
2368 [reg_178]
2369 [channel]
2370 [slot][rank]
2371 [lane].
2372 smallest +
2373 info->
2374 training.
2375 lane_timings
2376 [1][channel]
2377 [slot][rank]
2378 [lane]
2379 -
2380 info->
2381 training.
2382 lane_timings
2383 [0][channel]
2384 [slot][rank]
2385 [lane],
2386 get_timing_register_addr
2387 (lane, 1,
2388 slot, rank),
2389 9, 1);
2390 }
2391 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002392 num_successfully_checked[lane]
2393 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002394 }
2395 }
Felix Held04be2dd2018-07-29 04:53:22 +02002396 while (!check_bounded(num_successfully_checked, 2))
2397 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002398
2399 for (lane = 0; lane < 8; lane++)
2400 if (state[lane] == COMPLETE) {
2401 write_500(info, channel,
2402 timings[reg_178][channel][slot][rank]
2403 [lane].largest,
2404 get_timing_register_addr(lane, 0,
2405 slot, rank),
2406 9, 1);
2407 write_500(info, channel,
2408 timings[reg_178][channel][slot][rank]
2409 [lane].largest +
2410 info->training.
2411 lane_timings[1][channel][slot][rank]
2412 [lane]
2413 -
2414 info->training.
2415 lane_timings[0][channel][slot][rank]
2416 [lane], get_timing_register_addr(lane,
2417 1,
2418 slot,
2419 rank),
2420 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002421 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002422 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002423 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002424
2425 do {
2426 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002427 for (i = 0; i < niter; i++) {
2428 if (failmask == 0xFF)
2429 break;
2430 failmask |=
2431 check_testing_type2(info, total_rank, 2, i,
2432 0);
2433 failmask |=
2434 check_testing_type2(info, total_rank, 3, i,
2435 1);
2436 }
2437
Felix Held04be2dd2018-07-29 04:53:22 +02002438 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002439 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002440 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002441 if ((1 << lane) & failmask) {
2442 if (timings[reg_178][channel]
2443 [slot][rank][lane].
2444 largest <=
2445 timings[reg_178][channel]
2446 [slot][rank][lane].
2447 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002448 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002449 [lane] = -1;
2450 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002451 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002452 [lane] = 0;
2453 timings[reg_178]
2454 [channel][slot]
2455 [rank][lane].
2456 largest--;
2457 write_500(info, channel,
2458 timings
2459 [reg_178]
2460 [channel]
2461 [slot][rank]
2462 [lane].
2463 largest,
2464 get_timing_register_addr
2465 (lane, 0,
2466 slot, rank),
2467 9, 1);
2468 write_500(info, channel,
2469 timings
2470 [reg_178]
2471 [channel]
2472 [slot][rank]
2473 [lane].
2474 largest +
2475 info->
2476 training.
2477 lane_timings
2478 [1][channel]
2479 [slot][rank]
2480 [lane]
2481 -
2482 info->
2483 training.
2484 lane_timings
2485 [0][channel]
2486 [slot][rank]
2487 [lane],
2488 get_timing_register_addr
2489 (lane, 1,
2490 slot, rank),
2491 9, 1);
2492 }
2493 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002494 num_successfully_checked[lane]
2495 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002496 }
2497 }
2498 }
Felix Held04be2dd2018-07-29 04:53:22 +02002499 while (!check_bounded(num_successfully_checked, 3))
2500 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002501
2502 for (lane = 0; lane < 8; lane++) {
2503 write_500(info, channel,
2504 info->training.
2505 lane_timings[0][channel][slot][rank][lane],
2506 get_timing_register_addr(lane, 0, slot, rank),
2507 9, 1);
2508 write_500(info, channel,
2509 info->training.
2510 lane_timings[1][channel][slot][rank][lane],
2511 get_timing_register_addr(lane, 1, slot, rank),
2512 9, 1);
2513 if (timings[reg_178][channel][slot][rank][lane].
2514 largest <=
2515 timings[reg_178][channel][slot][rank][lane].
2516 smallest) {
2517 timings[reg_178][channel][slot][rank][lane].
2518 largest = 0;
2519 timings[reg_178][channel][slot][rank][lane].
2520 smallest = 0;
2521 }
2522 }
2523 }
2524}
2525
2526static void set_10b(struct raminfo *info, u8 val)
2527{
2528 int channel;
2529 int slot, rank;
2530 int lane;
2531
2532 if (read_1d0(0x10b, 6) == val)
2533 return;
2534
2535 write_1d0(val, 0x10b, 6, 1);
2536
2537 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2538 u16 reg_500;
2539 reg_500 = read_500(info, channel,
2540 get_timing_register_addr(lane, 0, slot,
2541 rank), 9);
2542 if (val == 1) {
2543 if (lut16[info->clock_speed_index] <= reg_500)
2544 reg_500 -= lut16[info->clock_speed_index];
2545 else
2546 reg_500 = 0;
2547 } else {
2548 reg_500 += lut16[info->clock_speed_index];
2549 }
2550 write_500(info, channel, reg_500,
2551 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2552 }
2553}
2554
2555static void set_ecc(int onoff)
2556{
2557 int channel;
2558 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2559 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002560 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002561 if (onoff)
2562 t |= 1;
2563 else
2564 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002565 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002566 }
2567}
2568
2569static void set_178(u8 val)
2570{
2571 if (val >= 31)
2572 val = val - 31;
2573 else
2574 val = 63 - val;
2575
2576 write_1d0(2 * val, 0x178, 7, 1);
2577}
2578
2579static void
2580write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2581 int type)
2582{
2583 int lane;
2584
2585 for (lane = 0; lane < 8; lane++)
2586 write_500(info, channel,
2587 info->training.
2588 lane_timings[type][channel][slot][rank][lane],
2589 get_timing_register_addr(lane, type, slot, rank), 9,
2590 0);
2591}
2592
2593static void
2594try_timing_offsets(struct raminfo *info, int channel,
2595 int slot, int rank, int totalrank)
2596{
2597 u16 count[8];
2598 enum state state[8];
2599 u8 lower_usable[8], upper_usable[8];
2600 int lane;
2601 int i;
2602 int flip = 1;
2603 int timing_offset;
2604
2605 for (i = 0; i < 8; i++)
2606 state[i] = BEFORE_USABLE;
2607
2608 memset(count, 0, sizeof(count));
2609
2610 for (lane = 0; lane < 8; lane++)
2611 write_500(info, channel,
2612 info->training.
2613 lane_timings[2][channel][slot][rank][lane] + 32,
2614 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2615
2616 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2617 timing_offset++) {
2618 u8 failmask;
2619 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2620 failmask = 0;
2621 for (i = 0; i < 2 && failmask != 0xff; i++) {
2622 flip = !flip;
2623 write_testing(info, totalrank, flip);
2624 failmask |= check_testing(info, totalrank, flip);
2625 }
2626 do_fsm(state, count, failmask, 10, 63, lower_usable,
2627 upper_usable, timing_offset);
2628 }
2629 write_1d0(0, 0x1bb, 6, 1);
2630 dump_timings(info);
2631 if (!validate_state(state))
2632 die("Couldn't discover DRAM timings (1)\n");
2633
2634 for (lane = 0; lane < 8; lane++) {
2635 u8 bias = 0;
2636
2637 if (info->silicon_revision) {
2638 int usable_length;
2639
2640 usable_length = upper_usable[lane] - lower_usable[lane];
2641 if (usable_length >= 20) {
2642 bias = usable_length / 2 - 10;
2643 if (bias >= 2)
2644 bias = 2;
2645 }
2646 }
2647 write_500(info, channel,
2648 info->training.
2649 lane_timings[2][channel][slot][rank][lane] +
2650 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2651 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2652 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2653 info->training.lane_timings[2][channel][slot][rank][lane] +
2654 lower_usable[lane];
2655 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2656 info->training.lane_timings[2][channel][slot][rank][lane] +
2657 upper_usable[lane];
2658 info->training.timing2_offset[channel][slot][rank][lane] =
2659 info->training.lane_timings[2][channel][slot][rank][lane];
2660 }
2661}
2662
2663static u8
2664choose_training(struct raminfo *info, int channel, int slot, int rank,
2665 int lane, timing_bounds_t * timings, u8 center_178)
2666{
2667 u16 central_weight;
2668 u16 side_weight;
2669 unsigned int sum = 0, count = 0;
2670 u8 span;
2671 u8 lower_margin, upper_margin;
2672 u8 reg_178;
2673 u8 result;
2674
2675 span = 12;
2676 central_weight = 20;
2677 side_weight = 20;
2678 if (info->silicon_revision == 1 && channel == 1) {
2679 central_weight = 5;
2680 side_weight = 20;
2681 if ((info->
2682 populated_ranks_mask[1] ^ (info->
2683 populated_ranks_mask[1] >> 2)) &
2684 1)
2685 span = 18;
2686 }
2687 if ((info->populated_ranks_mask[0] & 5) == 5) {
2688 central_weight = 20;
2689 side_weight = 20;
2690 }
2691 if (info->clock_speed_index >= 2
2692 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2693 if (info->silicon_revision == 1) {
2694 switch (channel) {
2695 case 0:
2696 if (lane == 1) {
2697 central_weight = 10;
2698 side_weight = 20;
2699 }
2700 break;
2701 case 1:
2702 if (lane == 6) {
2703 side_weight = 5;
2704 central_weight = 20;
2705 }
2706 break;
2707 }
2708 }
2709 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2710 side_weight = 5;
2711 central_weight = 20;
2712 }
2713 }
2714 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2715 reg_178 += span) {
2716 u8 smallest;
2717 u8 largest;
2718 largest = timings[reg_178][channel][slot][rank][lane].largest;
2719 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2720 if (largest - smallest + 1 >= 5) {
2721 unsigned int weight;
2722 if (reg_178 == center_178)
2723 weight = central_weight;
2724 else
2725 weight = side_weight;
2726 sum += weight * (largest + smallest);
2727 count += weight;
2728 }
2729 }
2730 dump_timings(info);
2731 if (count == 0)
2732 die("Couldn't discover DRAM timings (2)\n");
2733 result = sum / (2 * count);
2734 lower_margin =
2735 result - timings[center_178][channel][slot][rank][lane].smallest;
2736 upper_margin =
2737 timings[center_178][channel][slot][rank][lane].largest - result;
2738 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002739 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002740 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002741 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002742 return result;
2743}
2744
2745#define STANDARD_MIN_MARGIN 5
2746
2747static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2748{
2749 u16 margin[64];
2750 int lane, rank, slot, channel;
2751 u8 reg178;
2752 int count = 0, sum = 0;
2753
2754 for (reg178 = reg178_min[info->clock_speed_index];
2755 reg178 < reg178_max[info->clock_speed_index];
2756 reg178 += reg178_step[info->clock_speed_index]) {
2757 margin[reg178] = -1;
2758 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2759 int curmargin =
2760 timings[reg178][channel][slot][rank][lane].largest -
2761 timings[reg178][channel][slot][rank][lane].
2762 smallest + 1;
2763 if (curmargin < margin[reg178])
2764 margin[reg178] = curmargin;
2765 }
2766 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2767 u16 weight;
2768 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2769 sum += weight * reg178;
2770 count += weight;
2771 }
2772 }
2773 dump_timings(info);
2774 if (count == 0)
2775 die("Couldn't discover DRAM timings (3)\n");
2776
2777 u8 threshold;
2778
2779 for (threshold = 30; threshold >= 5; threshold--) {
2780 int usable_length = 0;
2781 int smallest_fount = 0;
2782 for (reg178 = reg178_min[info->clock_speed_index];
2783 reg178 < reg178_max[info->clock_speed_index];
2784 reg178 += reg178_step[info->clock_speed_index])
2785 if (margin[reg178] >= threshold) {
2786 usable_length +=
2787 reg178_step[info->clock_speed_index];
2788 info->training.reg178_largest =
2789 reg178 -
2790 2 * reg178_step[info->clock_speed_index];
2791
2792 if (!smallest_fount) {
2793 smallest_fount = 1;
2794 info->training.reg178_smallest =
2795 reg178 +
2796 reg178_step[info->
2797 clock_speed_index];
2798 }
2799 }
2800 if (usable_length >= 0x21)
2801 break;
2802 }
2803
2804 return sum / count;
2805}
2806
2807static int check_cached_sanity(struct raminfo *info)
2808{
2809 int lane;
2810 int slot, rank;
2811 int channel;
2812
2813 if (!info->cached_training)
2814 return 0;
2815
2816 for (channel = 0; channel < NUM_CHANNELS; channel++)
2817 for (slot = 0; slot < NUM_SLOTS; slot++)
2818 for (rank = 0; rank < NUM_RANKS; rank++)
2819 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2820 u16 cached_value, estimation_value;
2821 cached_value =
2822 info->cached_training->
2823 lane_timings[1][channel][slot][rank]
2824 [lane];
2825 if (cached_value >= 0x18
2826 && cached_value <= 0x1E7) {
2827 estimation_value =
2828 info->training.
2829 lane_timings[1][channel]
2830 [slot][rank][lane];
2831 if (estimation_value <
2832 cached_value - 24)
2833 return 0;
2834 if (estimation_value >
2835 cached_value + 24)
2836 return 0;
2837 }
2838 }
2839 return 1;
2840}
2841
2842static int try_cached_training(struct raminfo *info)
2843{
2844 u8 saved_243[2];
2845 u8 tm;
2846
2847 int channel, slot, rank, lane;
2848 int flip = 1;
2849 int i, j;
2850
2851 if (!check_cached_sanity(info))
2852 return 0;
2853
2854 info->training.reg178_center = info->cached_training->reg178_center;
2855 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2856 info->training.reg178_largest = info->cached_training->reg178_largest;
2857 memcpy(&info->training.timing_bounds,
2858 &info->cached_training->timing_bounds,
2859 sizeof(info->training.timing_bounds));
2860 memcpy(&info->training.timing_offset,
2861 &info->cached_training->timing_offset,
2862 sizeof(info->training.timing_offset));
2863
2864 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002865 saved_243[0] = MCHBAR8(0x243);
2866 saved_243[1] = MCHBAR8(0x643);
2867 MCHBAR8(0x243) = saved_243[0] | 2;
2868 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002869 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002870 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002871 if (read_1d0(0x10b, 6) & 1)
2872 set_10b(info, 0);
2873 for (tm = 0; tm < 2; tm++) {
2874 int totalrank;
2875
2876 set_178(tm ? info->cached_training->reg178_largest : info->
2877 cached_training->reg178_smallest);
2878
2879 totalrank = 0;
2880 /* Check timing ranges. With i == 0 we check smallest one and with
2881 i == 1 the largest bound. With j == 0 we check that on the bound
2882 it still works whereas with j == 1 we check that just outside of
2883 bound we fail.
2884 */
2885 FOR_POPULATED_RANKS_BACKWARDS {
2886 for (i = 0; i < 2; i++) {
2887 for (lane = 0; lane < 8; lane++) {
2888 write_500(info, channel,
2889 info->cached_training->
2890 timing2_bounds[channel][slot]
2891 [rank][lane][i],
2892 get_timing_register_addr(lane,
2893 3,
2894 slot,
2895 rank),
2896 9, 1);
2897
2898 if (!i)
2899 write_500(info, channel,
2900 info->
2901 cached_training->
2902 timing2_offset
2903 [channel][slot][rank]
2904 [lane],
2905 get_timing_register_addr
2906 (lane, 2, slot, rank),
2907 9, 1);
2908 write_500(info, channel,
2909 i ? info->cached_training->
2910 timing_bounds[tm][channel]
2911 [slot][rank][lane].
2912 largest : info->
2913 cached_training->
2914 timing_bounds[tm][channel]
2915 [slot][rank][lane].smallest,
2916 get_timing_register_addr(lane,
2917 0,
2918 slot,
2919 rank),
2920 9, 1);
2921 write_500(info, channel,
2922 info->cached_training->
2923 timing_offset[channel][slot]
2924 [rank][lane] +
2925 (i ? info->cached_training->
2926 timing_bounds[tm][channel]
2927 [slot][rank][lane].
2928 largest : info->
2929 cached_training->
2930 timing_bounds[tm][channel]
2931 [slot][rank][lane].
2932 smallest) - 64,
2933 get_timing_register_addr(lane,
2934 1,
2935 slot,
2936 rank),
2937 9, 1);
2938 }
2939 for (j = 0; j < 2; j++) {
2940 u8 failmask;
2941 u8 expected_failmask;
2942 char reg1b3;
2943
2944 reg1b3 = (j == 1) + 4;
2945 reg1b3 =
2946 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2947 write_1d0(reg1b3, 0x1bb, 6, 1);
2948 write_1d0(reg1b3, 0x1b3, 6, 1);
2949 write_1d0(reg1b3, 0x1a3, 6, 1);
2950
2951 flip = !flip;
2952 write_testing(info, totalrank, flip);
2953 failmask =
2954 check_testing(info, totalrank,
2955 flip);
2956 expected_failmask =
2957 j == 0 ? 0x00 : 0xff;
2958 if (failmask != expected_failmask)
2959 goto fail;
2960 }
2961 }
2962 totalrank++;
2963 }
2964 }
2965
2966 set_178(info->cached_training->reg178_center);
2967 if (info->use_ecc)
2968 set_ecc(1);
2969 write_training_data(info);
2970 write_1d0(0, 322, 3, 1);
2971 info->training = *info->cached_training;
2972
2973 write_1d0(0, 0x1bb, 6, 1);
2974 write_1d0(0, 0x1b3, 6, 1);
2975 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002976 MCHBAR8(0x243) = saved_243[0];
2977 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002978
2979 return 1;
2980
2981fail:
2982 FOR_POPULATED_RANKS {
2983 write_500_timings_type(info, channel, slot, rank, 1);
2984 write_500_timings_type(info, channel, slot, rank, 2);
2985 write_500_timings_type(info, channel, slot, rank, 3);
2986 }
2987
2988 write_1d0(0, 0x1bb, 6, 1);
2989 write_1d0(0, 0x1b3, 6, 1);
2990 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002991 MCHBAR8(0x243) = saved_243[0];
2992 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002993
2994 return 0;
2995}
2996
2997static void do_ram_training(struct raminfo *info)
2998{
2999 u8 saved_243[2];
3000 int totalrank = 0;
3001 u8 reg_178;
3002 int niter;
3003
Matthias Gazzaridfa51252018-05-19 00:44:20 +02003004 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003005 int lane, rank, slot, channel;
3006 u8 reg178_center;
3007
3008 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003009 saved_243[0] = MCHBAR8(0x243);
3010 saved_243[1] = MCHBAR8(0x643);
3011 MCHBAR8(0x243) = saved_243[0] | 2;
3012 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003013 switch (info->clock_speed_index) {
3014 case 0:
3015 niter = 5;
3016 break;
3017 case 1:
3018 niter = 10;
3019 break;
3020 default:
3021 niter = 19;
3022 break;
3023 }
3024 set_ecc(0);
3025
3026 FOR_POPULATED_RANKS_BACKWARDS {
3027 int i;
3028
3029 write_500_timings_type(info, channel, slot, rank, 0);
3030
3031 write_testing(info, totalrank, 0);
3032 for (i = 0; i < niter; i++) {
3033 write_testing_type2(info, totalrank, 2, i, 0);
3034 write_testing_type2(info, totalrank, 3, i, 1);
3035 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003036 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003037 totalrank++;
3038 }
3039
3040 if (reg178_min[info->clock_speed_index] <
3041 reg178_max[info->clock_speed_index])
3042 memset(timings[reg178_min[info->clock_speed_index]], 0,
3043 sizeof(timings[0]) *
3044 (reg178_max[info->clock_speed_index] -
3045 reg178_min[info->clock_speed_index]));
3046 for (reg_178 = reg178_min[info->clock_speed_index];
3047 reg_178 < reg178_max[info->clock_speed_index];
3048 reg_178 += reg178_step[info->clock_speed_index]) {
3049 totalrank = 0;
3050 set_178(reg_178);
3051 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3052 for (slot = 0; slot < NUM_SLOTS; slot++)
3053 for (rank = 0; rank < NUM_RANKS; rank++) {
3054 memset(&timings[reg_178][channel][slot]
3055 [rank][0].smallest, 0, 16);
3056 if (info->
3057 populated_ranks[channel][slot]
3058 [rank]) {
3059 train_ram_at_178(info, channel,
3060 slot, rank,
3061 totalrank,
3062 reg_178, 1,
3063 niter,
3064 timings);
3065 totalrank++;
3066 }
3067 }
3068 }
3069
3070 reg178_center = choose_reg178(info, timings);
3071
3072 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3073 info->training.timing_bounds[0][channel][slot][rank][lane].
3074 smallest =
3075 timings[info->training.
3076 reg178_smallest][channel][slot][rank][lane].
3077 smallest;
3078 info->training.timing_bounds[0][channel][slot][rank][lane].
3079 largest =
3080 timings[info->training.
3081 reg178_smallest][channel][slot][rank][lane].largest;
3082 info->training.timing_bounds[1][channel][slot][rank][lane].
3083 smallest =
3084 timings[info->training.
3085 reg178_largest][channel][slot][rank][lane].smallest;
3086 info->training.timing_bounds[1][channel][slot][rank][lane].
3087 largest =
3088 timings[info->training.
3089 reg178_largest][channel][slot][rank][lane].largest;
3090 info->training.timing_offset[channel][slot][rank][lane] =
3091 info->training.lane_timings[1][channel][slot][rank][lane]
3092 -
3093 info->training.lane_timings[0][channel][slot][rank][lane] +
3094 64;
3095 }
3096
3097 if (info->silicon_revision == 1
3098 && (info->
3099 populated_ranks_mask[1] ^ (info->
3100 populated_ranks_mask[1] >> 2)) & 1) {
3101 int ranks_after_channel1;
3102
3103 totalrank = 0;
3104 for (reg_178 = reg178_center - 18;
3105 reg_178 <= reg178_center + 18; reg_178 += 18) {
3106 totalrank = 0;
3107 set_178(reg_178);
3108 for (slot = 0; slot < NUM_SLOTS; slot++)
3109 for (rank = 0; rank < NUM_RANKS; rank++) {
3110 if (info->
3111 populated_ranks[1][slot][rank]) {
3112 train_ram_at_178(info, 1, slot,
3113 rank,
3114 totalrank,
3115 reg_178, 0,
3116 niter,
3117 timings);
3118 totalrank++;
3119 }
3120 }
3121 }
3122 ranks_after_channel1 = totalrank;
3123
3124 for (reg_178 = reg178_center - 12;
3125 reg_178 <= reg178_center + 12; reg_178 += 12) {
3126 totalrank = ranks_after_channel1;
3127 set_178(reg_178);
3128 for (slot = 0; slot < NUM_SLOTS; slot++)
3129 for (rank = 0; rank < NUM_RANKS; rank++)
3130 if (info->
3131 populated_ranks[0][slot][rank]) {
3132 train_ram_at_178(info, 0, slot,
3133 rank,
3134 totalrank,
3135 reg_178, 0,
3136 niter,
3137 timings);
3138 totalrank++;
3139 }
3140
3141 }
3142 } else {
3143 for (reg_178 = reg178_center - 12;
3144 reg_178 <= reg178_center + 12; reg_178 += 12) {
3145 totalrank = 0;
3146 set_178(reg_178);
3147 FOR_POPULATED_RANKS_BACKWARDS {
3148 train_ram_at_178(info, channel, slot, rank,
3149 totalrank, reg_178, 0, niter,
3150 timings);
3151 totalrank++;
3152 }
3153 }
3154 }
3155
3156 set_178(reg178_center);
3157 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3158 u16 tm0;
3159
3160 tm0 =
3161 choose_training(info, channel, slot, rank, lane, timings,
3162 reg178_center);
3163 write_500(info, channel, tm0,
3164 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3165 write_500(info, channel,
3166 tm0 +
3167 info->training.
3168 lane_timings[1][channel][slot][rank][lane] -
3169 info->training.
3170 lane_timings[0][channel][slot][rank][lane],
3171 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3172 }
3173
3174 totalrank = 0;
3175 FOR_POPULATED_RANKS_BACKWARDS {
3176 try_timing_offsets(info, channel, slot, rank, totalrank);
3177 totalrank++;
3178 }
Felix Held04be2dd2018-07-29 04:53:22 +02003179 MCHBAR8(0x243) = saved_243[0];
3180 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003181 write_1d0(0, 0x142, 3, 1);
3182 info->training.reg178_center = reg178_center;
3183}
3184
3185static void ram_training(struct raminfo *info)
3186{
3187 u16 saved_fc4;
3188
Felix Held04be2dd2018-07-29 04:53:22 +02003189 saved_fc4 = MCHBAR16(0xfc4);
3190 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003191
3192 if (info->revision >= 8)
3193 read_4090(info);
3194
3195 if (!try_cached_training(info))
3196 do_ram_training(info);
3197 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3198 && info->clock_speed_index < 2)
3199 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003200 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003201}
3202
Martin Roth468d02c2019-10-23 21:44:42 -06003203static unsigned int gcd(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003204{
Martin Roth468d02c2019-10-23 21:44:42 -06003205 unsigned int t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003206 if (a > b) {
3207 t = a;
3208 a = b;
3209 b = t;
3210 }
3211 /* invariant a < b. */
3212 while (a) {
3213 t = b % a;
3214 b = a;
3215 a = t;
3216 }
3217 return b;
3218}
3219
3220static inline int div_roundup(int a, int b)
3221{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003222 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003223}
3224
Martin Roth468d02c2019-10-23 21:44:42 -06003225static unsigned int lcm(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003226{
3227 return (a * b) / gcd(a, b);
3228}
3229
3230struct stru1 {
3231 u8 freqs_reversed;
3232 u8 freq_diff_reduced;
3233 u8 freq_min_reduced;
3234 u8 divisor_f4_to_fmax;
3235 u8 divisor_f3_to_fmax;
3236 u8 freq4_to_max_remainder;
3237 u8 freq3_to_2_remainder;
3238 u8 freq3_to_2_remaindera;
3239 u8 freq4_to_2_remainder;
3240 int divisor_f3_to_f1, divisor_f4_to_f2;
3241 int common_time_unit_ps;
3242 int freq_max_reduced;
3243};
3244
3245static void
3246compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3247 int num_cycles_2, int num_cycles_1, int round_it,
3248 int add_freqs, struct stru1 *result)
3249{
3250 int g;
3251 int common_time_unit_ps;
3252 int freq1_reduced, freq2_reduced;
3253 int freq_min_reduced;
3254 int freq_max_reduced;
3255 int freq3, freq4;
3256
3257 g = gcd(freq1, freq2);
3258 freq1_reduced = freq1 / g;
3259 freq2_reduced = freq2 / g;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003260 freq_min_reduced = MIN(freq1_reduced, freq2_reduced);
3261 freq_max_reduced = MAX(freq1_reduced, freq2_reduced);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003262
3263 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3264 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3265 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3266 if (add_freqs) {
3267 freq3 += freq2_reduced;
3268 freq4 += freq1_reduced;
3269 }
3270
3271 if (round_it) {
3272 result->freq3_to_2_remainder = 0;
3273 result->freq3_to_2_remaindera = 0;
3274 result->freq4_to_max_remainder = 0;
3275 result->divisor_f4_to_f2 = 0;
3276 result->divisor_f3_to_f1 = 0;
3277 } else {
3278 if (freq2_reduced < freq1_reduced) {
3279 result->freq3_to_2_remainder =
3280 result->freq3_to_2_remaindera =
3281 freq3 % freq1_reduced - freq1_reduced + 1;
3282 result->freq4_to_max_remainder =
3283 -(freq4 % freq1_reduced);
3284 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3285 result->divisor_f4_to_f2 =
3286 (freq4 -
3287 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3288 result->freq4_to_2_remainder =
3289 -(char)((freq1_reduced - freq2_reduced) +
3290 ((u8) freq4 -
3291 (freq1_reduced -
3292 freq2_reduced)) % (u8) freq2_reduced);
3293 } else {
3294 if (freq2_reduced > freq1_reduced) {
3295 result->freq4_to_max_remainder =
3296 (freq4 % freq2_reduced) - freq2_reduced + 1;
3297 result->freq4_to_2_remainder =
3298 freq4 % freq_max_reduced -
3299 freq_max_reduced + 1;
3300 } else {
3301 result->freq4_to_max_remainder =
3302 -(freq4 % freq2_reduced);
3303 result->freq4_to_2_remainder =
3304 -(char)(freq4 % freq_max_reduced);
3305 }
3306 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3307 result->divisor_f3_to_f1 =
3308 (freq3 -
3309 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3310 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3311 result->freq3_to_2_remaindera =
3312 -(char)((freq_max_reduced - freq_min_reduced) +
3313 (freq3 -
3314 (freq_max_reduced -
3315 freq_min_reduced)) % freq1_reduced);
3316 }
3317 }
3318 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3319 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3320 if (round_it) {
3321 if (freq2_reduced > freq1_reduced) {
3322 if (freq3 % freq_max_reduced)
3323 result->divisor_f3_to_fmax++;
3324 }
3325 if (freq2_reduced < freq1_reduced) {
3326 if (freq4 % freq_max_reduced)
3327 result->divisor_f4_to_fmax++;
3328 }
3329 }
3330 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3331 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3332 result->freq_min_reduced = freq_min_reduced;
3333 result->common_time_unit_ps = common_time_unit_ps;
3334 result->freq_max_reduced = freq_max_reduced;
3335}
3336
3337static void
3338set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3339 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3340 int num_cycles_4, int reverse)
3341{
3342 struct stru1 vv;
3343 char multiplier;
3344
3345 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3346 0, 1, &vv);
3347
3348 multiplier =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003349 div_roundup(MAX
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003350 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3351 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3352 div_roundup(num_cycles_1,
3353 vv.common_time_unit_ps) +
3354 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3355 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3356
3357 u32 y =
3358 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3359 vv.freq_max_reduced * multiplier)
3360 | (vv.
3361 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3362 multiplier) << 16) | ((u8) (vv.
3363 freq_min_reduced
3364 *
3365 multiplier)
3366 << 24);
3367 u32 x =
3368 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3369 divisor_f3_to_f1
3370 << 16)
3371 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3372 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003373 MCHBAR32(reg) = y;
3374 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003375 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003376 MCHBAR32(reg + 4) = y;
3377 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003378 }
3379}
3380
3381static void
3382set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3383 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3384 int num_cycles_4)
3385{
3386 struct stru1 ratios1;
3387 struct stru1 ratios2;
3388
3389 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3390 0, 1, &ratios2);
3391 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3392 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003393 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003394 ratios1.freq4_to_max_remainder | (ratios2.
3395 freq4_to_max_remainder
3396 << 8)
3397 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3398 divisor_f4_to_fmax
3399 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003400 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3401 (ratios2.freq4_to_max_remainder << 8) |
3402 (ratios1.divisor_f4_to_fmax << 16) |
3403 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003404}
3405
3406static void
3407set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3408 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3409{
3410 struct stru1 ratios;
3411
3412 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3413 round_it, add_freqs, &ratios);
3414 switch (mode) {
3415 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003416 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3417 (ratios.freqs_reversed << 8);
3418 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3419 (ratios.freq4_to_max_remainder << 8) |
3420 (ratios.divisor_f3_to_fmax << 16) |
3421 (ratios.divisor_f4_to_fmax << 20) |
3422 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003423 break;
3424
3425 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003426 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3427 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003428 break;
3429
3430 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003431 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3432 (ratios.freq4_to_max_remainder << 8) |
3433 (ratios.divisor_f3_to_fmax << 16) |
3434 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003435 break;
3436
3437 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003438 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3439 (ratios.divisor_f4_to_fmax << 8) |
3440 (ratios.freqs_reversed << 12) |
3441 (ratios.freq_min_reduced << 16) |
3442 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003443 break;
3444 }
3445}
3446
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003447static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003448{
3449 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3450 0, 1);
3451 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3452 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3453 1);
3454 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3455 frequency_11(info), 1231, 1524, 0, 1);
3456 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3457 frequency_11(info) / 2, 1278, 2008, 0, 1);
3458 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3459 1167, 1539, 0, 1);
3460 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3461 frequency_11(info) / 2, 1403, 1318, 0, 1);
3462 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3463 1);
3464 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3465 1);
3466 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3467 1, 1);
3468 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3469 1);
3470 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3471 frequency_11(info) / 2, 4000, 0, 0, 0);
3472 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3473 frequency_11(info) / 2, 4000, 4000, 0, 0);
3474
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003475 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003476 printk(RAM_SPEW, "[6dc] <= %x\n",
3477 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003478 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003479 } else
3480 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3481 info->delay46_ps[0], 0,
3482 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003483 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3484 frequency_11(info), 2500, 0, 0, 0);
3485 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3486 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003487 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003488 printk(RAM_SPEW, "[6e8] <= %x\n",
3489 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003490 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003491 } else
3492 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3493 info->delay46_ps[1], 0,
3494 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003495 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3496 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3497 470, 0);
3498 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3499 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3500 454, 459, 0);
3501 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3502 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3503 2588, 0);
3504 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3505 2405, 0);
3506 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3507 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3508 480, 0);
3509 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003510 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3511 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003512}
3513
3514static u16 get_max_timing(struct raminfo *info, int channel)
3515{
3516 int slot, rank, lane;
3517 u16 ret = 0;
3518
Felix Held04be2dd2018-07-29 04:53:22 +02003519 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003520 return 384;
3521
3522 if (info->revision < 8)
3523 return 256;
3524
3525 for (slot = 0; slot < NUM_SLOTS; slot++)
3526 for (rank = 0; rank < NUM_RANKS; rank++)
3527 if (info->populated_ranks[channel][slot][rank])
3528 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003529 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003530 get_timing_register_addr
3531 (lane, 0, slot,
3532 rank), 9));
3533 return ret;
3534}
3535
3536static void set_274265(struct raminfo *info)
3537{
3538 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3539 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3540 int delay_e_over_cycle_ps;
3541 int cycletime_ps;
3542 int channel;
3543
3544 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003545 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003546 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3547 cycletime_ps =
3548 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3549 delay_d_ps =
3550 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3551 - info->some_delay_3_ps_rounded + 200;
3552 if (!
3553 ((info->silicon_revision == 0
3554 || info->silicon_revision == 1)
3555 && (info->revision >= 8)))
3556 delay_d_ps += halfcycle_ps(info) * 2;
3557 delay_d_ps +=
3558 halfcycle_ps(info) * (!info->revision_flag_1 +
3559 info->some_delay_2_halfcycles_ceil +
3560 2 * info->some_delay_1_cycle_floor +
3561 info->clock_speed_index +
3562 2 * info->cas_latency - 7 + 11);
3563 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3564
Felix Held04be2dd2018-07-29 04:53:22 +02003565 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3566 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3567 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003568 delay_d_ps += 650;
3569 delay_c_ps = delay_d_ps + 1800;
3570 if (delay_c_ps <= delay_a_ps)
3571 delay_e_ps = 0;
3572 else
3573 delay_e_ps =
3574 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3575 cycletime_ps);
3576
3577 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3578 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3579 delay_f_cycles =
3580 div_roundup(2500 - delay_e_over_cycle_ps,
3581 2 * halfcycle_ps(info));
3582 if (delay_f_cycles > delay_e_cycles) {
3583 info->delay46_ps[channel] = delay_e_ps;
3584 delay_e_cycles = 0;
3585 } else {
3586 info->delay46_ps[channel] =
3587 delay_e_over_cycle_ps +
3588 2 * halfcycle_ps(info) * delay_f_cycles;
3589 delay_e_cycles -= delay_f_cycles;
3590 }
3591
3592 if (info->delay46_ps[channel] < 2500) {
3593 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003594 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003595 }
3596 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3597 if (delay_b_ps <= delay_a_ps)
3598 delay_b_ps = 0;
3599 else
3600 delay_b_ps -= delay_a_ps;
3601 info->delay54_ps[channel] =
3602 cycletime_ps * div_roundup(delay_b_ps,
3603 cycletime_ps) -
3604 2 * halfcycle_ps(info) * delay_e_cycles;
3605 if (info->delay54_ps[channel] < 2500)
3606 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003607 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003608 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3609 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003610 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003611 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003612 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003613 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3614 4 * halfcycle_ps(info)) - 6;
3615 MCHBAR32((channel << 10) + 0x274) =
3616 info->training.reg274265[channel][1] |
3617 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003618 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003619 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3620 4 * halfcycle_ps(info)) + 1;
3621 MCHBAR16((channel << 10) + 0x265) =
3622 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003623 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003624 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003625 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003626 else
Felix Held04be2dd2018-07-29 04:53:22 +02003627 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003628}
3629
3630static void restore_274265(struct raminfo *info)
3631{
3632 int channel;
3633
3634 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003635 MCHBAR32((channel << 10) + 0x274) =
3636 (info->cached_training->reg274265[channel][0] << 16) |
3637 info->cached_training->reg274265[channel][1];
3638 MCHBAR16((channel << 10) + 0x265) =
3639 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003640 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003641 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003642 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003643 else
Felix Held04be2dd2018-07-29 04:53:22 +02003644 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003645}
3646
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003647static void dmi_setup(void)
3648{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003649 gav(read8(DEFAULT_DMIBAR + 0x254));
3650 write8(DEFAULT_DMIBAR + 0x254, 0x1);
3651 write16(DEFAULT_DMIBAR + 0x1b8, 0x18f2);
Felix Heldf83d80b2018-07-29 05:30:30 +02003652 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003653
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003654 write32(DEFAULT_DMIBAR + 0xd68, read32(DEFAULT_DMIBAR + 0xd68) | 0x08000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003655
3656 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3657 DEFAULT_GPIOBASE | 0x38);
3658 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3659}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003660
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003661void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003662{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003663 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003664 u16 ggc;
3665 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003666
Felix Held04be2dd2018-07-29 04:53:22 +02003667 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003668 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3669 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003670 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003671 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003672 }
Felix Held29a9c072018-07-29 01:34:45 +02003673#if 0
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003674 if (!s3resume) {
3675 pre_raminit_3(x2ca8);
3676 }
Vladimir Serbinenkof62669c2014-01-09 10:59:38 +01003677 pre_raminit_4a(x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003678#endif
3679
3680 dmi_setup();
3681
Felix Held04be2dd2018-07-29 04:53:22 +02003682 MCHBAR16(0x1170) = 0xa880;
3683 MCHBAR8(0x11c1) = 0x1;
3684 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003685 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003686
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003687 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3688 /* 0 for 32MB */
3689 gfxsize = 0;
3690 }
3691
3692 ggc = 0xb00 | ((gfxsize + 5) << 4);
3693
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003694 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003695
3696 u16 deven;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003697 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003698
3699 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003700 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003701 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003702 MCHBAR16_OR(0x2c30, 0x200);
3703 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003704 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003705 pci_read_config8(GMA, 0x62); // = 0x2
3706 pci_write_config8(GMA, 0x62, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003707 read8(DEFAULT_RCBA + 0x2318);
3708 write8(DEFAULT_RCBA + 0x2318, 0x47);
3709 read8(DEFAULT_RCBA + 0x2320);
3710 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003711 }
3712
Felix Heldf83d80b2018-07-29 05:30:30 +02003713 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003714
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003715 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003716 gav(read32(DEFAULT_RCBA + 0x3428));
3717 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003718}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003719
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003720void raminit(const int s3resume, const u8 *spd_addrmap)
3721{
Martin Roth468d02c2019-10-23 21:44:42 -06003722 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003723 int i;
3724 struct raminfo info;
3725 u8 x2ca8;
3726 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003727 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003728
Felix Held04be2dd2018-07-29 04:53:22 +02003729 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003730
3731 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3732
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003733 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003734
3735 memset(&info, 0x5a, sizeof(info));
3736
3737 info.last_500_command[0] = 0;
3738 info.last_500_command[1] = 0;
3739
3740 info.fsb_frequency = 135 * 2;
3741 info.board_lane_delay[0] = 0x14;
3742 info.board_lane_delay[1] = 0x07;
3743 info.board_lane_delay[2] = 0x07;
3744 info.board_lane_delay[3] = 0x08;
3745 info.board_lane_delay[4] = 0x56;
3746 info.board_lane_delay[5] = 0x04;
3747 info.board_lane_delay[6] = 0x04;
3748 info.board_lane_delay[7] = 0x05;
3749 info.board_lane_delay[8] = 0x10;
3750
3751 info.training.reg_178 = 0;
3752 info.training.reg_10b = 0;
3753
3754 info.heci_bar = 0;
3755 info.memory_reserved_for_heci_mb = 0;
3756
3757 /* before SPD */
3758 timestamp_add_now(101);
3759
Felix Held29a9c072018-07-29 01:34:45 +02003760 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003761 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003762
3763 collect_system_info(&info);
3764
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003765 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3766
3767 info.use_ecc = 1;
3768 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003769 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003770 int v;
3771 int try;
3772 int addr;
3773 const u8 useful_addresses[] = {
3774 DEVICE_TYPE,
3775 MODULE_TYPE,
3776 DENSITY,
3777 RANKS_AND_DQ,
3778 MEMORY_BUS_WIDTH,
3779 TIMEBASE_DIVIDEND,
3780 TIMEBASE_DIVISOR,
3781 CYCLETIME,
3782 CAS_LATENCIES_LSB,
3783 CAS_LATENCIES_MSB,
3784 CAS_LATENCY_TIME,
3785 0x11, 0x12, 0x13, 0x14, 0x15,
3786 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3787 0x1c, 0x1d,
3788 THERMAL_AND_REFRESH,
3789 0x20,
3790 REFERENCE_RAW_CARD_USED,
3791 RANK1_ADDRESS_MAPPING,
3792 0x75, 0x76, 0x77, 0x78,
3793 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3794 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3795 0x85, 0x86, 0x87, 0x88,
3796 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3797 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3798 0x95
3799 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003800 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003801 continue;
3802 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003803 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003804 DEVICE_TYPE);
3805 if (v >= 0)
3806 break;
3807 }
3808 if (v < 0)
3809 continue;
3810 for (addr = 0;
3811 addr <
3812 sizeof(useful_addresses) /
3813 sizeof(useful_addresses[0]); addr++)
3814 gav(info.
3815 spd[channel][0][useful_addresses
3816 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003817 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003818 useful_addresses
3819 [addr]));
3820 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3821 die("Only DDR3 is supported");
3822
3823 v = info.spd[channel][0][RANKS_AND_DQ];
3824 info.populated_ranks[channel][0][0] = 1;
3825 info.populated_ranks[channel][0][1] =
3826 ((v >> 3) & 7);
3827 if (((v >> 3) & 7) > 1)
3828 die("At most 2 ranks are supported");
3829 if ((v & 7) == 0 || (v & 7) > 2)
3830 die("Only x8 and x16 modules are supported");
3831 if ((info.
3832 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3833 && (info.
3834 spd[channel][slot][MODULE_TYPE] & 0xF)
3835 != 3)
3836 die("Registered memory is not supported");
3837 info.is_x16_module[channel][0] = (v & 7) - 1;
3838 info.density[channel][slot] =
3839 info.spd[channel][slot][DENSITY] & 0xF;
3840 if (!
3841 (info.
3842 spd[channel][slot][MEMORY_BUS_WIDTH] &
3843 0x18))
3844 info.use_ecc = 0;
3845 }
3846
3847 gav(0x55);
3848
3849 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3850 int v = 0;
3851 for (slot = 0; slot < NUM_SLOTS; slot++)
3852 for (rank = 0; rank < NUM_RANKS; rank++)
3853 v |= info.
3854 populated_ranks[channel][slot][rank]
3855 << (2 * slot + rank);
3856 info.populated_ranks_mask[channel] = v;
3857 }
3858
3859 gav(0x55);
3860
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003861 gav(pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003862 }
3863
3864 /* after SPD */
3865 timestamp_add_now(102);
3866
Felix Held04be2dd2018-07-29 04:53:22 +02003867 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003868
3869 collect_system_info(&info);
3870 calculate_timings(&info);
3871
Felix Held29a9c072018-07-29 01:34:45 +02003872#if 0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003873 pci_write_config8(NORTHBRIDGE, 0xdf, 0x82);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003874#endif
3875
3876 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003877 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003878 if (x2ca8 == 0 && (reg8 & 0x80)) {
3879 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3880 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3881 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3882 */
3883
3884 /* Clear bit7. */
3885
3886 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3887 (reg8 & ~(1 << 7)));
3888
3889 printk(BIOS_INFO,
3890 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003891 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003892 }
3893 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003894
3895 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003896 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3897 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003898
3899 compute_derived_timings(&info);
3900
3901 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003902 gav(MCHBAR8(0x164));
3903 MCHBAR8(0x164) = 0x26;
3904 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003905 }
3906
Felix Held04be2dd2018-07-29 04:53:22 +02003907 MCHBAR32_OR(0x18b4, 0x210000);
3908 MCHBAR32_OR(0x1890, 0x2000000);
3909 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003910
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003911 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x50)); // !!!!
3912 pci_write_config8(PCI_DEV(0xff, 2, 1), 0x54, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003913
Felix Held04be2dd2018-07-29 04:53:22 +02003914 gav(MCHBAR16(0x2c10));
3915 MCHBAR16(0x2c10) = 0x412;
3916 gav(MCHBAR16(0x2c10));
3917 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003918
Felix Held04be2dd2018-07-29 04:53:22 +02003919 gav(MCHBAR8(0x2ca8)); // !!!!
3920 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003921
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003922 pci_read_config32(PCI_DEV(0xff, 2, 1), 0x6c); // !!!!
3923 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x6c, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003924 gav(MCHBAR32(0x1c04)); // !!!!
3925 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003926
3927 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003928 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003929 }
3930
Felix Held04be2dd2018-07-29 04:53:22 +02003931 MCHBAR32(0x18d8) = 0x120000;
3932 MCHBAR32(0x18dc) = 0x30a484a;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003933 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x0);
3934 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003935 MCHBAR32(0x18d8) = 0x40000;
3936 MCHBAR32(0x18dc) = 0xb000000;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003937 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x60000);
3938 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003939 MCHBAR32(0x18d8) = 0x180000;
3940 MCHBAR32(0x18dc) = 0xc0000142;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003941 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x20000);
3942 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003943 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003944
Felix Held04be2dd2018-07-29 04:53:22 +02003945 gav(MCHBAR32(0x18dc)); // !!!!
3946 MCHBAR32(0x18dc) = 0x3;
3947 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003948
3949 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003950 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003951 }
3952
Felix Held04be2dd2018-07-29 04:53:22 +02003953 MCHBAR32(0x188c) = 0x20bc09;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003954 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xd0, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003955 MCHBAR32(0x1a10) = 0x4200010e;
3956 MCHBAR32_OR(0x18b8, 0x200);
3957 gav(MCHBAR32(0x1918)); // !!!!
3958 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003959
Felix Held04be2dd2018-07-29 04:53:22 +02003960 gav(MCHBAR32(0x18b8)); // !!!!
3961 MCHBAR32(0x18b8) = 0xe00;
3962 gav(MCHBAR32(0x182c)); // !!!!
3963 MCHBAR32(0x182c) = 0x10202;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003964 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x94)); // !!!!
3965 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x94, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003966 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3967 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003968
Felix Held04be2dd2018-07-29 04:53:22 +02003969 MCHBAR32_AND(0x18b4, 0xffff7fff);
3970 gav(MCHBAR32(0x1a68)); // !!!!
3971 MCHBAR32(0x1a68) = 0x343800;
3972 gav(MCHBAR32(0x1e68)); // !!!!
3973 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003974
3975 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003976 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003977 }
3978
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003979 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x048); // !!!!
3980 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x048, 0x140000);
3981 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3982 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x058, 0x64555);
3983 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3984 pci_read_config32(PCI_DEV (0xff, 0, 0), 0xd0); // !!!!
3985 pci_write_config32(PCI_DEV (0xff, 0, 0), 0xd0, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003986 gav(MCHBAR32(0x1af0)); // !!!!
3987 gav(MCHBAR32(0x1af0)); // !!!!
3988 MCHBAR32(0x1af0) = 0x1f020003;
3989 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003990
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003991 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003992 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003993 }
3994
Felix Held04be2dd2018-07-29 04:53:22 +02003995 gav(MCHBAR32(0x1890)); // !!!!
3996 MCHBAR32(0x1890) = 0x80102;
3997 gav(MCHBAR32(0x18b4)); // !!!!
3998 MCHBAR32(0x18b4) = 0x216000;
3999 MCHBAR32(0x18a4) = 0x22222222;
4000 MCHBAR32(0x18a8) = 0x22222222;
4001 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004002
4003 udelay(1000);
4004
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004005 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004006
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004007 if (x2ca8 == 0) {
4008 int j;
4009 if (s3resume && info.cached_training) {
4010 restore_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02004011 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004012 info.cached_training->reg2ca9_bit0);
4013 for (i = 0; i < 2; i++)
4014 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02004015 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004016 i, j, info.cached_training->reg274265[i][j]);
4017 } else {
4018 set_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02004019 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004020 info.training.reg2ca9_bit0);
4021 for (i = 0; i < 2; i++)
4022 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02004023 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004024 i, j, info.training.reg274265[i][j]);
4025 }
4026
4027 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004028
4029 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02004030 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004031 }
4032
4033 udelay(1000);
4034
4035 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02004036 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02004037 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004038 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4039 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4040 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004041
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004042 MCHBAR8(0x1150);
4043 MCHBAR8(0x1151);
4044 MCHBAR8(0x1022);
4045 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004046 MCHBAR32(0x1300) = 0x60606060;
4047 MCHBAR32(0x1304) = 0x60606060;
4048 MCHBAR32(0x1308) = 0x78797a7b;
4049 MCHBAR32(0x130c) = 0x7c7d7e7f;
4050 MCHBAR32(0x1310) = 0x60606060;
4051 MCHBAR32(0x1314) = 0x60606060;
4052 MCHBAR32(0x1318) = 0x60606060;
4053 MCHBAR32(0x131c) = 0x60606060;
4054 MCHBAR32(0x1320) = 0x50515253;
4055 MCHBAR32(0x1324) = 0x54555657;
4056 MCHBAR32(0x1328) = 0x58595a5b;
4057 MCHBAR32(0x132c) = 0x5c5d5e5f;
4058 MCHBAR32(0x1330) = 0x40414243;
4059 MCHBAR32(0x1334) = 0x44454647;
4060 MCHBAR32(0x1338) = 0x48494a4b;
4061 MCHBAR32(0x133c) = 0x4c4d4e4f;
4062 MCHBAR32(0x1340) = 0x30313233;
4063 MCHBAR32(0x1344) = 0x34353637;
4064 MCHBAR32(0x1348) = 0x38393a3b;
4065 MCHBAR32(0x134c) = 0x3c3d3e3f;
4066 MCHBAR32(0x1350) = 0x20212223;
4067 MCHBAR32(0x1354) = 0x24252627;
4068 MCHBAR32(0x1358) = 0x28292a2b;
4069 MCHBAR32(0x135c) = 0x2c2d2e2f;
4070 MCHBAR32(0x1360) = 0x10111213;
4071 MCHBAR32(0x1364) = 0x14151617;
4072 MCHBAR32(0x1368) = 0x18191a1b;
4073 MCHBAR32(0x136c) = 0x1c1d1e1f;
4074 MCHBAR32(0x1370) = 0x10203;
4075 MCHBAR32(0x1374) = 0x4050607;
4076 MCHBAR32(0x1378) = 0x8090a0b;
4077 MCHBAR32(0x137c) = 0xc0d0e0f;
4078 MCHBAR8(0x11cc) = 0x4e;
4079 MCHBAR32(0x1110) = 0x73970404;
4080 MCHBAR32(0x1114) = 0x72960404;
4081 MCHBAR32(0x1118) = 0x6f950404;
4082 MCHBAR32(0x111c) = 0x6d940404;
4083 MCHBAR32(0x1120) = 0x6a930404;
4084 MCHBAR32(0x1124) = 0x68a41404;
4085 MCHBAR32(0x1128) = 0x66a21404;
4086 MCHBAR32(0x112c) = 0x63a01404;
4087 MCHBAR32(0x1130) = 0x609e1404;
4088 MCHBAR32(0x1134) = 0x5f9c1404;
4089 MCHBAR32(0x1138) = 0x5c961404;
4090 MCHBAR32(0x113c) = 0x58a02404;
4091 MCHBAR32(0x1140) = 0x54942404;
4092 MCHBAR32(0x1190) = 0x900080a;
4093 MCHBAR16(0x11c0) = 0xc40b;
4094 MCHBAR16(0x11c2) = 0x303;
4095 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004096 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004097 MCHBAR32(0x11b8) = 0x70c3000;
4098 MCHBAR8(0x11ec) = 0xa;
4099 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004100 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004101 MCHBAR16(0x11ca) = 0xfa;
4102 MCHBAR32(0x11e4) = 0x4e20;
4103 MCHBAR8(0x11bc) = 0xf;
4104 MCHBAR16(0x11da) = 0x19;
4105 MCHBAR16(0x11ba) = 0x470c;
4106 MCHBAR32(0x1680) = 0xe6ffe4ff;
4107 MCHBAR32(0x1684) = 0xdeffdaff;
4108 MCHBAR32(0x1688) = 0xd4ffd0ff;
4109 MCHBAR32(0x168c) = 0xccffc6ff;
4110 MCHBAR32(0x1690) = 0xc0ffbeff;
4111 MCHBAR32(0x1694) = 0xb8ffb0ff;
4112 MCHBAR32(0x1698) = 0xa8ff0000;
4113 MCHBAR32(0x169c) = 0xc00;
4114 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004115 }
4116
Felix Held04be2dd2018-07-29 04:53:22 +02004117 MCHBAR32(0x124c) = 0x15040d00;
4118 MCHBAR32(0x1250) = 0x7f0000;
4119 MCHBAR32(0x1254) = 0x1e220004;
4120 MCHBAR32(0x1258) = 0x4000004;
4121 MCHBAR32(0x1278) = 0x0;
4122 MCHBAR32(0x125c) = 0x0;
4123 MCHBAR32(0x1260) = 0x0;
4124 MCHBAR32(0x1264) = 0x0;
4125 MCHBAR32(0x1268) = 0x0;
4126 MCHBAR32(0x126c) = 0x0;
4127 MCHBAR32(0x1270) = 0x0;
4128 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004129 }
4130
4131 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004132 MCHBAR16(0x1214) = 0x320;
4133 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004134 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4135 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004136 MCHBAR32(0x1400) = 0x13040020;
4137 MCHBAR32(0x1404) = 0xe090120;
4138 MCHBAR32(0x1408) = 0x5120220;
4139 MCHBAR32(0x140c) = 0x5120330;
4140 MCHBAR32(0x1410) = 0xe090220;
4141 MCHBAR32(0x1414) = 0x1010001;
4142 MCHBAR32(0x1418) = 0x1110000;
4143 MCHBAR32(0x141c) = 0x9020020;
4144 MCHBAR32(0x1420) = 0xd090220;
4145 MCHBAR32(0x1424) = 0x2090220;
4146 MCHBAR32(0x1428) = 0x2090330;
4147 MCHBAR32(0x142c) = 0xd090220;
4148 MCHBAR32(0x1430) = 0x1010001;
4149 MCHBAR32(0x1434) = 0x1110000;
4150 MCHBAR32(0x1438) = 0x11040020;
4151 MCHBAR32(0x143c) = 0x4030220;
4152 MCHBAR32(0x1440) = 0x1060220;
4153 MCHBAR32(0x1444) = 0x1060330;
4154 MCHBAR32(0x1448) = 0x4030220;
4155 MCHBAR32(0x144c) = 0x1010001;
4156 MCHBAR32(0x1450) = 0x1110000;
4157 MCHBAR32(0x1454) = 0x4010020;
4158 MCHBAR32(0x1458) = 0xb090220;
4159 MCHBAR32(0x145c) = 0x1090220;
4160 MCHBAR32(0x1460) = 0x1090330;
4161 MCHBAR32(0x1464) = 0xb090220;
4162 MCHBAR32(0x1468) = 0x1010001;
4163 MCHBAR32(0x146c) = 0x1110000;
4164 MCHBAR32(0x1470) = 0xf040020;
4165 MCHBAR32(0x1474) = 0xa090220;
4166 MCHBAR32(0x1478) = 0x1120220;
4167 MCHBAR32(0x147c) = 0x1120330;
4168 MCHBAR32(0x1480) = 0xa090220;
4169 MCHBAR32(0x1484) = 0x1010001;
4170 MCHBAR32(0x1488) = 0x1110000;
4171 MCHBAR32(0x148c) = 0x7020020;
4172 MCHBAR32(0x1490) = 0x1010220;
4173 MCHBAR32(0x1494) = 0x10210;
4174 MCHBAR32(0x1498) = 0x10320;
4175 MCHBAR32(0x149c) = 0x1010220;
4176 MCHBAR32(0x14a0) = 0x1010001;
4177 MCHBAR32(0x14a4) = 0x1110000;
4178 MCHBAR32(0x14a8) = 0xd040020;
4179 MCHBAR32(0x14ac) = 0x8090220;
4180 MCHBAR32(0x14b0) = 0x1111310;
4181 MCHBAR32(0x14b4) = 0x1111420;
4182 MCHBAR32(0x14b8) = 0x8090220;
4183 MCHBAR32(0x14bc) = 0x1010001;
4184 MCHBAR32(0x14c0) = 0x1110000;
4185 MCHBAR32(0x14c4) = 0x3010020;
4186 MCHBAR32(0x14c8) = 0x7090220;
4187 MCHBAR32(0x14cc) = 0x1081310;
4188 MCHBAR32(0x14d0) = 0x1081420;
4189 MCHBAR32(0x14d4) = 0x7090220;
4190 MCHBAR32(0x14d8) = 0x1010001;
4191 MCHBAR32(0x14dc) = 0x1110000;
4192 MCHBAR32(0x14e0) = 0xb040020;
4193 MCHBAR32(0x14e4) = 0x2030220;
4194 MCHBAR32(0x14e8) = 0x1051310;
4195 MCHBAR32(0x14ec) = 0x1051420;
4196 MCHBAR32(0x14f0) = 0x2030220;
4197 MCHBAR32(0x14f4) = 0x1010001;
4198 MCHBAR32(0x14f8) = 0x1110000;
4199 MCHBAR32(0x14fc) = 0x5020020;
4200 MCHBAR32(0x1500) = 0x5090220;
4201 MCHBAR32(0x1504) = 0x2071310;
4202 MCHBAR32(0x1508) = 0x2071420;
4203 MCHBAR32(0x150c) = 0x5090220;
4204 MCHBAR32(0x1510) = 0x1010001;
4205 MCHBAR32(0x1514) = 0x1110000;
4206 MCHBAR32(0x1518) = 0x7040120;
4207 MCHBAR32(0x151c) = 0x2090220;
4208 MCHBAR32(0x1520) = 0x70b1210;
4209 MCHBAR32(0x1524) = 0x70b1310;
4210 MCHBAR32(0x1528) = 0x2090220;
4211 MCHBAR32(0x152c) = 0x1010001;
4212 MCHBAR32(0x1530) = 0x1110000;
4213 MCHBAR32(0x1534) = 0x1010110;
4214 MCHBAR32(0x1538) = 0x1081310;
4215 MCHBAR32(0x153c) = 0x5041200;
4216 MCHBAR32(0x1540) = 0x5041310;
4217 MCHBAR32(0x1544) = 0x1081310;
4218 MCHBAR32(0x1548) = 0x1010001;
4219 MCHBAR32(0x154c) = 0x1110000;
4220 MCHBAR32(0x1550) = 0x1040120;
4221 MCHBAR32(0x1554) = 0x4051210;
4222 MCHBAR32(0x1558) = 0xd051200;
4223 MCHBAR32(0x155c) = 0xd051200;
4224 MCHBAR32(0x1560) = 0x4051210;
4225 MCHBAR32(0x1564) = 0x1010001;
4226 MCHBAR32(0x1568) = 0x1110000;
4227 MCHBAR16(0x1222) = 0x220a;
4228 MCHBAR16(0x123c) = 0x1fc0;
4229 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004230 }
4231
Felix Heldf83d80b2018-07-29 05:30:30 +02004232 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004233 MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004234 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004235
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004236 MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004237
4238 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004239 MCHBAR8_AND(0x2ca8, ~3);
4240 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02004241 /* This issues a CPU reset without resetting the platform */
4242 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02004243 /* Write back the S3 state to PM1_CNT to let the reset CPU
4244 know it also needs to take the s3 path. */
4245 if (s3resume)
4246 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
4247 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02004248 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004249 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004250 }
4251
Felix Held04be2dd2018-07-29 04:53:22 +02004252 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004253 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004254 pci_write_config32(PCI_DEV (0xff, 0, 0), 0x60, 0x20220);
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004255 MCHBAR16(0x2c20); // !!!!
4256 MCHBAR16(0x2c10); // !!!!
4257 MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004258 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004259 udelay(1000);
4260 write_1d0(0, 0x33d, 0, 0);
4261 write_500(&info, 0, 0, 0xb61, 0, 0);
4262 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004263 MCHBAR32(0x1a30) = 0x0;
4264 MCHBAR32(0x1a34) = 0x0;
4265 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4266 (info.populated_ranks[0][0][0] * 0xa0);
4267 MCHBAR16(0x616) = 0x26a;
4268 MCHBAR32(0x134) = 0x856000;
4269 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004270 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4271 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004272 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004273 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4274 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004275 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004276 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004277 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4278 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004279 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4280 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4281 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4282 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4283 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4284 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4285 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4286 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4287 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4288 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004289 }
4290
4291 write_1d0(0x4, 0x151, 4, 1);
4292 write_1d0(0, 0x142, 3, 1);
4293 rdmsr(0x1ac); // !!!!
4294 write_500(&info, 1, 1, 0x6b3, 4, 1);
4295 write_500(&info, 1, 1, 0x6cf, 4, 1);
4296
4297 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4298
4299 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4300 populated_ranks[0]
4301 [0][0]) << 0),
4302 0x1d1, 3, 1);
4303 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004304 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4305 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004306 }
4307
4308 set_334(0);
4309
4310 program_base_timings(&info);
4311
Felix Held04be2dd2018-07-29 04:53:22 +02004312 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004313
4314 write_1d0(0x2, 0x1d5, 2, 1);
4315 write_1d0(0x20, 0x166, 7, 1);
4316 write_1d0(0x0, 0xeb, 3, 1);
4317 write_1d0(0x0, 0xf3, 6, 1);
4318
4319 for (channel = 0; channel < NUM_CHANNELS; channel++)
4320 for (lane = 0; lane < 9; lane++) {
4321 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4322 u8 a;
4323 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4324 write_500(&info, channel, a, addr, 6, 1);
4325 }
4326
4327 udelay(1000);
4328
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004329 if (s3resume) {
4330 if (info.cached_training == NULL) {
4331 u32 reg32;
4332 printk(BIOS_ERR,
4333 "Couldn't find training data. Rebooting\n");
4334 reg32 = inl(DEFAULT_PMBASE + 0x04);
4335 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004336 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004337 }
4338 int tm;
4339 info.training = *info.cached_training;
4340 for (tm = 0; tm < 4; tm++)
4341 for (channel = 0; channel < NUM_CHANNELS; channel++)
4342 for (slot = 0; slot < NUM_SLOTS; slot++)
4343 for (rank = 0; rank < NUM_RANKS; rank++)
4344 for (lane = 0; lane < 9; lane++)
4345 write_500(&info,
4346 channel,
4347 info.training.
4348 lane_timings
4349 [tm][channel]
4350 [slot][rank]
4351 [lane],
4352 get_timing_register_addr
4353 (lane, tm,
4354 slot, rank),
4355 9, 0);
4356 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4357 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4358 }
4359
Felix Heldf83d80b2018-07-29 05:30:30 +02004360 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004361 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004362 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004363 MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004364
4365 program_board_delay(&info);
4366
Felix Held04be2dd2018-07-29 04:53:22 +02004367 MCHBAR8(0x5ff) = 0x0;
4368 MCHBAR8(0x5ff) = 0x80;
4369 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004370
Felix Held04be2dd2018-07-29 04:53:22 +02004371 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004372 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004373 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004374 gav(read_1d0(0x14b, 7)); // = 0x81023100
4375 write_1d0(0x30, 0x14b, 7, 1);
4376 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4377 write_1d0(7, 0xd6, 6, 1);
4378 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4379 write_1d0(7, 0x328, 6, 1);
4380
4381 for (channel = 0; channel < NUM_CHANNELS; channel++)
4382 set_4cf(&info, channel,
4383 info.populated_ranks[channel][0][0] ? 8 : 0);
4384
4385 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4386 write_1d0(2, 0x116, 4, 1);
4387 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4388 write_1d0(0, 0xae, 6, 1);
4389 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4390 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004391 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4392 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004393 MCHBAR32_AND(0x140, ~0x07000000);
4394 MCHBAR32_AND(0x138, ~0x07000000);
4395 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004396 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004397 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004398 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004399
4400 {
4401 u32 t;
4402 u8 val_a1;
4403 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4404 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4405 rmw_1d0(0x320, 0x07,
4406 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4407 rmw_1d0(0x14b, 0x78,
4408 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4409 4), 7,
4410 1);
4411 rmw_1d0(0xce, 0x38,
4412 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4413 4), 6,
4414 1);
4415 }
4416
4417 for (channel = 0; channel < NUM_CHANNELS; channel++)
4418 set_4cf(&info, channel,
4419 info.populated_ranks[channel][0][0] ? 9 : 1);
4420
4421 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004422 MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004423 write_1d0(2, 0xae, 6, 1);
4424 write_1d0(2, 0x300, 6, 1);
4425 write_1d0(2, 0x121, 3, 1);
4426 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4427 write_1d0(4, 0xd6, 6, 1);
4428 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4429 write_1d0(4, 0x328, 6, 1);
4430
4431 for (channel = 0; channel < NUM_CHANNELS; channel++)
4432 set_4cf(&info, channel,
4433 info.populated_ranks[channel][0][0] ? 9 : 0);
4434
Felix Held04be2dd2018-07-29 04:53:22 +02004435 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4436 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004437 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004438 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004439 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4440 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4441 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4442 write_1d0(0, 0x21c, 6, 1);
4443 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4444 write_1d0(0x35, 0x14b, 7, 1);
4445
4446 for (channel = 0; channel < NUM_CHANNELS; channel++)
4447 set_4cf(&info, channel,
4448 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4449
4450 set_334(1);
4451
Felix Held04be2dd2018-07-29 04:53:22 +02004452 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004453
4454 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4455 write_500(&info, channel,
4456 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4457 1);
4458 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4459 }
Felix Held04be2dd2018-07-29 04:53:22 +02004460 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4461 MCHBAR16(0x6c0) = 0x14a0;
4462 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4463 MCHBAR16(0x232) = 0x8;
4464 /* 0x40004 or 0 depending on ? */
4465 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4466 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4467 MCHBAR32(0x128) = 0x2150d05;
4468 MCHBAR8(0x12c) = 0x1f;
4469 MCHBAR8(0x12d) = 0x56;
4470 MCHBAR8(0x12e) = 0x31;
4471 MCHBAR8(0x12f) = 0x0;
4472 MCHBAR8(0x271) = 0x2;
4473 MCHBAR8(0x671) = 0x2;
4474 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004475 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004476 MCHBAR32(0x294 + (channel << 10)) =
4477 (info.populated_ranks_mask[channel] & 3) << 16;
4478 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4479 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004480 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004481 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4482 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004483
4484 if (!s3resume)
4485 jedec_init(&info);
4486
4487 int totalrank = 0;
4488 for (channel = 0; channel < NUM_CHANNELS; channel++)
4489 for (slot = 0; slot < NUM_SLOTS; slot++)
4490 for (rank = 0; rank < NUM_RANKS; rank++)
4491 if (info.populated_ranks[channel][slot][rank]) {
4492 jedec_read(&info, channel, slot, rank,
4493 totalrank, 0xa, 0x400);
4494 totalrank++;
4495 }
4496
Felix Held04be2dd2018-07-29 04:53:22 +02004497 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004498
Felix Heldf83d80b2018-07-29 05:30:30 +02004499 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4500 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004501
4502 if (!s3resume) {
4503 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004504 MCHBAR32(0x294 + (channel << 10)) =
4505 (info.populated_ranks_mask[channel] & 3) << 16;
4506 MCHBAR16(0x298 + (channel << 10)) =
4507 info.populated_ranks[channel][0][0] |
4508 (info.populated_ranks[channel][0][1] << 5);
4509 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004510 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004511 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004512
4513 {
4514 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004515 a = MCHBAR8(0x243);
4516 b = MCHBAR8(0x643);
4517 MCHBAR8(0x243) = a | 2;
4518 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004519 }
4520
4521 write_1d0(7, 0x19b, 3, 1);
4522 write_1d0(7, 0x1c0, 3, 1);
4523 write_1d0(4, 0x1c6, 4, 1);
4524 write_1d0(4, 0x1cc, 4, 1);
4525 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4526 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004527 MCHBAR32(0x584) = 0xfffff;
4528 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004529
4530 for (channel = 0; channel < NUM_CHANNELS; channel++)
4531 for (slot = 0; slot < NUM_SLOTS; slot++)
4532 for (rank = 0; rank < NUM_RANKS; rank++)
4533 if (info.
4534 populated_ranks[channel][slot]
4535 [rank])
4536 config_rank(&info, s3resume,
4537 channel, slot,
4538 rank);
4539
Felix Held04be2dd2018-07-29 04:53:22 +02004540 MCHBAR8(0x243) = 0x1;
4541 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004542 }
4543
4544 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004545 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004546 write_26c(0, 0x820);
4547 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004548 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004549 /* end */
4550
4551 if (s3resume) {
4552 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004553 MCHBAR32(0x294 + (channel << 10)) =
4554 (info.populated_ranks_mask[channel] & 3) << 16;
4555 MCHBAR16(0x298 + (channel << 10)) =
4556 info.populated_ranks[channel][0][0] |
4557 (info.populated_ranks[channel][0][1] << 5);
4558 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004559 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004560 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004561 }
4562
Felix Held04be2dd2018-07-29 04:53:22 +02004563 MCHBAR32_AND(0xfa4, ~0x01000002);
4564 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004565
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004566 /* Before training. */
4567 timestamp_add_now(103);
4568
4569 if (!s3resume)
4570 ram_training(&info);
4571
4572 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004573 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004574
4575 dump_timings(&info);
4576
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004577 program_modules_memory_map(&info, 0);
4578 program_total_memory_map(&info);
4579
4580 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004581 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004582 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004583 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004584 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004585 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004586 else
Felix Held04be2dd2018-07-29 04:53:22 +02004587 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004588
Felix Held04be2dd2018-07-29 04:53:22 +02004589 MCHBAR32_AND(0xfac, ~0x80000000);
4590 MCHBAR32(0xfb4) = 0x4800;
4591 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4592 MCHBAR32(0xe94) = 0x7ffff;
4593 MCHBAR32(0xfc0) = 0x80002040;
4594 MCHBAR32(0xfc4) = 0x701246;
4595 MCHBAR8_AND(0xfc8, ~0x70);
4596 MCHBAR32_OR(0xe5c, 0x1000000);
4597 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4598 MCHBAR32(0x50) = 0x700b0;
4599 MCHBAR32(0x3c) = 0x10;
4600 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4601 MCHBAR8_OR(0xff4, 0x2);
4602 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004603
Felix Held29a9c072018-07-29 01:34:45 +02004604#if 1
Felix Held04be2dd2018-07-29 04:53:22 +02004605 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4606 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4607 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004608
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004609 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4610 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4611 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004612
4613#else
4614 {
4615 u32 eax;
Felix Held04be2dd2018-07-29 04:53:22 +02004616 // = 0xe911714b
4617 eax = read32p(0xffc + (MCHBAR32(0xd00) & ~1)) | 0x08000000;
4618 write32p(0xffc + (MCHBAR32(0xd00) & ~1), eax);
4619 // = 0xe911714b
4620 eax = read32p(0xffc + (MCHBAR32(0xdc0) & ~1)) | 0x40000000;
4621 write32p(0xffc + (MCHBAR32(0xdc0) & ~1), eax);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004622 }
4623#endif
4624
4625 {
4626 u32 eax;
4627
4628 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004629 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4630 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4631 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004632 }
4633
4634 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004635 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004636 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004637 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004638 else
Felix Held04be2dd2018-07-29 04:53:22 +02004639 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004640
Felix Held04be2dd2018-07-29 04:53:22 +02004641 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004642
Felix Held04be2dd2018-07-29 04:53:22 +02004643 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004644 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004645 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004646 else
Felix Held04be2dd2018-07-29 04:53:22 +02004647 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004648 }
4649
Felix Held04be2dd2018-07-29 04:53:22 +02004650 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004651
4652 {
4653 u8 al;
4654 al = 0xd;
4655 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4656 al += 2;
4657 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004658 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004659 }
4660
4661 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004662 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4663 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4664 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4665 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004666 }
4667 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004668 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004669 reg1c = read32p(DEFAULT_EPBAR | 0x01c); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004670 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004671 write32p(DEFAULT_EPBAR | 0x01c, reg1c); // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004672 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004673 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004674 MCHBAR8_OR(0x1210, 2);
4675 MCHBAR32(0x1200) = 0x8800440;
4676 MCHBAR32(0x1204) = 0x53ff0453;
4677 MCHBAR32(0x1208) = 0x19002043;
4678 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004679
4680 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004681 MCHBAR16(0x1214) = 0x220;
4682 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004683 }
4684
Felix Held04be2dd2018-07-29 04:53:22 +02004685 MCHBAR8_OR(0x1214, 0x4);
4686 MCHBAR8(0x120c) = 0x1;
4687 MCHBAR8(0x1218) = 0x3;
4688 MCHBAR8(0x121a) = 0x3;
4689 MCHBAR8(0x121c) = 0x3;
4690 MCHBAR16(0xc14) = 0x0;
4691 MCHBAR16(0xc20) = 0x0;
4692 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004693
4694 /* revision dependent here. */
4695
Felix Held04be2dd2018-07-29 04:53:22 +02004696 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004697
4698 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004699 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004700
Felix Held04be2dd2018-07-29 04:53:22 +02004701 MCHBAR16_OR(0x1230, 0x8000);
4702 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004703
4704 u8 bl, ebpb;
4705 u16 reg_1020;
4706
Felix Held04be2dd2018-07-29 04:53:22 +02004707 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4708 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004709
Felix Held04be2dd2018-07-29 04:53:22 +02004710 MCHBAR32(0x1000) = 0x100;
4711 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004712
4713 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004714 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004715 bl = reg_1020 >> 8;
4716 ebpb = reg_1020 & 0xff;
4717 } else {
4718 ebpb = 0;
4719 bl = 8;
4720 }
4721
4722 rdmsr(0x1a2);
4723
Felix Held04be2dd2018-07-29 04:53:22 +02004724 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004725
Felix Held04be2dd2018-07-29 04:53:22 +02004726 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004727
Felix Held04be2dd2018-07-29 04:53:22 +02004728 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004729
Felix Held04be2dd2018-07-29 04:53:22 +02004730 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004731 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004732 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4733 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004734 }
4735
4736 setup_heci_uma(&info);
4737
4738 if (info.uma_enabled) {
4739 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004740 MCHBAR32_OR(0x11b0, 0x4000);
4741 MCHBAR32_OR(0x11b4, 0x4000);
4742 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004743
Felix Held04be2dd2018-07-29 04:53:22 +02004744 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4745 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4746 MCHBAR16_OR(0x1170, 0x1000);
4747
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004748 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004749
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004750 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004751 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004752 ;
4753 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004754 }
4755
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004756 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4757 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004758 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004759 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004760
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004761 udelay(1000);
4762 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004763 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4764
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004765 if (!s3resume)
4766 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004767 if (s3resume && cbmem_wasnot_inited) {
4768 u32 reg32;
4769 printk(BIOS_ERR, "Failed S3 resume.\n");
4770 ram_check(0x100000, 0x200000);
4771
4772 /* Clear SLP_TYPE. */
4773 reg32 = inl(DEFAULT_PMBASE + 0x04);
4774 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4775
4776 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004777 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004778 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004779}