blob: 46189117a7317b93a229d0ef4e01fd6b0bf20b1d [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
Kyösti Mälkki931c1dc2014-06-30 09:40:19 +030017#include <stdlib.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010018#include <console/console.h>
19#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 <arch/cbfs.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010027#include <ip_checksum.h>
28#include <pc80/mc146818rtc.h>
29#include <device/pci_def.h>
Patrick Rudolph266a1f72016-06-09 18:13:34 +020030#include <device/device.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010031#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010032#include <spd.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010033#include <timestamp.h>
34#include <cpu/x86/mtrr.h>
35#include <cpu/intel/speedstep.h>
36#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010037#include <mrc_cache.h>
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020038#include <southbridge/intel/ibexpeak/me.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];
209 unsigned total_memory_mb;
210 unsigned interleaved_part_mb;
211 unsigned non_interleaved_part_mb;
212
213 u32 heci_bar;
214 u64 heci_uma_addr;
215 unsigned memory_reserved_for_heci_mb;
216
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{
551 unsigned cycletime;
552 unsigned cas_latency_time;
553 unsigned supported_cas_latencies;
554 unsigned channel, slot;
555 unsigned clock_speed_index;
556 unsigned min_cas_latency;
557 unsigned cas_latency;
558 unsigned max_clock_index;
559
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
573 max_clock_index = min(3, info->max_supported_clock_speed_index);
574
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]) {
581 unsigned timebase;
582 timebase =
583 1000 *
584 info->
585 spd[channel][slot][TIMEBASE_DIVIDEND] /
586 info->spd[channel][slot][TIMEBASE_DIVISOR];
587 cycletime =
588 max(cycletime,
589 timebase *
590 info->spd[channel][slot][CYCLETIME]);
591 cas_latency_time =
592 max(cas_latency_time,
593 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{
629 unsigned channel;
630 unsigned slot, rank, lane;
631 unsigned extended_silicon_revision;
632 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. */
792static unsigned frequency_11(struct raminfo *info)
793{
794 return (info->clock_speed_index + 3) * 120;
795}
796
797/* Frequency in 0.1 MHz units. */
798static unsigned frequency_01(struct raminfo *info)
799{
800 return 100 * frequency_11(info) / 9;
801}
802
803static unsigned ps_to_halfcycles(struct raminfo *info, unsigned int ps)
804{
805 return (frequency_11(info) * 2) * ps / 900000;
806}
807
808static unsigned ns_to_cycles(struct raminfo *info, unsigned int ns)
809{
810 return (frequency_11(info)) * ns / 900;
811}
812
813static void compute_derived_timings(struct raminfo *info)
814{
815 unsigned channel, slot, rank;
816 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;
822 int some_delay_3_halfcycles;
823 int some_delay_3_ps_rounded;
824 int some_delay_1_cycle_ceil;
825 int some_delay_1_cycle_floor;
826
827 some_delay_3_halfcycles = 0;
828 some_delay_3_ps_rounded = 0;
829 extended_silicon_revision = info->silicon_revision;
830 if (!info->silicon_revision)
831 for (channel = 0; channel < NUM_CHANNELS; channel++)
832 for (slot = 0; slot < NUM_SLOTS; slot++)
833 if ((info->
834 spd[channel][slot][MODULE_TYPE] & 0xF) ==
835 3)
836 extended_silicon_revision = 4;
837 if (info->board_lane_delay[7] < 5)
838 info->board_lane_delay[7] = 5;
839 info->revision_flag_1 = 2;
840 if (info->silicon_revision == 2 || info->silicon_revision == 3)
841 info->revision_flag_1 = 0;
842 if (info->revision < 16)
843 info->revision_flag_1 = 0;
844
845 if (info->revision < 8)
846 info->revision_flag_1 = 0;
847 if (info->revision >= 8 && (info->silicon_revision == 0
848 || info->silicon_revision == 1))
849 some_delay_2_ps = 735;
850 else
851 some_delay_2_ps = 750;
852
853 if (info->revision >= 0x10 && (info->silicon_revision == 0
854 || info->silicon_revision == 1))
855 some_delay_1_ps = 3929;
856 else
857 some_delay_1_ps = 3490;
858
859 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
860 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
861 if (some_delay_1_ps % cycle_ps(info))
862 some_delay_1_cycle_ceil++;
863 else
864 some_delay_1_cycle_floor--;
865 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
866 if (info->revision_flag_1)
867 some_delay_2_ps = halfcycle_ps(info) >> 6;
868 some_delay_2_ps +=
869 max(some_delay_1_ps - 30,
870 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
871 375;
872 some_delay_3_ps =
873 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
874 if (info->revision_flag_1) {
875 if (some_delay_3_ps < 150)
876 some_delay_3_halfcycles = 0;
877 else
878 some_delay_3_halfcycles =
879 (some_delay_3_ps << 6) / halfcycle_ps(info);
880 some_delay_3_ps_rounded =
881 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
882 }
883 some_delay_2_halfcycles_ceil =
884 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
885 2 * (some_delay_1_cycle_ceil - 1);
886 if (info->revision_flag_1 && some_delay_3_ps < 150)
887 some_delay_2_halfcycles_ceil++;
888 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
889 if (info->revision < 0x10)
890 some_delay_2_halfcycles_floor =
891 some_delay_2_halfcycles_ceil - 1;
892 if (!info->revision_flag_1)
893 some_delay_2_halfcycles_floor++;
894 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
895 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
896 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
897 || (info->populated_ranks[1][0][0]
898 && info->populated_ranks[1][1][0]))
899 info->max_slots_used_in_channel = 2;
900 else
901 info->max_slots_used_in_channel = 1;
902 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200903 MCHBAR32(0x244 + (channel << 10)) =
904 ((info->revision < 8) ? 1 : 0x200) |
905 ((2 - info->max_slots_used_in_channel) << 17) |
906 (channel << 21) |
907 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100908 if (info->max_slots_used_in_channel == 1) {
909 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
910 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
911 } else {
912 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 */
913 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
914 || (count_ranks_in_channel(info, 1) ==
915 2)) ? 2 : 3;
916 }
917 for (channel = 0; channel < NUM_CHANNELS; channel++) {
918 int max_of_unk;
919 int min_of_unk_2;
920
921 int i, count;
922 int sum;
923
924 if (!info->populated_ranks_mask[channel])
925 continue;
926
927 max_of_unk = 0;
928 min_of_unk_2 = 32767;
929
930 sum = 0;
931 count = 0;
932 for (i = 0; i < 3; i++) {
933 int unk1;
934 if (info->revision < 8)
935 unk1 =
936 u8_FFFD1891[0][channel][info->
937 clock_speed_index]
938 [i];
939 else if (!
940 (info->revision >= 0x10
941 || info->revision_flag_1))
942 unk1 =
943 u8_FFFD1891[1][channel][info->
944 clock_speed_index]
945 [i];
946 else
947 unk1 = 0;
948 for (slot = 0; slot < NUM_SLOTS; slot++)
949 for (rank = 0; rank < NUM_RANKS; rank++) {
950 int a = 0;
951 int b = 0;
952
953 if (!info->
954 populated_ranks[channel][slot]
955 [rank])
956 continue;
957 if (extended_silicon_revision == 4
958 && (info->
959 populated_ranks_mask[channel] &
960 5) != 5) {
961 if ((info->
962 spd[channel][slot]
963 [REFERENCE_RAW_CARD_USED] &
964 0x1F) == 3) {
965 a = u16_ffd1178[0]
966 [info->
967 clock_speed_index];
968 b = u16_fe0eb8[0][info->
969 clock_speed_index];
970 } else
971 if ((info->
972 spd[channel][slot]
973 [REFERENCE_RAW_CARD_USED]
974 & 0x1F) == 5) {
975 a = u16_ffd1178[1]
976 [info->
977 clock_speed_index];
978 b = u16_fe0eb8[1][info->
979 clock_speed_index];
980 }
981 }
982 min_of_unk_2 = min(min_of_unk_2, a);
983 min_of_unk_2 = min(min_of_unk_2, b);
984 if (rank == 0) {
985 sum += a;
986 count++;
987 }
988 {
989 int t;
990 t = b +
991 u8_FFFD0EF8[channel]
992 [extended_silicon_revision]
993 [info->
994 mode4030[channel]][info->
995 clock_speed_index];
996 if (unk1 >= t)
997 max_of_unk =
998 max(max_of_unk,
999 unk1 - t);
1000 }
1001 }
1002 {
1003 int t =
1004 u8_FFFD17E0[channel]
1005 [extended_silicon_revision][info->
1006 mode4030
1007 [channel]]
1008 [info->clock_speed_index] + min_of_unk_2;
1009 if (unk1 >= t)
1010 max_of_unk = max(max_of_unk, unk1 - t);
1011 }
1012 }
1013
Jacob Garber64fb4a32019-06-10 17:29:18 -06001014 if (count == 0)
1015 die("No memory ranks found for channel %u\n", channel);
1016
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001017 info->avg4044[channel] = sum / count;
1018 info->max4048[channel] = max_of_unk;
1019 }
1020}
1021
1022static void jedec_read(struct raminfo *info,
1023 int channel, int slot, int rank,
1024 int total_rank, u8 addr3, unsigned int value)
1025{
1026 /* Handle mirrored mapping. */
1027 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001028 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1029 ((addr3 >> 1) & 0x10);
1030 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1031 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001032
1033 /* Handle mirrored mapping. */
1034 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1035 value =
1036 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1037 << 1);
1038
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001039 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001040
Felix Held04be2dd2018-07-29 04:53:22 +02001041 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1042 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001043
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001044 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001045}
1046
1047enum {
1048 MR1_RZQ12 = 512,
1049 MR1_RZQ2 = 64,
1050 MR1_RZQ4 = 4,
1051 MR1_ODS34OHM = 2
1052};
1053
1054enum {
1055 MR0_BT_INTERLEAVED = 8,
1056 MR0_DLL_RESET_ON = 256
1057};
1058
1059enum {
1060 MR2_RTT_WR_DISABLED = 0,
1061 MR2_RZQ2 = 1 << 10
1062};
1063
1064static void jedec_init(struct raminfo *info)
1065{
1066 int write_recovery;
1067 int channel, slot, rank;
1068 int total_rank;
1069 int dll_on;
1070 int self_refresh_temperature;
1071 int auto_self_refresh;
1072
1073 auto_self_refresh = 1;
1074 self_refresh_temperature = 1;
1075 if (info->board_lane_delay[3] <= 10) {
1076 if (info->board_lane_delay[3] <= 8)
1077 write_recovery = info->board_lane_delay[3] - 4;
1078 else
1079 write_recovery = 5;
1080 } else {
1081 write_recovery = 6;
1082 }
1083 FOR_POPULATED_RANKS {
1084 auto_self_refresh &=
1085 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1086 self_refresh_temperature &=
1087 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1088 }
1089 if (auto_self_refresh == 1)
1090 self_refresh_temperature = 0;
1091
1092 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1093 || (info->populated_ranks[0][0][0]
1094 && info->populated_ranks[0][1][0])
1095 || (info->populated_ranks[1][0][0]
1096 && info->populated_ranks[1][1][0]));
1097
1098 total_rank = 0;
1099
1100 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1101 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1102 int rzq_reg58e;
1103
1104 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1105 rzq_reg58e = 64;
1106 rtt = MR1_RZQ2;
1107 if (info->clock_speed_index != 0) {
1108 rzq_reg58e = 4;
1109 if (info->populated_ranks_mask[channel] == 3)
1110 rtt = MR1_RZQ4;
1111 }
1112 } else {
1113 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1114 rtt = MR1_RZQ12;
1115 rzq_reg58e = 64;
1116 rtt_wr = MR2_RZQ2;
1117 } else {
1118 rzq_reg58e = 4;
1119 rtt = MR1_RZQ4;
1120 }
1121 }
1122
Felix Held04be2dd2018-07-29 04:53:22 +02001123 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1124 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1125 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1126 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1127 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001128
1129 for (slot = 0; slot < NUM_SLOTS; slot++)
1130 for (rank = 0; rank < NUM_RANKS; rank++)
1131 if (info->populated_ranks[channel][slot][rank]) {
1132 jedec_read(info, channel, slot, rank,
1133 total_rank, 0x28,
1134 rtt_wr | (info->
1135 clock_speed_index
1136 << 3)
1137 | (auto_self_refresh << 6) |
1138 (self_refresh_temperature <<
1139 7));
1140 jedec_read(info, channel, slot, rank,
1141 total_rank, 0x38, 0);
1142 jedec_read(info, channel, slot, rank,
1143 total_rank, 0x18,
1144 rtt | MR1_ODS34OHM);
1145 jedec_read(info, channel, slot, rank,
1146 total_rank, 6,
1147 (dll_on << 12) |
1148 (write_recovery << 9)
1149 | ((info->cas_latency - 4) <<
1150 4) | MR0_BT_INTERLEAVED |
1151 MR0_DLL_RESET_ON);
1152 total_rank++;
1153 }
1154 }
1155}
1156
1157static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1158{
1159 unsigned channel, slot, rank;
1160 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1161 unsigned int channel_0_non_interleaved;
1162
1163 FOR_ALL_RANKS {
1164 if (info->populated_ranks[channel][slot][rank]) {
1165 total_mb[channel] +=
1166 pre_jedec ? 256 : (256 << info->
1167 density[channel][slot] >> info->
1168 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001169 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1170 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1171 (info->is_x16_module[channel][slot] |
1172 ((info->density[channel][slot] + 1) << 1))) |
1173 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001174 }
Felix Held04be2dd2018-07-29 04:53:22 +02001175 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1176 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001177 }
1178
1179 info->total_memory_mb = total_mb[0] + total_mb[1];
1180
1181 info->interleaved_part_mb =
1182 pre_jedec ? 0 : 2 * min(total_mb[0], total_mb[1]);
1183 info->non_interleaved_part_mb =
1184 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1185 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001186 MCHBAR32(0x100) = channel_0_non_interleaved |
1187 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001188 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001189 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001190}
1191
1192static void program_board_delay(struct raminfo *info)
1193{
1194 int cas_latency_shift;
1195 int some_delay_ns;
1196 int some_delay_3_half_cycles;
1197
1198 unsigned channel, i;
1199 int high_multiplier;
1200 int lane_3_delay;
1201 int cas_latency_derived;
1202
1203 high_multiplier = 0;
1204 some_delay_ns = 200;
1205 some_delay_3_half_cycles = 4;
1206 cas_latency_shift = info->silicon_revision == 0
1207 || info->silicon_revision == 1 ? 1 : 0;
1208 if (info->revision < 8) {
1209 some_delay_ns = 600;
1210 cas_latency_shift = 0;
1211 }
1212 {
1213 int speed_bit;
1214 speed_bit =
1215 ((info->clock_speed_index > 1
1216 || (info->silicon_revision != 2
1217 && info->silicon_revision != 3))) ^ (info->revision >=
1218 0x10);
1219 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1220 3, 1);
1221 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1222 3, 1);
1223 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1224 && (info->silicon_revision == 2
1225 || info->silicon_revision == 3))
1226 rmw_1d0(0x116, 5, 2, 4, 1);
1227 }
Felix Held04be2dd2018-07-29 04:53:22 +02001228 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1229 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001230
Felix Held04be2dd2018-07-29 04:53:22 +02001231 MCHBAR8(0x124) = info->board_lane_delay[4] +
1232 ((frequency_01(info) + 999) / 1000);
1233 MCHBAR16(0x125) = 0x1360;
1234 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001235 if (info->fsb_frequency < frequency_11(info) / 2) {
1236 unsigned some_delay_2_half_cycles;
1237 high_multiplier = 1;
1238 some_delay_2_half_cycles = ps_to_halfcycles(info,
1239 ((3 *
1240 fsbcycle_ps(info))
1241 >> 1) +
1242 (halfcycle_ps(info)
1243 *
1244 reg178_min[info->
1245 clock_speed_index]
1246 >> 6)
1247 +
1248 4 *
1249 halfcycle_ps(info)
1250 + 2230);
1251 some_delay_3_half_cycles =
1252 min((some_delay_2_half_cycles +
1253 (frequency_11(info) * 2) * (28 -
1254 some_delay_2_half_cycles) /
1255 (frequency_11(info) * 2 -
1256 4 * (info->fsb_frequency))) >> 3, 7);
1257 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001258 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001259 some_delay_3_half_cycles = 3;
1260 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001261 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1262 MCHBAR32(0x224 + (channel << 10)) =
1263 (info->max_slots_used_in_channel - 1) |
1264 ((info->cas_latency - 5 - info->clock_speed_index)
1265 << 21) | ((info->max_slots_used_in_channel +
1266 info->cas_latency - cas_latency_shift - 4) << 16) |
1267 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1268 ((info->cas_latency - info->clock_speed_index +
1269 info->max_slots_used_in_channel - 6) << 8);
1270 MCHBAR32(0x228 + (channel << 10)) =
1271 info->max_slots_used_in_channel;
1272 MCHBAR8(0x239 + (channel << 10)) = 32;
1273 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1274 (some_delay_3_half_cycles << 25) | 0x840000;
1275 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1276 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1277 MCHBAR32(0x24c + (channel << 10)) =
1278 ((!!info->clock_speed_index) << 17) |
1279 (((2 + info->clock_speed_index -
1280 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001281
Felix Held04be2dd2018-07-29 04:53:22 +02001282 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1283 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1284 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001285
1286 write_500(info, channel,
1287 ((!info->populated_ranks[channel][1][1])
1288 | (!info->populated_ranks[channel][1][0] << 1)
1289 | (!info->populated_ranks[channel][0][1] << 2)
1290 | (!info->populated_ranks[channel][0][0] << 3)),
1291 0x4c9, 4, 1);
1292 }
1293
Felix Held22ca8cb2018-07-29 05:09:44 +02001294 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001295 {
1296 u8 freq_divisor = 2;
1297 if (info->fsb_frequency == frequency_11(info))
1298 freq_divisor = 3;
1299 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1300 freq_divisor = 1;
1301 else
1302 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001303 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001304 }
1305
1306 if (info->board_lane_delay[3] <= 10) {
1307 if (info->board_lane_delay[3] <= 8)
1308 lane_3_delay = info->board_lane_delay[3];
1309 else
1310 lane_3_delay = 10;
1311 } else {
1312 lane_3_delay = 12;
1313 }
1314 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1315 if (info->clock_speed_index > 1)
1316 cas_latency_derived++;
1317 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001318 MCHBAR32(0x240 + (channel << 10)) =
1319 ((info->clock_speed_index == 0) * 0x11000) |
1320 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1321 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001322 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1323 0x609, 6, 1);
1324 write_500(info, channel,
1325 info->clock_speed_index + 2 * info->cas_latency - 7,
1326 0x601, 6, 1);
1327
Felix Held04be2dd2018-07-29 04:53:22 +02001328 MCHBAR32(0x250 + (channel << 10)) =
1329 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1330 (info->board_lane_delay[7] << 2) |
1331 (info->board_lane_delay[4] << 16) |
1332 (info->board_lane_delay[1] << 25) |
1333 (info->board_lane_delay[1] << 29) | 1;
1334 MCHBAR32(0x254 + (channel << 10)) =
1335 (info->board_lane_delay[1] >> 3) |
1336 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1337 0x80 | (info->board_lane_delay[6] << 1) |
1338 (info->board_lane_delay[2] << 28) |
1339 (cas_latency_derived << 16) | 0x4700000;
1340 MCHBAR32(0x258 + (channel << 10)) =
1341 ((info->board_lane_delay[5] + info->clock_speed_index +
1342 9) << 12) | ((info->clock_speed_index -
1343 info->cas_latency + 12) << 8) |
1344 (info->board_lane_delay[2] << 17) |
1345 (info->board_lane_delay[4] << 24) | 0x47;
1346 MCHBAR32(0x25c + (channel << 10)) =
1347 (info->board_lane_delay[1] << 1) |
1348 (info->board_lane_delay[0] << 8) | 0x1da50000;
1349 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1350 MCHBAR8(0x5f8 + (channel << 10)) =
1351 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001352 }
1353
1354 program_modules_memory_map(info, 1);
1355
Felix Held04be2dd2018-07-29 04:53:22 +02001356 MCHBAR16(0x610) = (min(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
1357 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1358 MCHBAR16_OR(0x612, 0x100);
1359 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001360 for (i = 0; i < 8; i++) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001361 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0x80 + 4 * i,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001362 (info->total_memory_mb - 64) | !i | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001363 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0xc0 + 4 * i, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001364 }
1365}
1366
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001367#define DEFAULT_PCI_MMIO_SIZE 2048
1368#define HOST_BRIDGE PCI_DEVFN(0, 0)
1369
1370static unsigned int get_mmio_size(void)
1371{
1372 const struct device *dev;
1373 const struct northbridge_intel_nehalem_config *cfg = NULL;
1374
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001375 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001376 if (dev)
1377 cfg = dev->chip_info;
1378
1379 /* If this is zero, it just means devicetree.cb didn't set it */
1380 if (!cfg || cfg->pci_mmio_size == 0)
1381 return DEFAULT_PCI_MMIO_SIZE;
1382 else
1383 return cfg->pci_mmio_size;
1384}
1385
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001386#define BETTER_MEMORY_MAP 0
1387
1388static void program_total_memory_map(struct raminfo *info)
1389{
1390 unsigned int TOM, TOLUD, TOUUD;
1391 unsigned int quickpath_reserved;
1392 unsigned int REMAPbase;
1393 unsigned int uma_base_igd;
1394 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001395 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001396 int memory_remap;
1397 unsigned int memory_map[8];
1398 int i;
1399 unsigned int current_limit;
1400 unsigned int tseg_base;
1401 int uma_size_igd = 0, uma_size_gtt = 0;
1402
1403 memset(memory_map, 0, sizeof(memory_map));
1404
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001405 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001406 u16 t = pci_read_config16(NORTHBRIDGE, D0F0_GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001407 gav(t);
1408 const int uma_sizes_gtt[16] =
1409 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1410 /* Igd memory */
1411 const int uma_sizes_igd[16] = {
1412 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1413 256, 512
1414 };
1415
1416 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1417 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1418 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001419
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001420 mmio_size = get_mmio_size();
1421
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001422 TOM = info->total_memory_mb;
1423 if (TOM == 4096)
1424 TOM = 4032;
1425 TOUUD = ALIGN_DOWN(TOM - info->memory_reserved_for_heci_mb, 64);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001426 TOLUD = ALIGN_DOWN(min(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
Elyes HAOUASa342f392018-10-17 10:56:26 +02001427 , TOUUD), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001428 memory_remap = 0;
1429 if (TOUUD - TOLUD > 64) {
1430 memory_remap = 1;
1431 REMAPbase = max(4096, TOUUD);
1432 TOUUD = TOUUD - TOLUD + 4096;
1433 }
1434 if (TOUUD > 4096)
1435 memory_map[2] = TOUUD | 1;
1436 quickpath_reserved = 0;
1437
Jacob Garber975a7e32019-06-10 16:32:47 -06001438 u32 t = pci_read_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001439
Jacob Garber975a7e32019-06-10 16:32:47 -06001440 gav(t);
1441
1442 if (t & 0x800) {
1443 u32 shift = t >> 20;
1444 if (shift == 0)
1445 die("Quickpath value is 0\n");
1446 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001447 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001448
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001449 if (memory_remap)
1450 TOUUD -= quickpath_reserved;
1451
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001452 uma_base_igd = TOLUD - uma_size_igd;
1453 uma_base_gtt = uma_base_igd - uma_size_gtt;
1454 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1455 if (!memory_remap)
1456 tseg_base -= quickpath_reserved;
1457 tseg_base = ALIGN_DOWN(tseg_base, 8);
1458
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001459 pci_write_config16(NORTHBRIDGE, D0F0_TOLUD, TOLUD << 4);
1460 pci_write_config16(NORTHBRIDGE, D0F0_TOM, TOM >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001461 if (memory_remap) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001462 pci_write_config16(NORTHBRIDGE, D0F0_REMAPBASE, REMAPbase >> 6);
1463 pci_write_config16(NORTHBRIDGE, D0F0_REMAPLIMIT, (TOUUD - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001464 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001465 pci_write_config16(NORTHBRIDGE, D0F0_TOUUD, TOUUD);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001466
1467 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001468 pci_write_config32(NORTHBRIDGE, D0F0_IGD_BASE, uma_base_igd << 20);
1469 pci_write_config32(NORTHBRIDGE, D0F0_GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001470 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001471 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001472
1473 current_limit = 0;
1474 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1475 memory_map[1] = 4096;
1476 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
1477 current_limit = max(current_limit, memory_map[i] & ~1);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001478 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0x80,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001479 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1480 1, 64) | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001481 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0xc0, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001482 }
1483}
1484
1485static void collect_system_info(struct raminfo *info)
1486{
1487 u32 capid0[3];
1488 int i;
1489 unsigned channel;
1490
1491 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001492 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1493 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001494
1495 if (!info->heci_bar)
1496 gav(info->heci_bar =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001497 pci_read_config32(HECIDEV, HECIBAR) & 0xFFFFFFF8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001498 if (!info->memory_reserved_for_heci_mb) {
1499 /* Wait for ME to be ready */
1500 intel_early_me_init();
1501 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1502 }
1503
1504 for (i = 0; i < 3; i++)
1505 gav(capid0[i] =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001506 pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 | (i << 2)));
1507 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001508 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1509
1510 if ((capid0[1] >> 11) & 1)
1511 info->uma_enabled = 0;
1512 else
1513 gav(info->uma_enabled =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001514 pci_read_config8(NORTHBRIDGE, D0F0_DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001515 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1516 info->silicon_revision = 0;
1517
1518 if (capid0[2] & 2) {
1519 info->silicon_revision = 0;
1520 info->max_supported_clock_speed_index = 2;
1521 for (channel = 0; channel < NUM_CHANNELS; channel++)
1522 if (info->populated_ranks[channel][0][0]
1523 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1524 3) {
1525 info->silicon_revision = 2;
1526 info->max_supported_clock_speed_index = 1;
1527 }
1528 } else {
1529 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1530 case 1:
1531 case 2:
1532 info->silicon_revision = 3;
1533 break;
1534 case 3:
1535 info->silicon_revision = 0;
1536 break;
1537 case 0:
1538 info->silicon_revision = 2;
1539 break;
1540 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001541 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001542 case 0x40:
1543 info->silicon_revision = 0;
1544 break;
1545 case 0x48:
1546 info->silicon_revision = 1;
1547 break;
1548 }
1549 }
1550}
1551
1552static void write_training_data(struct raminfo *info)
1553{
1554 int tm, channel, slot, rank, lane;
1555 if (info->revision < 8)
1556 return;
1557
1558 for (tm = 0; tm < 4; tm++)
1559 for (channel = 0; channel < NUM_CHANNELS; channel++)
1560 for (slot = 0; slot < NUM_SLOTS; slot++)
1561 for (rank = 0; rank < NUM_RANKS; rank++)
1562 for (lane = 0; lane < 9; lane++)
1563 write_500(info, channel,
1564 info->
1565 cached_training->
1566 lane_timings[tm]
1567 [channel][slot][rank]
1568 [lane],
1569 get_timing_register_addr
1570 (lane, tm, slot,
1571 rank), 9, 0);
1572 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1573 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1574}
1575
1576static void dump_timings(struct raminfo *info)
1577{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001578 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001579 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001580 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001581 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001582 slot, rank);
1583 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001584 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001585 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001586 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001587 read_500(info, channel,
1588 get_timing_register_addr
1589 (lane, i, slot, rank),
1590 9),
1591 info->training.
1592 lane_timings[i][channel][slot][rank]
1593 [lane]);
1594 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001595 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001596 }
1597 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001598 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001599 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001600 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001601 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001602}
1603
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001604/* Read timings and other registers that need to be restored verbatim and
1605 put them to CBMEM.
1606 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001607static void save_timings(struct raminfo *info)
1608{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001609 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001610 int channel, slot, rank, lane, i;
1611
1612 train = info->training;
1613 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1614 for (i = 0; i < 4; i++)
1615 train.lane_timings[i][channel][slot][rank][lane] =
1616 read_500(info, channel,
1617 get_timing_register_addr(lane, i, slot,
1618 rank), 9);
1619 train.reg_178 = read_1d0(0x178, 7);
1620 train.reg_10b = read_1d0(0x10b, 6);
1621
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001622 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1623 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001624 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001625 train.reg274265[channel][0] = reg32 >> 16;
1626 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001627 train.reg274265[channel][2] =
1628 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001629 }
Felix Held04be2dd2018-07-29 04:53:22 +02001630 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1631 train.reg_6dc = MCHBAR32(0x6dc);
1632 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001633
Arthur Heymansb3282092019-04-14 17:53:28 +02001634 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1635 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001636
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001637 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001638 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1639 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001640}
1641
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001642static const struct ram_training *get_cached_training(void)
1643{
Arthur Heymansdc71e252018-01-29 10:14:48 +01001644 struct region_device rdev;
1645 if (mrc_cache_get_current(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1646 &rdev))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001647 return 0;
Arthur Heymansdc71e252018-01-29 10:14:48 +01001648 return (void *)rdev_mmap_full(&rdev);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001649}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001650
1651/* FIXME: add timeout. */
1652static void wait_heci_ready(void)
1653{
Felix Held04be2dd2018-07-29 04:53:22 +02001654 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1655 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001656 write32((DEFAULT_HECIBAR + 0x4),
1657 (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001658}
1659
1660/* FIXME: add timeout. */
1661static void wait_heci_cb_avail(int len)
1662{
1663 union {
1664 struct mei_csr csr;
1665 u32 raw;
1666 } csr;
1667
Felix Held22ca8cb2018-07-29 05:09:44 +02001668 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1669 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001670
1671 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001672 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001673 while (len >
1674 csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
Felix Held22ca8cb2018-07-29 05:09:44 +02001675 csr.csr.buffer_read_ptr))
1676 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001677}
1678
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001679static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001680{
1681 int len = (head->length + 3) / 4;
1682 int i;
1683
1684 wait_heci_cb_avail(len + 1);
1685
1686 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001687 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001688 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001689 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001690
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001691 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1692 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001693}
1694
1695static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001696send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001697{
1698 struct mei_header head;
1699 int maxlen;
1700
1701 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001702 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001703
1704 while (len) {
1705 int cur = len;
1706 if (cur > maxlen) {
1707 cur = maxlen;
1708 head.is_complete = 0;
1709 } else
1710 head.is_complete = 1;
1711 head.length = cur;
1712 head.reserved = 0;
1713 head.client_address = clientaddress;
1714 head.host_address = hostaddress;
1715 send_heci_packet(&head, (u32 *) msg);
1716 len -= cur;
1717 msg += cur;
1718 }
1719}
1720
1721/* FIXME: Add timeout. */
1722static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001723recv_heci_packet(struct raminfo *info, struct mei_header *head, u32 *packet,
1724 u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001725{
1726 union {
1727 struct mei_csr csr;
1728 u32 raw;
1729 } csr;
1730 int i = 0;
1731
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001732 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001733 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001734 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001735 }
Felix Held04be2dd2018-07-29 04:53:22 +02001736 while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr)
1737 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001738 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001739 if (!head->length) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001740 write32(DEFAULT_HECIBAR + 0x4,
1741 read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001742 *packet_size = 0;
1743 return 0;
1744 }
1745 if (head->length + 4 > 4 * csr.csr.buffer_depth
1746 || head->length > *packet_size) {
1747 *packet_size = 0;
1748 return -1;
1749 }
1750
1751 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001752 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Felix Held22ca8cb2018-07-29 05:09:44 +02001753 while (((head->length + 3) >> 2) >
1754 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr))
1755 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001756
1757 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001758 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001759 *packet_size = head->length;
1760 if (!csr.csr.ready)
1761 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001762 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001763 return 0;
1764}
1765
1766/* FIXME: Add timeout. */
1767static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001768recv_heci_message(struct raminfo *info, u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001769{
1770 struct mei_header head;
1771 int current_position;
1772
1773 current_position = 0;
1774 while (1) {
1775 u32 current_size;
1776 current_size = *message_size - current_position;
1777 if (recv_heci_packet
1778 (info, &head, message + (current_position >> 2),
1779 &current_size) == -1)
1780 break;
1781 if (!current_size)
1782 break;
1783 current_position += current_size;
1784 if (head.is_complete) {
1785 *message_size = current_position;
1786 return 0;
1787 }
1788
1789 if (current_position >= *message_size)
1790 break;
1791 }
1792 *message_size = 0;
1793 return -1;
1794}
1795
1796static void send_heci_uma_message(struct raminfo *info)
1797{
1798 struct uma_reply {
1799 u8 group_id;
1800 u8 command;
1801 u8 reserved;
1802 u8 result;
1803 u8 field2;
1804 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001805 } __packed reply;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001806 struct uma_message {
1807 u8 group_id;
1808 u8 cmd;
1809 u8 reserved;
1810 u8 result;
1811 u32 c2;
1812 u64 heci_uma_addr;
1813 u32 memory_reserved_for_heci_mb;
1814 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001815 } __packed msg = {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001816 0, MKHI_SET_UMA, 0, 0,
1817 0x82,
1818 info->heci_uma_addr, info->memory_reserved_for_heci_mb, 0};
1819 u32 reply_size;
1820
1821 send_heci_message((u8 *) & msg, sizeof(msg), 0, 7);
1822
1823 reply_size = sizeof(reply);
1824 if (recv_heci_message(info, (u32 *) & reply, &reply_size) == -1)
1825 return;
1826
1827 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1828 die("HECI init failed\n");
1829}
1830
1831static void setup_heci_uma(struct raminfo *info)
1832{
1833 u32 reg44;
1834
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001835 reg44 = pci_read_config32(HECIDEV, 0x44); // = 0x80010020
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001836 info->memory_reserved_for_heci_mb = 0;
1837 info->heci_uma_addr = 0;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001838 if (!((reg44 & 0x10000) && !(pci_read_config32(HECIDEV, 0x40) & 0x20)))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001839 return;
1840
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001841 info->heci_bar = pci_read_config32(HECIDEV, 0x10) & 0xFFFFFFF0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001842 info->memory_reserved_for_heci_mb = reg44 & 0x3f;
1843 info->heci_uma_addr =
1844 ((u64)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001845 ((((u64) pci_read_config16(NORTHBRIDGE, D0F0_TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001846 info->memory_reserved_for_heci_mb)) << 20;
1847
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001848 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001849 if (info->memory_reserved_for_heci_mb) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001850 write32(DEFAULT_DMIBAR + 0x14,
1851 read32(DEFAULT_DMIBAR + 0x14) & ~0x80);
1852 write32(DEFAULT_RCBA + 0x14,
1853 read32(DEFAULT_RCBA + 0x14) & ~0x80);
1854 write32(DEFAULT_DMIBAR + 0x20,
1855 read32(DEFAULT_DMIBAR + 0x20) & ~0x80);
1856 write32(DEFAULT_RCBA + 0x20,
1857 read32(DEFAULT_RCBA + 0x20) & ~0x80);
1858 write32(DEFAULT_DMIBAR + 0x2c,
1859 read32(DEFAULT_DMIBAR + 0x2c) & ~0x80);
1860 write32(DEFAULT_RCBA + 0x30,
1861 read32(DEFAULT_RCBA + 0x30) & ~0x80);
1862 write32(DEFAULT_DMIBAR + 0x38,
1863 read32(DEFAULT_DMIBAR + 0x38) & ~0x80);
1864 write32(DEFAULT_RCBA + 0x40,
1865 read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001866
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001867 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
1868 write32(DEFAULT_DMIBAR + 0x38, 0x87000080); // OK
Felix Held04be2dd2018-07-29 04:53:22 +02001869 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
1870 read16(DEFAULT_DMIBAR + 0x3e) & 2)
1871 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001872 }
1873
Felix Held04be2dd2018-07-29 04:53:22 +02001874 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001875
1876 send_heci_uma_message(info);
1877
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001878 pci_write_config32(HECIDEV, 0x10, 0x0);
1879 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001880
1881}
1882
1883static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1884{
1885 int ranks_in_channel;
1886 ranks_in_channel = info->populated_ranks[channel][0][0]
1887 + info->populated_ranks[channel][0][1]
1888 + info->populated_ranks[channel][1][0]
1889 + info->populated_ranks[channel][1][1];
1890
1891 /* empty channel */
1892 if (ranks_in_channel == 0)
1893 return 1;
1894
1895 if (ranks_in_channel != ranks)
1896 return 0;
1897 /* single slot */
1898 if (info->populated_ranks[channel][0][0] !=
1899 info->populated_ranks[channel][1][0])
1900 return 1;
1901 if (info->populated_ranks[channel][0][1] !=
1902 info->populated_ranks[channel][1][1])
1903 return 1;
1904 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1905 return 0;
1906 if (info->density[channel][0] != info->density[channel][1])
1907 return 0;
1908 return 1;
1909}
1910
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001911static void read_4090(struct raminfo *info)
1912{
1913 int i, channel, slot, rank, lane;
1914 for (i = 0; i < 2; i++)
1915 for (slot = 0; slot < NUM_SLOTS; slot++)
1916 for (rank = 0; rank < NUM_RANKS; rank++)
1917 for (lane = 0; lane < 9; lane++)
1918 info->training.
1919 lane_timings[0][i][slot][rank][lane]
1920 = 32;
1921
1922 for (i = 1; i < 4; i++)
1923 for (channel = 0; channel < NUM_CHANNELS; channel++)
1924 for (slot = 0; slot < NUM_SLOTS; slot++)
1925 for (rank = 0; rank < NUM_RANKS; rank++)
1926 for (lane = 0; lane < 9; lane++) {
1927 info->training.
1928 lane_timings[i][channel]
1929 [slot][rank][lane] =
1930 read_500(info, channel,
1931 get_timing_register_addr
1932 (lane, i, slot,
1933 rank), 9)
1934 + (i == 1) * 11; // !!!!
1935 }
1936
1937}
1938
1939static u32 get_etalon2(int flip, u32 addr)
1940{
1941 const u16 invmask[] = {
1942 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1943 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1944 };
1945 u32 ret;
1946 u32 comp4 = addr / 480;
1947 addr %= 480;
1948 u32 comp1 = addr & 0xf;
1949 u32 comp2 = (addr >> 4) & 1;
1950 u32 comp3 = addr >> 5;
1951
1952 if (comp4)
1953 ret = 0x1010101 << (comp4 - 1);
1954 else
1955 ret = 0;
1956 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1957 ret = ~ret;
1958
1959 return ret;
1960}
1961
1962static void disable_cache(void)
1963{
1964 msr_t msr = {.lo = 0, .hi = 0 };
1965
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001966 wrmsr(MTRR_PHYS_BASE(3), msr);
1967 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001968}
1969
1970static void enable_cache(unsigned int base, unsigned int size)
1971{
1972 msr_t msr;
1973 msr.lo = base | MTRR_TYPE_WRPROT;
1974 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001975 wrmsr(MTRR_PHYS_BASE(3), msr);
1976 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001977 & 0xffffffff);
1978 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001979 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001980}
1981
1982static void flush_cache(u32 start, u32 size)
1983{
1984 u32 end;
1985 u32 addr;
1986
1987 end = start + (ALIGN_DOWN(size + 4096, 4096));
1988 for (addr = start; addr < end; addr += 64)
1989 clflush(addr);
1990}
1991
1992static void clear_errors(void)
1993{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001994 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001995}
1996
1997static void write_testing(struct raminfo *info, int totalrank, int flip)
1998{
1999 int nwrites = 0;
2000 /* in 8-byte units. */
2001 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002002 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002003
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002004 base = (u8 *)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002005 for (offset = 0; offset < 9 * 480; offset += 2) {
2006 write32(base + offset * 8, get_etalon2(flip, offset));
2007 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
2008 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
2009 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
2010 nwrites += 4;
2011 if (nwrites >= 320) {
2012 clear_errors();
2013 nwrites = 0;
2014 }
2015 }
2016}
2017
2018static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
2019{
2020 u8 failmask = 0;
2021 int i;
2022 int comp1, comp2, comp3;
2023 u32 failxor[2] = { 0, 0 };
2024
2025 enable_cache((total_rank << 28), 1728 * 5 * 4);
2026
2027 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
2028 for (comp1 = 0; comp1 < 4; comp1++)
2029 for (comp2 = 0; comp2 < 60; comp2++) {
2030 u32 re[4];
2031 u32 curroffset =
2032 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
2033 read128((total_rank << 28) | (curroffset << 3),
2034 (u64 *) re);
2035 failxor[0] |=
2036 get_etalon2(flip, curroffset) ^ re[0];
2037 failxor[1] |=
2038 get_etalon2(flip, curroffset) ^ re[1];
2039 failxor[0] |=
2040 get_etalon2(flip, curroffset | 1) ^ re[2];
2041 failxor[1] |=
2042 get_etalon2(flip, curroffset | 1) ^ re[3];
2043 }
2044 for (i = 0; i < 8; i++)
2045 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2046 failmask |= 1 << i;
2047 }
2048 disable_cache();
2049 flush_cache((total_rank << 28), 1728 * 5 * 4);
2050 return failmask;
2051}
2052
2053const u32 seed1[0x18] = {
2054 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2055 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2056 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2057 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2058 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2059 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2060};
2061
2062static u32 get_seed2(int a, int b)
2063{
2064 const u32 seed2[5] = {
2065 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2066 0x5b6db6db,
2067 };
2068 u32 r;
2069 r = seed2[(a + (a >= 10)) / 5];
2070 return b ? ~r : r;
2071}
2072
2073static int make_shift(int comp2, int comp5, int x)
2074{
2075 const u8 seed3[32] = {
2076 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2077 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2078 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2079 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2080 };
2081
2082 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2083}
2084
2085static u32 get_etalon(int flip, u32 addr)
2086{
2087 u32 mask_byte = 0;
2088 int comp1 = (addr >> 1) & 1;
2089 int comp2 = (addr >> 3) & 0x1f;
2090 int comp3 = (addr >> 8) & 0xf;
2091 int comp4 = (addr >> 12) & 0xf;
2092 int comp5 = (addr >> 16) & 0x1f;
2093 u32 mask_bit = ~(0x10001 << comp3);
2094 u32 part1;
2095 u32 part2;
2096 int byte;
2097
2098 part2 =
2099 ((seed1[comp5] >>
2100 make_shift(comp2, comp5,
2101 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2102 part1 =
2103 ((seed1[comp5] >>
2104 make_shift(comp2, comp5,
2105 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2106
2107 for (byte = 0; byte < 4; byte++)
2108 if ((get_seed2(comp5, comp4) >>
2109 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2110 mask_byte |= 0xff << (8 * byte);
2111
2112 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2113 (comp3 + 16));
2114}
2115
2116static void
2117write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2118 char flip)
2119{
2120 int i;
2121 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002122 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2123 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002124}
2125
2126static u8
2127check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2128 char flip)
2129{
2130 u8 failmask = 0;
2131 u32 failxor[2];
2132 int i;
2133 int comp1, comp2, comp3;
2134
2135 failxor[0] = 0;
2136 failxor[1] = 0;
2137
2138 enable_cache(totalrank << 28, 134217728);
2139 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2140 for (comp1 = 0; comp1 < 16; comp1++)
2141 for (comp2 = 0; comp2 < 64; comp2++) {
2142 u32 addr =
2143 (totalrank << 28) | (region << 25) | (block
2144 << 16)
2145 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2146 2);
2147 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002148 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002149 }
2150 for (i = 0; i < 8; i++)
2151 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2152 failmask |= 1 << i;
2153 }
2154 disable_cache();
2155 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2156 return failmask;
2157}
2158
2159static int check_bounded(unsigned short *vals, u16 bound)
2160{
2161 int i;
2162
2163 for (i = 0; i < 8; i++)
2164 if (vals[i] < bound)
2165 return 0;
2166 return 1;
2167}
2168
2169enum state {
2170 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2171};
2172
2173static int validate_state(enum state *in)
2174{
2175 int i;
2176 for (i = 0; i < 8; i++)
2177 if (in[i] != COMPLETE)
2178 return 0;
2179 return 1;
2180}
2181
2182static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002183do_fsm(enum state *state, u16 *counter,
2184 u8 fail_mask, int margin, int uplimit,
2185 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002186{
2187 int lane;
2188
2189 for (lane = 0; lane < 8; lane++) {
2190 int is_fail = (fail_mask >> lane) & 1;
2191 switch (state[lane]) {
2192 case BEFORE_USABLE:
2193 if (!is_fail) {
2194 counter[lane] = 1;
2195 state[lane] = AT_USABLE;
2196 break;
2197 }
2198 counter[lane] = 0;
2199 state[lane] = BEFORE_USABLE;
2200 break;
2201 case AT_USABLE:
2202 if (!is_fail) {
2203 ++counter[lane];
2204 if (counter[lane] >= margin) {
2205 state[lane] = AT_MARGIN;
2206 res_low[lane] = val - margin + 1;
2207 break;
2208 }
2209 state[lane] = 1;
2210 break;
2211 }
2212 counter[lane] = 0;
2213 state[lane] = BEFORE_USABLE;
2214 break;
2215 case AT_MARGIN:
2216 if (is_fail) {
2217 state[lane] = COMPLETE;
2218 res_high[lane] = val - 1;
2219 } else {
2220 counter[lane]++;
2221 state[lane] = AT_MARGIN;
2222 if (val == uplimit) {
2223 state[lane] = COMPLETE;
2224 res_high[lane] = uplimit;
2225 }
2226 }
2227 break;
2228 case COMPLETE:
2229 break;
2230 }
2231 }
2232}
2233
2234static void
2235train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2236 u8 total_rank, u8 reg_178, int first_run, int niter,
2237 timing_bounds_t * timings)
2238{
2239 int lane;
2240 enum state state[8];
2241 u16 count[8];
2242 u8 lower_usable[8];
2243 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002244 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002245 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002246 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002247
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002248 for (i = 0; i < 8; i++)
2249 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002250
2251 if (!first_run) {
2252 int is_all_ok = 1;
2253 for (lane = 0; lane < 8; lane++)
2254 if (timings[reg_178][channel][slot][rank][lane].
2255 smallest ==
2256 timings[reg_178][channel][slot][rank][lane].
2257 largest) {
2258 timings[reg_178][channel][slot][rank][lane].
2259 smallest = 0;
2260 timings[reg_178][channel][slot][rank][lane].
2261 largest = 0;
2262 is_all_ok = 0;
2263 }
2264 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002265 for (i = 0; i < 8; i++)
2266 state[i] = COMPLETE;
2267 }
2268 }
2269
2270 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2271 u8 failmask = 0;
2272 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2273 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2274 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002275 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002276 do_fsm(state, count, failmask, 5, 47, lower_usable,
2277 upper_usable, reg1b3);
2278 }
2279
2280 if (reg1b3) {
2281 write_1d0(0, 0x1b3, 6, 1);
2282 write_1d0(0, 0x1a3, 6, 1);
2283 for (lane = 0; lane < 8; lane++) {
2284 if (state[lane] == COMPLETE) {
2285 timings[reg_178][channel][slot][rank][lane].
2286 smallest =
2287 lower_usable[lane] +
2288 (info->training.
2289 lane_timings[0][channel][slot][rank][lane]
2290 & 0x3F) - 32;
2291 timings[reg_178][channel][slot][rank][lane].
2292 largest =
2293 upper_usable[lane] +
2294 (info->training.
2295 lane_timings[0][channel][slot][rank][lane]
2296 & 0x3F) - 32;
2297 }
2298 }
2299 }
2300
2301 if (!first_run) {
2302 for (lane = 0; lane < 8; lane++)
2303 if (state[lane] == COMPLETE) {
2304 write_500(info, channel,
2305 timings[reg_178][channel][slot][rank]
2306 [lane].smallest,
2307 get_timing_register_addr(lane, 0,
2308 slot, rank),
2309 9, 1);
2310 write_500(info, channel,
2311 timings[reg_178][channel][slot][rank]
2312 [lane].smallest +
2313 info->training.
2314 lane_timings[1][channel][slot][rank]
2315 [lane]
2316 -
2317 info->training.
2318 lane_timings[0][channel][slot][rank]
2319 [lane], get_timing_register_addr(lane,
2320 1,
2321 slot,
2322 rank),
2323 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002324 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002325 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002326 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002327
2328 do {
2329 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002330 for (i = 0; i < niter; i++) {
2331 if (failmask == 0xFF)
2332 break;
2333 failmask |=
2334 check_testing_type2(info, total_rank, 2, i,
2335 0);
2336 failmask |=
2337 check_testing_type2(info, total_rank, 3, i,
2338 1);
2339 }
Felix Held04be2dd2018-07-29 04:53:22 +02002340 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002341 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002342 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002343 if ((1 << lane) & failmask) {
2344 if (timings[reg_178][channel]
2345 [slot][rank][lane].
2346 largest <=
2347 timings[reg_178][channel]
2348 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002349 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002350 [lane] = -1;
2351 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002352 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002353 [lane] = 0;
2354 timings[reg_178]
2355 [channel][slot]
2356 [rank][lane].
2357 smallest++;
2358 write_500(info, channel,
2359 timings
2360 [reg_178]
2361 [channel]
2362 [slot][rank]
2363 [lane].
2364 smallest,
2365 get_timing_register_addr
2366 (lane, 0,
2367 slot, rank),
2368 9, 1);
2369 write_500(info, channel,
2370 timings
2371 [reg_178]
2372 [channel]
2373 [slot][rank]
2374 [lane].
2375 smallest +
2376 info->
2377 training.
2378 lane_timings
2379 [1][channel]
2380 [slot][rank]
2381 [lane]
2382 -
2383 info->
2384 training.
2385 lane_timings
2386 [0][channel]
2387 [slot][rank]
2388 [lane],
2389 get_timing_register_addr
2390 (lane, 1,
2391 slot, rank),
2392 9, 1);
2393 }
2394 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002395 num_successfully_checked[lane]
2396 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002397 }
2398 }
Felix Held04be2dd2018-07-29 04:53:22 +02002399 while (!check_bounded(num_successfully_checked, 2))
2400 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002401
2402 for (lane = 0; lane < 8; lane++)
2403 if (state[lane] == COMPLETE) {
2404 write_500(info, channel,
2405 timings[reg_178][channel][slot][rank]
2406 [lane].largest,
2407 get_timing_register_addr(lane, 0,
2408 slot, rank),
2409 9, 1);
2410 write_500(info, channel,
2411 timings[reg_178][channel][slot][rank]
2412 [lane].largest +
2413 info->training.
2414 lane_timings[1][channel][slot][rank]
2415 [lane]
2416 -
2417 info->training.
2418 lane_timings[0][channel][slot][rank]
2419 [lane], get_timing_register_addr(lane,
2420 1,
2421 slot,
2422 rank),
2423 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002424 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002425 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002426 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002427
2428 do {
2429 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002430 for (i = 0; i < niter; i++) {
2431 if (failmask == 0xFF)
2432 break;
2433 failmask |=
2434 check_testing_type2(info, total_rank, 2, i,
2435 0);
2436 failmask |=
2437 check_testing_type2(info, total_rank, 3, i,
2438 1);
2439 }
2440
Felix Held04be2dd2018-07-29 04:53:22 +02002441 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002442 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002443 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002444 if ((1 << lane) & failmask) {
2445 if (timings[reg_178][channel]
2446 [slot][rank][lane].
2447 largest <=
2448 timings[reg_178][channel]
2449 [slot][rank][lane].
2450 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002451 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002452 [lane] = -1;
2453 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002454 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002455 [lane] = 0;
2456 timings[reg_178]
2457 [channel][slot]
2458 [rank][lane].
2459 largest--;
2460 write_500(info, channel,
2461 timings
2462 [reg_178]
2463 [channel]
2464 [slot][rank]
2465 [lane].
2466 largest,
2467 get_timing_register_addr
2468 (lane, 0,
2469 slot, rank),
2470 9, 1);
2471 write_500(info, channel,
2472 timings
2473 [reg_178]
2474 [channel]
2475 [slot][rank]
2476 [lane].
2477 largest +
2478 info->
2479 training.
2480 lane_timings
2481 [1][channel]
2482 [slot][rank]
2483 [lane]
2484 -
2485 info->
2486 training.
2487 lane_timings
2488 [0][channel]
2489 [slot][rank]
2490 [lane],
2491 get_timing_register_addr
2492 (lane, 1,
2493 slot, rank),
2494 9, 1);
2495 }
2496 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002497 num_successfully_checked[lane]
2498 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002499 }
2500 }
2501 }
Felix Held04be2dd2018-07-29 04:53:22 +02002502 while (!check_bounded(num_successfully_checked, 3))
2503 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002504
2505 for (lane = 0; lane < 8; lane++) {
2506 write_500(info, channel,
2507 info->training.
2508 lane_timings[0][channel][slot][rank][lane],
2509 get_timing_register_addr(lane, 0, slot, rank),
2510 9, 1);
2511 write_500(info, channel,
2512 info->training.
2513 lane_timings[1][channel][slot][rank][lane],
2514 get_timing_register_addr(lane, 1, slot, rank),
2515 9, 1);
2516 if (timings[reg_178][channel][slot][rank][lane].
2517 largest <=
2518 timings[reg_178][channel][slot][rank][lane].
2519 smallest) {
2520 timings[reg_178][channel][slot][rank][lane].
2521 largest = 0;
2522 timings[reg_178][channel][slot][rank][lane].
2523 smallest = 0;
2524 }
2525 }
2526 }
2527}
2528
2529static void set_10b(struct raminfo *info, u8 val)
2530{
2531 int channel;
2532 int slot, rank;
2533 int lane;
2534
2535 if (read_1d0(0x10b, 6) == val)
2536 return;
2537
2538 write_1d0(val, 0x10b, 6, 1);
2539
2540 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2541 u16 reg_500;
2542 reg_500 = read_500(info, channel,
2543 get_timing_register_addr(lane, 0, slot,
2544 rank), 9);
2545 if (val == 1) {
2546 if (lut16[info->clock_speed_index] <= reg_500)
2547 reg_500 -= lut16[info->clock_speed_index];
2548 else
2549 reg_500 = 0;
2550 } else {
2551 reg_500 += lut16[info->clock_speed_index];
2552 }
2553 write_500(info, channel, reg_500,
2554 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2555 }
2556}
2557
2558static void set_ecc(int onoff)
2559{
2560 int channel;
2561 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2562 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002563 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002564 if (onoff)
2565 t |= 1;
2566 else
2567 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002568 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002569 }
2570}
2571
2572static void set_178(u8 val)
2573{
2574 if (val >= 31)
2575 val = val - 31;
2576 else
2577 val = 63 - val;
2578
2579 write_1d0(2 * val, 0x178, 7, 1);
2580}
2581
2582static void
2583write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2584 int type)
2585{
2586 int lane;
2587
2588 for (lane = 0; lane < 8; lane++)
2589 write_500(info, channel,
2590 info->training.
2591 lane_timings[type][channel][slot][rank][lane],
2592 get_timing_register_addr(lane, type, slot, rank), 9,
2593 0);
2594}
2595
2596static void
2597try_timing_offsets(struct raminfo *info, int channel,
2598 int slot, int rank, int totalrank)
2599{
2600 u16 count[8];
2601 enum state state[8];
2602 u8 lower_usable[8], upper_usable[8];
2603 int lane;
2604 int i;
2605 int flip = 1;
2606 int timing_offset;
2607
2608 for (i = 0; i < 8; i++)
2609 state[i] = BEFORE_USABLE;
2610
2611 memset(count, 0, sizeof(count));
2612
2613 for (lane = 0; lane < 8; lane++)
2614 write_500(info, channel,
2615 info->training.
2616 lane_timings[2][channel][slot][rank][lane] + 32,
2617 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2618
2619 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2620 timing_offset++) {
2621 u8 failmask;
2622 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2623 failmask = 0;
2624 for (i = 0; i < 2 && failmask != 0xff; i++) {
2625 flip = !flip;
2626 write_testing(info, totalrank, flip);
2627 failmask |= check_testing(info, totalrank, flip);
2628 }
2629 do_fsm(state, count, failmask, 10, 63, lower_usable,
2630 upper_usable, timing_offset);
2631 }
2632 write_1d0(0, 0x1bb, 6, 1);
2633 dump_timings(info);
2634 if (!validate_state(state))
2635 die("Couldn't discover DRAM timings (1)\n");
2636
2637 for (lane = 0; lane < 8; lane++) {
2638 u8 bias = 0;
2639
2640 if (info->silicon_revision) {
2641 int usable_length;
2642
2643 usable_length = upper_usable[lane] - lower_usable[lane];
2644 if (usable_length >= 20) {
2645 bias = usable_length / 2 - 10;
2646 if (bias >= 2)
2647 bias = 2;
2648 }
2649 }
2650 write_500(info, channel,
2651 info->training.
2652 lane_timings[2][channel][slot][rank][lane] +
2653 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2654 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2655 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2656 info->training.lane_timings[2][channel][slot][rank][lane] +
2657 lower_usable[lane];
2658 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2659 info->training.lane_timings[2][channel][slot][rank][lane] +
2660 upper_usable[lane];
2661 info->training.timing2_offset[channel][slot][rank][lane] =
2662 info->training.lane_timings[2][channel][slot][rank][lane];
2663 }
2664}
2665
2666static u8
2667choose_training(struct raminfo *info, int channel, int slot, int rank,
2668 int lane, timing_bounds_t * timings, u8 center_178)
2669{
2670 u16 central_weight;
2671 u16 side_weight;
2672 unsigned int sum = 0, count = 0;
2673 u8 span;
2674 u8 lower_margin, upper_margin;
2675 u8 reg_178;
2676 u8 result;
2677
2678 span = 12;
2679 central_weight = 20;
2680 side_weight = 20;
2681 if (info->silicon_revision == 1 && channel == 1) {
2682 central_weight = 5;
2683 side_weight = 20;
2684 if ((info->
2685 populated_ranks_mask[1] ^ (info->
2686 populated_ranks_mask[1] >> 2)) &
2687 1)
2688 span = 18;
2689 }
2690 if ((info->populated_ranks_mask[0] & 5) == 5) {
2691 central_weight = 20;
2692 side_weight = 20;
2693 }
2694 if (info->clock_speed_index >= 2
2695 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2696 if (info->silicon_revision == 1) {
2697 switch (channel) {
2698 case 0:
2699 if (lane == 1) {
2700 central_weight = 10;
2701 side_weight = 20;
2702 }
2703 break;
2704 case 1:
2705 if (lane == 6) {
2706 side_weight = 5;
2707 central_weight = 20;
2708 }
2709 break;
2710 }
2711 }
2712 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2713 side_weight = 5;
2714 central_weight = 20;
2715 }
2716 }
2717 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2718 reg_178 += span) {
2719 u8 smallest;
2720 u8 largest;
2721 largest = timings[reg_178][channel][slot][rank][lane].largest;
2722 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2723 if (largest - smallest + 1 >= 5) {
2724 unsigned int weight;
2725 if (reg_178 == center_178)
2726 weight = central_weight;
2727 else
2728 weight = side_weight;
2729 sum += weight * (largest + smallest);
2730 count += weight;
2731 }
2732 }
2733 dump_timings(info);
2734 if (count == 0)
2735 die("Couldn't discover DRAM timings (2)\n");
2736 result = sum / (2 * count);
2737 lower_margin =
2738 result - timings[center_178][channel][slot][rank][lane].smallest;
2739 upper_margin =
2740 timings[center_178][channel][slot][rank][lane].largest - result;
2741 if (upper_margin < 10 && lower_margin > 10)
2742 result -= min(lower_margin - 10, 10 - upper_margin);
2743 if (upper_margin > 10 && lower_margin < 10)
2744 result += min(upper_margin - 10, 10 - lower_margin);
2745 return result;
2746}
2747
2748#define STANDARD_MIN_MARGIN 5
2749
2750static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2751{
2752 u16 margin[64];
2753 int lane, rank, slot, channel;
2754 u8 reg178;
2755 int count = 0, sum = 0;
2756
2757 for (reg178 = reg178_min[info->clock_speed_index];
2758 reg178 < reg178_max[info->clock_speed_index];
2759 reg178 += reg178_step[info->clock_speed_index]) {
2760 margin[reg178] = -1;
2761 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2762 int curmargin =
2763 timings[reg178][channel][slot][rank][lane].largest -
2764 timings[reg178][channel][slot][rank][lane].
2765 smallest + 1;
2766 if (curmargin < margin[reg178])
2767 margin[reg178] = curmargin;
2768 }
2769 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2770 u16 weight;
2771 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2772 sum += weight * reg178;
2773 count += weight;
2774 }
2775 }
2776 dump_timings(info);
2777 if (count == 0)
2778 die("Couldn't discover DRAM timings (3)\n");
2779
2780 u8 threshold;
2781
2782 for (threshold = 30; threshold >= 5; threshold--) {
2783 int usable_length = 0;
2784 int smallest_fount = 0;
2785 for (reg178 = reg178_min[info->clock_speed_index];
2786 reg178 < reg178_max[info->clock_speed_index];
2787 reg178 += reg178_step[info->clock_speed_index])
2788 if (margin[reg178] >= threshold) {
2789 usable_length +=
2790 reg178_step[info->clock_speed_index];
2791 info->training.reg178_largest =
2792 reg178 -
2793 2 * reg178_step[info->clock_speed_index];
2794
2795 if (!smallest_fount) {
2796 smallest_fount = 1;
2797 info->training.reg178_smallest =
2798 reg178 +
2799 reg178_step[info->
2800 clock_speed_index];
2801 }
2802 }
2803 if (usable_length >= 0x21)
2804 break;
2805 }
2806
2807 return sum / count;
2808}
2809
2810static int check_cached_sanity(struct raminfo *info)
2811{
2812 int lane;
2813 int slot, rank;
2814 int channel;
2815
2816 if (!info->cached_training)
2817 return 0;
2818
2819 for (channel = 0; channel < NUM_CHANNELS; channel++)
2820 for (slot = 0; slot < NUM_SLOTS; slot++)
2821 for (rank = 0; rank < NUM_RANKS; rank++)
2822 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2823 u16 cached_value, estimation_value;
2824 cached_value =
2825 info->cached_training->
2826 lane_timings[1][channel][slot][rank]
2827 [lane];
2828 if (cached_value >= 0x18
2829 && cached_value <= 0x1E7) {
2830 estimation_value =
2831 info->training.
2832 lane_timings[1][channel]
2833 [slot][rank][lane];
2834 if (estimation_value <
2835 cached_value - 24)
2836 return 0;
2837 if (estimation_value >
2838 cached_value + 24)
2839 return 0;
2840 }
2841 }
2842 return 1;
2843}
2844
2845static int try_cached_training(struct raminfo *info)
2846{
2847 u8 saved_243[2];
2848 u8 tm;
2849
2850 int channel, slot, rank, lane;
2851 int flip = 1;
2852 int i, j;
2853
2854 if (!check_cached_sanity(info))
2855 return 0;
2856
2857 info->training.reg178_center = info->cached_training->reg178_center;
2858 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2859 info->training.reg178_largest = info->cached_training->reg178_largest;
2860 memcpy(&info->training.timing_bounds,
2861 &info->cached_training->timing_bounds,
2862 sizeof(info->training.timing_bounds));
2863 memcpy(&info->training.timing_offset,
2864 &info->cached_training->timing_offset,
2865 sizeof(info->training.timing_offset));
2866
2867 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002868 saved_243[0] = MCHBAR8(0x243);
2869 saved_243[1] = MCHBAR8(0x643);
2870 MCHBAR8(0x243) = saved_243[0] | 2;
2871 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002872 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002873 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002874 if (read_1d0(0x10b, 6) & 1)
2875 set_10b(info, 0);
2876 for (tm = 0; tm < 2; tm++) {
2877 int totalrank;
2878
2879 set_178(tm ? info->cached_training->reg178_largest : info->
2880 cached_training->reg178_smallest);
2881
2882 totalrank = 0;
2883 /* Check timing ranges. With i == 0 we check smallest one and with
2884 i == 1 the largest bound. With j == 0 we check that on the bound
2885 it still works whereas with j == 1 we check that just outside of
2886 bound we fail.
2887 */
2888 FOR_POPULATED_RANKS_BACKWARDS {
2889 for (i = 0; i < 2; i++) {
2890 for (lane = 0; lane < 8; lane++) {
2891 write_500(info, channel,
2892 info->cached_training->
2893 timing2_bounds[channel][slot]
2894 [rank][lane][i],
2895 get_timing_register_addr(lane,
2896 3,
2897 slot,
2898 rank),
2899 9, 1);
2900
2901 if (!i)
2902 write_500(info, channel,
2903 info->
2904 cached_training->
2905 timing2_offset
2906 [channel][slot][rank]
2907 [lane],
2908 get_timing_register_addr
2909 (lane, 2, slot, rank),
2910 9, 1);
2911 write_500(info, channel,
2912 i ? info->cached_training->
2913 timing_bounds[tm][channel]
2914 [slot][rank][lane].
2915 largest : info->
2916 cached_training->
2917 timing_bounds[tm][channel]
2918 [slot][rank][lane].smallest,
2919 get_timing_register_addr(lane,
2920 0,
2921 slot,
2922 rank),
2923 9, 1);
2924 write_500(info, channel,
2925 info->cached_training->
2926 timing_offset[channel][slot]
2927 [rank][lane] +
2928 (i ? info->cached_training->
2929 timing_bounds[tm][channel]
2930 [slot][rank][lane].
2931 largest : info->
2932 cached_training->
2933 timing_bounds[tm][channel]
2934 [slot][rank][lane].
2935 smallest) - 64,
2936 get_timing_register_addr(lane,
2937 1,
2938 slot,
2939 rank),
2940 9, 1);
2941 }
2942 for (j = 0; j < 2; j++) {
2943 u8 failmask;
2944 u8 expected_failmask;
2945 char reg1b3;
2946
2947 reg1b3 = (j == 1) + 4;
2948 reg1b3 =
2949 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2950 write_1d0(reg1b3, 0x1bb, 6, 1);
2951 write_1d0(reg1b3, 0x1b3, 6, 1);
2952 write_1d0(reg1b3, 0x1a3, 6, 1);
2953
2954 flip = !flip;
2955 write_testing(info, totalrank, flip);
2956 failmask =
2957 check_testing(info, totalrank,
2958 flip);
2959 expected_failmask =
2960 j == 0 ? 0x00 : 0xff;
2961 if (failmask != expected_failmask)
2962 goto fail;
2963 }
2964 }
2965 totalrank++;
2966 }
2967 }
2968
2969 set_178(info->cached_training->reg178_center);
2970 if (info->use_ecc)
2971 set_ecc(1);
2972 write_training_data(info);
2973 write_1d0(0, 322, 3, 1);
2974 info->training = *info->cached_training;
2975
2976 write_1d0(0, 0x1bb, 6, 1);
2977 write_1d0(0, 0x1b3, 6, 1);
2978 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002979 MCHBAR8(0x243) = saved_243[0];
2980 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002981
2982 return 1;
2983
2984fail:
2985 FOR_POPULATED_RANKS {
2986 write_500_timings_type(info, channel, slot, rank, 1);
2987 write_500_timings_type(info, channel, slot, rank, 2);
2988 write_500_timings_type(info, channel, slot, rank, 3);
2989 }
2990
2991 write_1d0(0, 0x1bb, 6, 1);
2992 write_1d0(0, 0x1b3, 6, 1);
2993 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002994 MCHBAR8(0x243) = saved_243[0];
2995 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002996
2997 return 0;
2998}
2999
3000static void do_ram_training(struct raminfo *info)
3001{
3002 u8 saved_243[2];
3003 int totalrank = 0;
3004 u8 reg_178;
3005 int niter;
3006
Matthias Gazzaridfa51252018-05-19 00:44:20 +02003007 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003008 int lane, rank, slot, channel;
3009 u8 reg178_center;
3010
3011 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003012 saved_243[0] = MCHBAR8(0x243);
3013 saved_243[1] = MCHBAR8(0x643);
3014 MCHBAR8(0x243) = saved_243[0] | 2;
3015 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003016 switch (info->clock_speed_index) {
3017 case 0:
3018 niter = 5;
3019 break;
3020 case 1:
3021 niter = 10;
3022 break;
3023 default:
3024 niter = 19;
3025 break;
3026 }
3027 set_ecc(0);
3028
3029 FOR_POPULATED_RANKS_BACKWARDS {
3030 int i;
3031
3032 write_500_timings_type(info, channel, slot, rank, 0);
3033
3034 write_testing(info, totalrank, 0);
3035 for (i = 0; i < niter; i++) {
3036 write_testing_type2(info, totalrank, 2, i, 0);
3037 write_testing_type2(info, totalrank, 3, i, 1);
3038 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003039 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003040 totalrank++;
3041 }
3042
3043 if (reg178_min[info->clock_speed_index] <
3044 reg178_max[info->clock_speed_index])
3045 memset(timings[reg178_min[info->clock_speed_index]], 0,
3046 sizeof(timings[0]) *
3047 (reg178_max[info->clock_speed_index] -
3048 reg178_min[info->clock_speed_index]));
3049 for (reg_178 = reg178_min[info->clock_speed_index];
3050 reg_178 < reg178_max[info->clock_speed_index];
3051 reg_178 += reg178_step[info->clock_speed_index]) {
3052 totalrank = 0;
3053 set_178(reg_178);
3054 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3055 for (slot = 0; slot < NUM_SLOTS; slot++)
3056 for (rank = 0; rank < NUM_RANKS; rank++) {
3057 memset(&timings[reg_178][channel][slot]
3058 [rank][0].smallest, 0, 16);
3059 if (info->
3060 populated_ranks[channel][slot]
3061 [rank]) {
3062 train_ram_at_178(info, channel,
3063 slot, rank,
3064 totalrank,
3065 reg_178, 1,
3066 niter,
3067 timings);
3068 totalrank++;
3069 }
3070 }
3071 }
3072
3073 reg178_center = choose_reg178(info, timings);
3074
3075 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3076 info->training.timing_bounds[0][channel][slot][rank][lane].
3077 smallest =
3078 timings[info->training.
3079 reg178_smallest][channel][slot][rank][lane].
3080 smallest;
3081 info->training.timing_bounds[0][channel][slot][rank][lane].
3082 largest =
3083 timings[info->training.
3084 reg178_smallest][channel][slot][rank][lane].largest;
3085 info->training.timing_bounds[1][channel][slot][rank][lane].
3086 smallest =
3087 timings[info->training.
3088 reg178_largest][channel][slot][rank][lane].smallest;
3089 info->training.timing_bounds[1][channel][slot][rank][lane].
3090 largest =
3091 timings[info->training.
3092 reg178_largest][channel][slot][rank][lane].largest;
3093 info->training.timing_offset[channel][slot][rank][lane] =
3094 info->training.lane_timings[1][channel][slot][rank][lane]
3095 -
3096 info->training.lane_timings[0][channel][slot][rank][lane] +
3097 64;
3098 }
3099
3100 if (info->silicon_revision == 1
3101 && (info->
3102 populated_ranks_mask[1] ^ (info->
3103 populated_ranks_mask[1] >> 2)) & 1) {
3104 int ranks_after_channel1;
3105
3106 totalrank = 0;
3107 for (reg_178 = reg178_center - 18;
3108 reg_178 <= reg178_center + 18; reg_178 += 18) {
3109 totalrank = 0;
3110 set_178(reg_178);
3111 for (slot = 0; slot < NUM_SLOTS; slot++)
3112 for (rank = 0; rank < NUM_RANKS; rank++) {
3113 if (info->
3114 populated_ranks[1][slot][rank]) {
3115 train_ram_at_178(info, 1, slot,
3116 rank,
3117 totalrank,
3118 reg_178, 0,
3119 niter,
3120 timings);
3121 totalrank++;
3122 }
3123 }
3124 }
3125 ranks_after_channel1 = totalrank;
3126
3127 for (reg_178 = reg178_center - 12;
3128 reg_178 <= reg178_center + 12; reg_178 += 12) {
3129 totalrank = ranks_after_channel1;
3130 set_178(reg_178);
3131 for (slot = 0; slot < NUM_SLOTS; slot++)
3132 for (rank = 0; rank < NUM_RANKS; rank++)
3133 if (info->
3134 populated_ranks[0][slot][rank]) {
3135 train_ram_at_178(info, 0, slot,
3136 rank,
3137 totalrank,
3138 reg_178, 0,
3139 niter,
3140 timings);
3141 totalrank++;
3142 }
3143
3144 }
3145 } else {
3146 for (reg_178 = reg178_center - 12;
3147 reg_178 <= reg178_center + 12; reg_178 += 12) {
3148 totalrank = 0;
3149 set_178(reg_178);
3150 FOR_POPULATED_RANKS_BACKWARDS {
3151 train_ram_at_178(info, channel, slot, rank,
3152 totalrank, reg_178, 0, niter,
3153 timings);
3154 totalrank++;
3155 }
3156 }
3157 }
3158
3159 set_178(reg178_center);
3160 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3161 u16 tm0;
3162
3163 tm0 =
3164 choose_training(info, channel, slot, rank, lane, timings,
3165 reg178_center);
3166 write_500(info, channel, tm0,
3167 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3168 write_500(info, channel,
3169 tm0 +
3170 info->training.
3171 lane_timings[1][channel][slot][rank][lane] -
3172 info->training.
3173 lane_timings[0][channel][slot][rank][lane],
3174 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3175 }
3176
3177 totalrank = 0;
3178 FOR_POPULATED_RANKS_BACKWARDS {
3179 try_timing_offsets(info, channel, slot, rank, totalrank);
3180 totalrank++;
3181 }
Felix Held04be2dd2018-07-29 04:53:22 +02003182 MCHBAR8(0x243) = saved_243[0];
3183 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003184 write_1d0(0, 0x142, 3, 1);
3185 info->training.reg178_center = reg178_center;
3186}
3187
3188static void ram_training(struct raminfo *info)
3189{
3190 u16 saved_fc4;
3191
Felix Held04be2dd2018-07-29 04:53:22 +02003192 saved_fc4 = MCHBAR16(0xfc4);
3193 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003194
3195 if (info->revision >= 8)
3196 read_4090(info);
3197
3198 if (!try_cached_training(info))
3199 do_ram_training(info);
3200 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3201 && info->clock_speed_index < 2)
3202 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003203 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003204}
3205
3206static unsigned gcd(unsigned a, unsigned b)
3207{
3208 unsigned t;
3209 if (a > b) {
3210 t = a;
3211 a = b;
3212 b = t;
3213 }
3214 /* invariant a < b. */
3215 while (a) {
3216 t = b % a;
3217 b = a;
3218 a = t;
3219 }
3220 return b;
3221}
3222
3223static inline int div_roundup(int a, int b)
3224{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003225 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003226}
3227
3228static unsigned lcm(unsigned a, unsigned b)
3229{
3230 return (a * b) / gcd(a, b);
3231}
3232
3233struct stru1 {
3234 u8 freqs_reversed;
3235 u8 freq_diff_reduced;
3236 u8 freq_min_reduced;
3237 u8 divisor_f4_to_fmax;
3238 u8 divisor_f3_to_fmax;
3239 u8 freq4_to_max_remainder;
3240 u8 freq3_to_2_remainder;
3241 u8 freq3_to_2_remaindera;
3242 u8 freq4_to_2_remainder;
3243 int divisor_f3_to_f1, divisor_f4_to_f2;
3244 int common_time_unit_ps;
3245 int freq_max_reduced;
3246};
3247
3248static void
3249compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3250 int num_cycles_2, int num_cycles_1, int round_it,
3251 int add_freqs, struct stru1 *result)
3252{
3253 int g;
3254 int common_time_unit_ps;
3255 int freq1_reduced, freq2_reduced;
3256 int freq_min_reduced;
3257 int freq_max_reduced;
3258 int freq3, freq4;
3259
3260 g = gcd(freq1, freq2);
3261 freq1_reduced = freq1 / g;
3262 freq2_reduced = freq2 / g;
3263 freq_min_reduced = min(freq1_reduced, freq2_reduced);
3264 freq_max_reduced = max(freq1_reduced, freq2_reduced);
3265
3266 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3267 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3268 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3269 if (add_freqs) {
3270 freq3 += freq2_reduced;
3271 freq4 += freq1_reduced;
3272 }
3273
3274 if (round_it) {
3275 result->freq3_to_2_remainder = 0;
3276 result->freq3_to_2_remaindera = 0;
3277 result->freq4_to_max_remainder = 0;
3278 result->divisor_f4_to_f2 = 0;
3279 result->divisor_f3_to_f1 = 0;
3280 } else {
3281 if (freq2_reduced < freq1_reduced) {
3282 result->freq3_to_2_remainder =
3283 result->freq3_to_2_remaindera =
3284 freq3 % freq1_reduced - freq1_reduced + 1;
3285 result->freq4_to_max_remainder =
3286 -(freq4 % freq1_reduced);
3287 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3288 result->divisor_f4_to_f2 =
3289 (freq4 -
3290 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3291 result->freq4_to_2_remainder =
3292 -(char)((freq1_reduced - freq2_reduced) +
3293 ((u8) freq4 -
3294 (freq1_reduced -
3295 freq2_reduced)) % (u8) freq2_reduced);
3296 } else {
3297 if (freq2_reduced > freq1_reduced) {
3298 result->freq4_to_max_remainder =
3299 (freq4 % freq2_reduced) - freq2_reduced + 1;
3300 result->freq4_to_2_remainder =
3301 freq4 % freq_max_reduced -
3302 freq_max_reduced + 1;
3303 } else {
3304 result->freq4_to_max_remainder =
3305 -(freq4 % freq2_reduced);
3306 result->freq4_to_2_remainder =
3307 -(char)(freq4 % freq_max_reduced);
3308 }
3309 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3310 result->divisor_f3_to_f1 =
3311 (freq3 -
3312 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3313 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3314 result->freq3_to_2_remaindera =
3315 -(char)((freq_max_reduced - freq_min_reduced) +
3316 (freq3 -
3317 (freq_max_reduced -
3318 freq_min_reduced)) % freq1_reduced);
3319 }
3320 }
3321 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3322 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3323 if (round_it) {
3324 if (freq2_reduced > freq1_reduced) {
3325 if (freq3 % freq_max_reduced)
3326 result->divisor_f3_to_fmax++;
3327 }
3328 if (freq2_reduced < freq1_reduced) {
3329 if (freq4 % freq_max_reduced)
3330 result->divisor_f4_to_fmax++;
3331 }
3332 }
3333 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3334 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3335 result->freq_min_reduced = freq_min_reduced;
3336 result->common_time_unit_ps = common_time_unit_ps;
3337 result->freq_max_reduced = freq_max_reduced;
3338}
3339
3340static void
3341set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3342 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3343 int num_cycles_4, int reverse)
3344{
3345 struct stru1 vv;
3346 char multiplier;
3347
3348 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3349 0, 1, &vv);
3350
3351 multiplier =
3352 div_roundup(max
3353 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3354 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3355 div_roundup(num_cycles_1,
3356 vv.common_time_unit_ps) +
3357 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3358 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3359
3360 u32 y =
3361 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3362 vv.freq_max_reduced * multiplier)
3363 | (vv.
3364 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3365 multiplier) << 16) | ((u8) (vv.
3366 freq_min_reduced
3367 *
3368 multiplier)
3369 << 24);
3370 u32 x =
3371 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3372 divisor_f3_to_f1
3373 << 16)
3374 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3375 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003376 MCHBAR32(reg) = y;
3377 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003378 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003379 MCHBAR32(reg + 4) = y;
3380 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003381 }
3382}
3383
3384static void
3385set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3386 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3387 int num_cycles_4)
3388{
3389 struct stru1 ratios1;
3390 struct stru1 ratios2;
3391
3392 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3393 0, 1, &ratios2);
3394 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3395 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003396 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003397 ratios1.freq4_to_max_remainder | (ratios2.
3398 freq4_to_max_remainder
3399 << 8)
3400 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3401 divisor_f4_to_fmax
3402 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003403 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3404 (ratios2.freq4_to_max_remainder << 8) |
3405 (ratios1.divisor_f4_to_fmax << 16) |
3406 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003407}
3408
3409static void
3410set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3411 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3412{
3413 struct stru1 ratios;
3414
3415 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3416 round_it, add_freqs, &ratios);
3417 switch (mode) {
3418 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003419 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3420 (ratios.freqs_reversed << 8);
3421 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3422 (ratios.freq4_to_max_remainder << 8) |
3423 (ratios.divisor_f3_to_fmax << 16) |
3424 (ratios.divisor_f4_to_fmax << 20) |
3425 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003426 break;
3427
3428 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003429 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3430 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003431 break;
3432
3433 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003434 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3435 (ratios.freq4_to_max_remainder << 8) |
3436 (ratios.divisor_f3_to_fmax << 16) |
3437 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003438 break;
3439
3440 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003441 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3442 (ratios.divisor_f4_to_fmax << 8) |
3443 (ratios.freqs_reversed << 12) |
3444 (ratios.freq_min_reduced << 16) |
3445 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003446 break;
3447 }
3448}
3449
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003450static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003451{
3452 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3453 0, 1);
3454 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3455 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3456 1);
3457 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3458 frequency_11(info), 1231, 1524, 0, 1);
3459 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3460 frequency_11(info) / 2, 1278, 2008, 0, 1);
3461 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3462 1167, 1539, 0, 1);
3463 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3464 frequency_11(info) / 2, 1403, 1318, 0, 1);
3465 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3466 1);
3467 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3468 1);
3469 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3470 1, 1);
3471 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3472 1);
3473 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3474 frequency_11(info) / 2, 4000, 0, 0, 0);
3475 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3476 frequency_11(info) / 2, 4000, 4000, 0, 0);
3477
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003478 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003479 printk(RAM_SPEW, "[6dc] <= %x\n",
3480 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003481 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003482 } else
3483 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3484 info->delay46_ps[0], 0,
3485 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003486 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3487 frequency_11(info), 2500, 0, 0, 0);
3488 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3489 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003490 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003491 printk(RAM_SPEW, "[6e8] <= %x\n",
3492 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003493 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003494 } else
3495 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3496 info->delay46_ps[1], 0,
3497 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003498 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3499 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3500 470, 0);
3501 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3502 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3503 454, 459, 0);
3504 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3505 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3506 2588, 0);
3507 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3508 2405, 0);
3509 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3510 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3511 480, 0);
3512 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003513 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3514 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003515}
3516
3517static u16 get_max_timing(struct raminfo *info, int channel)
3518{
3519 int slot, rank, lane;
3520 u16 ret = 0;
3521
Felix Held04be2dd2018-07-29 04:53:22 +02003522 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003523 return 384;
3524
3525 if (info->revision < 8)
3526 return 256;
3527
3528 for (slot = 0; slot < NUM_SLOTS; slot++)
3529 for (rank = 0; rank < NUM_RANKS; rank++)
3530 if (info->populated_ranks[channel][slot][rank])
3531 for (lane = 0; lane < 8 + info->use_ecc; lane++)
3532 ret = max(ret, read_500(info, channel,
3533 get_timing_register_addr
3534 (lane, 0, slot,
3535 rank), 9));
3536 return ret;
3537}
3538
3539static void set_274265(struct raminfo *info)
3540{
3541 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3542 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3543 int delay_e_over_cycle_ps;
3544 int cycletime_ps;
3545 int channel;
3546
3547 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003548 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003549 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3550 cycletime_ps =
3551 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3552 delay_d_ps =
3553 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3554 - info->some_delay_3_ps_rounded + 200;
3555 if (!
3556 ((info->silicon_revision == 0
3557 || info->silicon_revision == 1)
3558 && (info->revision >= 8)))
3559 delay_d_ps += halfcycle_ps(info) * 2;
3560 delay_d_ps +=
3561 halfcycle_ps(info) * (!info->revision_flag_1 +
3562 info->some_delay_2_halfcycles_ceil +
3563 2 * info->some_delay_1_cycle_floor +
3564 info->clock_speed_index +
3565 2 * info->cas_latency - 7 + 11);
3566 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3567
Felix Held04be2dd2018-07-29 04:53:22 +02003568 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3569 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3570 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003571 delay_d_ps += 650;
3572 delay_c_ps = delay_d_ps + 1800;
3573 if (delay_c_ps <= delay_a_ps)
3574 delay_e_ps = 0;
3575 else
3576 delay_e_ps =
3577 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3578 cycletime_ps);
3579
3580 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3581 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3582 delay_f_cycles =
3583 div_roundup(2500 - delay_e_over_cycle_ps,
3584 2 * halfcycle_ps(info));
3585 if (delay_f_cycles > delay_e_cycles) {
3586 info->delay46_ps[channel] = delay_e_ps;
3587 delay_e_cycles = 0;
3588 } else {
3589 info->delay46_ps[channel] =
3590 delay_e_over_cycle_ps +
3591 2 * halfcycle_ps(info) * delay_f_cycles;
3592 delay_e_cycles -= delay_f_cycles;
3593 }
3594
3595 if (info->delay46_ps[channel] < 2500) {
3596 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003597 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003598 }
3599 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3600 if (delay_b_ps <= delay_a_ps)
3601 delay_b_ps = 0;
3602 else
3603 delay_b_ps -= delay_a_ps;
3604 info->delay54_ps[channel] =
3605 cycletime_ps * div_roundup(delay_b_ps,
3606 cycletime_ps) -
3607 2 * halfcycle_ps(info) * delay_e_cycles;
3608 if (info->delay54_ps[channel] < 2500)
3609 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003610 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003611 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3612 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003613 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003614 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003615 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003616 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3617 4 * halfcycle_ps(info)) - 6;
3618 MCHBAR32((channel << 10) + 0x274) =
3619 info->training.reg274265[channel][1] |
3620 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003621 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003622 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3623 4 * halfcycle_ps(info)) + 1;
3624 MCHBAR16((channel << 10) + 0x265) =
3625 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003626 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003627 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003628 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003629 else
Felix Held04be2dd2018-07-29 04:53:22 +02003630 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003631}
3632
3633static void restore_274265(struct raminfo *info)
3634{
3635 int channel;
3636
3637 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003638 MCHBAR32((channel << 10) + 0x274) =
3639 (info->cached_training->reg274265[channel][0] << 16) |
3640 info->cached_training->reg274265[channel][1];
3641 MCHBAR16((channel << 10) + 0x265) =
3642 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003643 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003644 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003645 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003646 else
Felix Held04be2dd2018-07-29 04:53:22 +02003647 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003648}
3649
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003650static void dmi_setup(void)
3651{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003652 gav(read8(DEFAULT_DMIBAR + 0x254));
3653 write8(DEFAULT_DMIBAR + 0x254, 0x1);
3654 write16(DEFAULT_DMIBAR + 0x1b8, 0x18f2);
Felix Heldf83d80b2018-07-29 05:30:30 +02003655 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003656
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003657 write32(DEFAULT_DMIBAR + 0xd68, read32(DEFAULT_DMIBAR + 0xd68) | 0x08000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003658
3659 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3660 DEFAULT_GPIOBASE | 0x38);
3661 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3662}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003663
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003664void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003665{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003666 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003667 u16 ggc;
3668 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003669
Felix Held04be2dd2018-07-29 04:53:22 +02003670 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003671 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3672 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003673 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003674 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003675 }
Felix Held29a9c072018-07-29 01:34:45 +02003676#if 0
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003677 if (!s3resume) {
3678 pre_raminit_3(x2ca8);
3679 }
Vladimir Serbinenkof62669c2014-01-09 10:59:38 +01003680 pre_raminit_4a(x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003681#endif
3682
3683 dmi_setup();
3684
Felix Held04be2dd2018-07-29 04:53:22 +02003685 MCHBAR16(0x1170) = 0xa880;
3686 MCHBAR8(0x11c1) = 0x1;
3687 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003688 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003689
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003690 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3691 /* 0 for 32MB */
3692 gfxsize = 0;
3693 }
3694
3695 ggc = 0xb00 | ((gfxsize + 5) << 4);
3696
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003697 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003698
3699 u16 deven;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003700 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003701
3702 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003703 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003704 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003705 MCHBAR16_OR(0x2c30, 0x200);
3706 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003707 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003708 pci_read_config8(GMA, 0x62); // = 0x2
3709 pci_write_config8(GMA, 0x62, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003710 read8(DEFAULT_RCBA + 0x2318);
3711 write8(DEFAULT_RCBA + 0x2318, 0x47);
3712 read8(DEFAULT_RCBA + 0x2320);
3713 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003714 }
3715
Felix Heldf83d80b2018-07-29 05:30:30 +02003716 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003717
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003718 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003719 gav(read32(DEFAULT_RCBA + 0x3428));
3720 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003721}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003722
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003723void raminit(const int s3resume, const u8 *spd_addrmap)
3724{
3725 unsigned channel, slot, lane, rank;
3726 int i;
3727 struct raminfo info;
3728 u8 x2ca8;
3729 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003730 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003731
Felix Held04be2dd2018-07-29 04:53:22 +02003732 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003733
3734 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3735
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003736 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003737
3738 memset(&info, 0x5a, sizeof(info));
3739
3740 info.last_500_command[0] = 0;
3741 info.last_500_command[1] = 0;
3742
3743 info.fsb_frequency = 135 * 2;
3744 info.board_lane_delay[0] = 0x14;
3745 info.board_lane_delay[1] = 0x07;
3746 info.board_lane_delay[2] = 0x07;
3747 info.board_lane_delay[3] = 0x08;
3748 info.board_lane_delay[4] = 0x56;
3749 info.board_lane_delay[5] = 0x04;
3750 info.board_lane_delay[6] = 0x04;
3751 info.board_lane_delay[7] = 0x05;
3752 info.board_lane_delay[8] = 0x10;
3753
3754 info.training.reg_178 = 0;
3755 info.training.reg_10b = 0;
3756
3757 info.heci_bar = 0;
3758 info.memory_reserved_for_heci_mb = 0;
3759
3760 /* before SPD */
3761 timestamp_add_now(101);
3762
Felix Held29a9c072018-07-29 01:34:45 +02003763 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003764 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003765
3766 collect_system_info(&info);
3767
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003768 /* Enable SMBUS. */
3769 enable_smbus();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003770
3771 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3772
3773 info.use_ecc = 1;
3774 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003775 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003776 int v;
3777 int try;
3778 int addr;
3779 const u8 useful_addresses[] = {
3780 DEVICE_TYPE,
3781 MODULE_TYPE,
3782 DENSITY,
3783 RANKS_AND_DQ,
3784 MEMORY_BUS_WIDTH,
3785 TIMEBASE_DIVIDEND,
3786 TIMEBASE_DIVISOR,
3787 CYCLETIME,
3788 CAS_LATENCIES_LSB,
3789 CAS_LATENCIES_MSB,
3790 CAS_LATENCY_TIME,
3791 0x11, 0x12, 0x13, 0x14, 0x15,
3792 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3793 0x1c, 0x1d,
3794 THERMAL_AND_REFRESH,
3795 0x20,
3796 REFERENCE_RAW_CARD_USED,
3797 RANK1_ADDRESS_MAPPING,
3798 0x75, 0x76, 0x77, 0x78,
3799 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3800 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3801 0x85, 0x86, 0x87, 0x88,
3802 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3803 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3804 0x95
3805 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003806 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003807 continue;
3808 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003809 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003810 DEVICE_TYPE);
3811 if (v >= 0)
3812 break;
3813 }
3814 if (v < 0)
3815 continue;
3816 for (addr = 0;
3817 addr <
3818 sizeof(useful_addresses) /
3819 sizeof(useful_addresses[0]); addr++)
3820 gav(info.
3821 spd[channel][0][useful_addresses
3822 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003823 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003824 useful_addresses
3825 [addr]));
3826 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3827 die("Only DDR3 is supported");
3828
3829 v = info.spd[channel][0][RANKS_AND_DQ];
3830 info.populated_ranks[channel][0][0] = 1;
3831 info.populated_ranks[channel][0][1] =
3832 ((v >> 3) & 7);
3833 if (((v >> 3) & 7) > 1)
3834 die("At most 2 ranks are supported");
3835 if ((v & 7) == 0 || (v & 7) > 2)
3836 die("Only x8 and x16 modules are supported");
3837 if ((info.
3838 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3839 && (info.
3840 spd[channel][slot][MODULE_TYPE] & 0xF)
3841 != 3)
3842 die("Registered memory is not supported");
3843 info.is_x16_module[channel][0] = (v & 7) - 1;
3844 info.density[channel][slot] =
3845 info.spd[channel][slot][DENSITY] & 0xF;
3846 if (!
3847 (info.
3848 spd[channel][slot][MEMORY_BUS_WIDTH] &
3849 0x18))
3850 info.use_ecc = 0;
3851 }
3852
3853 gav(0x55);
3854
3855 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3856 int v = 0;
3857 for (slot = 0; slot < NUM_SLOTS; slot++)
3858 for (rank = 0; rank < NUM_RANKS; rank++)
3859 v |= info.
3860 populated_ranks[channel][slot][rank]
3861 << (2 * slot + rank);
3862 info.populated_ranks_mask[channel] = v;
3863 }
3864
3865 gav(0x55);
3866
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003867 gav(pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003868 }
3869
3870 /* after SPD */
3871 timestamp_add_now(102);
3872
Felix Held04be2dd2018-07-29 04:53:22 +02003873 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003874
3875 collect_system_info(&info);
3876 calculate_timings(&info);
3877
Felix Held29a9c072018-07-29 01:34:45 +02003878#if 0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003879 pci_write_config8(NORTHBRIDGE, 0xdf, 0x82);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003880#endif
3881
3882 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003883 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003884 if (x2ca8 == 0 && (reg8 & 0x80)) {
3885 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3886 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3887 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3888 */
3889
3890 /* Clear bit7. */
3891
3892 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3893 (reg8 & ~(1 << 7)));
3894
3895 printk(BIOS_INFO,
3896 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003897 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003898 }
3899 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003900
3901 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003902 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3903 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003904
3905 compute_derived_timings(&info);
3906
3907 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003908 gav(MCHBAR8(0x164));
3909 MCHBAR8(0x164) = 0x26;
3910 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003911 }
3912
Felix Held04be2dd2018-07-29 04:53:22 +02003913 MCHBAR32_OR(0x18b4, 0x210000);
3914 MCHBAR32_OR(0x1890, 0x2000000);
3915 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003916
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003917 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x50)); // !!!!
3918 pci_write_config8(PCI_DEV(0xff, 2, 1), 0x54, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003919
Felix Held04be2dd2018-07-29 04:53:22 +02003920 gav(MCHBAR16(0x2c10));
3921 MCHBAR16(0x2c10) = 0x412;
3922 gav(MCHBAR16(0x2c10));
3923 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003924
Felix Held04be2dd2018-07-29 04:53:22 +02003925 gav(MCHBAR8(0x2ca8)); // !!!!
3926 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003927
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003928 pci_read_config32(PCI_DEV(0xff, 2, 1), 0x6c); // !!!!
3929 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x6c, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003930 gav(MCHBAR32(0x1c04)); // !!!!
3931 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003932
3933 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003934 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003935 }
3936
Felix Held04be2dd2018-07-29 04:53:22 +02003937 MCHBAR32(0x18d8) = 0x120000;
3938 MCHBAR32(0x18dc) = 0x30a484a;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003939 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x0);
3940 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003941 MCHBAR32(0x18d8) = 0x40000;
3942 MCHBAR32(0x18dc) = 0xb000000;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003943 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x60000);
3944 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003945 MCHBAR32(0x18d8) = 0x180000;
3946 MCHBAR32(0x18dc) = 0xc0000142;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003947 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x20000);
3948 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003949 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003950
Felix Held04be2dd2018-07-29 04:53:22 +02003951 gav(MCHBAR32(0x18dc)); // !!!!
3952 MCHBAR32(0x18dc) = 0x3;
3953 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003954
3955 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003956 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003957 }
3958
Felix Held04be2dd2018-07-29 04:53:22 +02003959 MCHBAR32(0x188c) = 0x20bc09;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003960 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xd0, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003961 MCHBAR32(0x1a10) = 0x4200010e;
3962 MCHBAR32_OR(0x18b8, 0x200);
3963 gav(MCHBAR32(0x1918)); // !!!!
3964 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003965
Felix Held04be2dd2018-07-29 04:53:22 +02003966 gav(MCHBAR32(0x18b8)); // !!!!
3967 MCHBAR32(0x18b8) = 0xe00;
3968 gav(MCHBAR32(0x182c)); // !!!!
3969 MCHBAR32(0x182c) = 0x10202;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003970 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x94)); // !!!!
3971 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x94, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003972 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3973 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003974
Felix Held04be2dd2018-07-29 04:53:22 +02003975 MCHBAR32_AND(0x18b4, 0xffff7fff);
3976 gav(MCHBAR32(0x1a68)); // !!!!
3977 MCHBAR32(0x1a68) = 0x343800;
3978 gav(MCHBAR32(0x1e68)); // !!!!
3979 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003980
3981 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003982 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003983 }
3984
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003985 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x048); // !!!!
3986 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x048, 0x140000);
3987 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3988 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x058, 0x64555);
3989 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3990 pci_read_config32(PCI_DEV (0xff, 0, 0), 0xd0); // !!!!
3991 pci_write_config32(PCI_DEV (0xff, 0, 0), 0xd0, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003992 gav(MCHBAR32(0x1af0)); // !!!!
3993 gav(MCHBAR32(0x1af0)); // !!!!
3994 MCHBAR32(0x1af0) = 0x1f020003;
3995 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003996
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003997 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003998 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003999 }
4000
Felix Held04be2dd2018-07-29 04:53:22 +02004001 gav(MCHBAR32(0x1890)); // !!!!
4002 MCHBAR32(0x1890) = 0x80102;
4003 gav(MCHBAR32(0x18b4)); // !!!!
4004 MCHBAR32(0x18b4) = 0x216000;
4005 MCHBAR32(0x18a4) = 0x22222222;
4006 MCHBAR32(0x18a8) = 0x22222222;
4007 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004008
4009 udelay(1000);
4010
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004011 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004012
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004013 if (x2ca8 == 0) {
4014 int j;
4015 if (s3resume && info.cached_training) {
4016 restore_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02004017 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004018 info.cached_training->reg2ca9_bit0);
4019 for (i = 0; i < 2; i++)
4020 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02004021 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004022 i, j, info.cached_training->reg274265[i][j]);
4023 } else {
4024 set_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02004025 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004026 info.training.reg2ca9_bit0);
4027 for (i = 0; i < 2; i++)
4028 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02004029 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004030 i, j, info.training.reg274265[i][j]);
4031 }
4032
4033 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004034
4035 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02004036 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004037 }
4038
4039 udelay(1000);
4040
4041 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02004042 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02004043 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004044 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4045 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4046 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004047
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004048 MCHBAR8(0x1150);
4049 MCHBAR8(0x1151);
4050 MCHBAR8(0x1022);
4051 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004052 MCHBAR32(0x1300) = 0x60606060;
4053 MCHBAR32(0x1304) = 0x60606060;
4054 MCHBAR32(0x1308) = 0x78797a7b;
4055 MCHBAR32(0x130c) = 0x7c7d7e7f;
4056 MCHBAR32(0x1310) = 0x60606060;
4057 MCHBAR32(0x1314) = 0x60606060;
4058 MCHBAR32(0x1318) = 0x60606060;
4059 MCHBAR32(0x131c) = 0x60606060;
4060 MCHBAR32(0x1320) = 0x50515253;
4061 MCHBAR32(0x1324) = 0x54555657;
4062 MCHBAR32(0x1328) = 0x58595a5b;
4063 MCHBAR32(0x132c) = 0x5c5d5e5f;
4064 MCHBAR32(0x1330) = 0x40414243;
4065 MCHBAR32(0x1334) = 0x44454647;
4066 MCHBAR32(0x1338) = 0x48494a4b;
4067 MCHBAR32(0x133c) = 0x4c4d4e4f;
4068 MCHBAR32(0x1340) = 0x30313233;
4069 MCHBAR32(0x1344) = 0x34353637;
4070 MCHBAR32(0x1348) = 0x38393a3b;
4071 MCHBAR32(0x134c) = 0x3c3d3e3f;
4072 MCHBAR32(0x1350) = 0x20212223;
4073 MCHBAR32(0x1354) = 0x24252627;
4074 MCHBAR32(0x1358) = 0x28292a2b;
4075 MCHBAR32(0x135c) = 0x2c2d2e2f;
4076 MCHBAR32(0x1360) = 0x10111213;
4077 MCHBAR32(0x1364) = 0x14151617;
4078 MCHBAR32(0x1368) = 0x18191a1b;
4079 MCHBAR32(0x136c) = 0x1c1d1e1f;
4080 MCHBAR32(0x1370) = 0x10203;
4081 MCHBAR32(0x1374) = 0x4050607;
4082 MCHBAR32(0x1378) = 0x8090a0b;
4083 MCHBAR32(0x137c) = 0xc0d0e0f;
4084 MCHBAR8(0x11cc) = 0x4e;
4085 MCHBAR32(0x1110) = 0x73970404;
4086 MCHBAR32(0x1114) = 0x72960404;
4087 MCHBAR32(0x1118) = 0x6f950404;
4088 MCHBAR32(0x111c) = 0x6d940404;
4089 MCHBAR32(0x1120) = 0x6a930404;
4090 MCHBAR32(0x1124) = 0x68a41404;
4091 MCHBAR32(0x1128) = 0x66a21404;
4092 MCHBAR32(0x112c) = 0x63a01404;
4093 MCHBAR32(0x1130) = 0x609e1404;
4094 MCHBAR32(0x1134) = 0x5f9c1404;
4095 MCHBAR32(0x1138) = 0x5c961404;
4096 MCHBAR32(0x113c) = 0x58a02404;
4097 MCHBAR32(0x1140) = 0x54942404;
4098 MCHBAR32(0x1190) = 0x900080a;
4099 MCHBAR16(0x11c0) = 0xc40b;
4100 MCHBAR16(0x11c2) = 0x303;
4101 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004102 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004103 MCHBAR32(0x11b8) = 0x70c3000;
4104 MCHBAR8(0x11ec) = 0xa;
4105 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004106 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004107 MCHBAR16(0x11ca) = 0xfa;
4108 MCHBAR32(0x11e4) = 0x4e20;
4109 MCHBAR8(0x11bc) = 0xf;
4110 MCHBAR16(0x11da) = 0x19;
4111 MCHBAR16(0x11ba) = 0x470c;
4112 MCHBAR32(0x1680) = 0xe6ffe4ff;
4113 MCHBAR32(0x1684) = 0xdeffdaff;
4114 MCHBAR32(0x1688) = 0xd4ffd0ff;
4115 MCHBAR32(0x168c) = 0xccffc6ff;
4116 MCHBAR32(0x1690) = 0xc0ffbeff;
4117 MCHBAR32(0x1694) = 0xb8ffb0ff;
4118 MCHBAR32(0x1698) = 0xa8ff0000;
4119 MCHBAR32(0x169c) = 0xc00;
4120 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004121 }
4122
Felix Held04be2dd2018-07-29 04:53:22 +02004123 MCHBAR32(0x124c) = 0x15040d00;
4124 MCHBAR32(0x1250) = 0x7f0000;
4125 MCHBAR32(0x1254) = 0x1e220004;
4126 MCHBAR32(0x1258) = 0x4000004;
4127 MCHBAR32(0x1278) = 0x0;
4128 MCHBAR32(0x125c) = 0x0;
4129 MCHBAR32(0x1260) = 0x0;
4130 MCHBAR32(0x1264) = 0x0;
4131 MCHBAR32(0x1268) = 0x0;
4132 MCHBAR32(0x126c) = 0x0;
4133 MCHBAR32(0x1270) = 0x0;
4134 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004135 }
4136
4137 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004138 MCHBAR16(0x1214) = 0x320;
4139 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004140 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4141 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004142 MCHBAR32(0x1400) = 0x13040020;
4143 MCHBAR32(0x1404) = 0xe090120;
4144 MCHBAR32(0x1408) = 0x5120220;
4145 MCHBAR32(0x140c) = 0x5120330;
4146 MCHBAR32(0x1410) = 0xe090220;
4147 MCHBAR32(0x1414) = 0x1010001;
4148 MCHBAR32(0x1418) = 0x1110000;
4149 MCHBAR32(0x141c) = 0x9020020;
4150 MCHBAR32(0x1420) = 0xd090220;
4151 MCHBAR32(0x1424) = 0x2090220;
4152 MCHBAR32(0x1428) = 0x2090330;
4153 MCHBAR32(0x142c) = 0xd090220;
4154 MCHBAR32(0x1430) = 0x1010001;
4155 MCHBAR32(0x1434) = 0x1110000;
4156 MCHBAR32(0x1438) = 0x11040020;
4157 MCHBAR32(0x143c) = 0x4030220;
4158 MCHBAR32(0x1440) = 0x1060220;
4159 MCHBAR32(0x1444) = 0x1060330;
4160 MCHBAR32(0x1448) = 0x4030220;
4161 MCHBAR32(0x144c) = 0x1010001;
4162 MCHBAR32(0x1450) = 0x1110000;
4163 MCHBAR32(0x1454) = 0x4010020;
4164 MCHBAR32(0x1458) = 0xb090220;
4165 MCHBAR32(0x145c) = 0x1090220;
4166 MCHBAR32(0x1460) = 0x1090330;
4167 MCHBAR32(0x1464) = 0xb090220;
4168 MCHBAR32(0x1468) = 0x1010001;
4169 MCHBAR32(0x146c) = 0x1110000;
4170 MCHBAR32(0x1470) = 0xf040020;
4171 MCHBAR32(0x1474) = 0xa090220;
4172 MCHBAR32(0x1478) = 0x1120220;
4173 MCHBAR32(0x147c) = 0x1120330;
4174 MCHBAR32(0x1480) = 0xa090220;
4175 MCHBAR32(0x1484) = 0x1010001;
4176 MCHBAR32(0x1488) = 0x1110000;
4177 MCHBAR32(0x148c) = 0x7020020;
4178 MCHBAR32(0x1490) = 0x1010220;
4179 MCHBAR32(0x1494) = 0x10210;
4180 MCHBAR32(0x1498) = 0x10320;
4181 MCHBAR32(0x149c) = 0x1010220;
4182 MCHBAR32(0x14a0) = 0x1010001;
4183 MCHBAR32(0x14a4) = 0x1110000;
4184 MCHBAR32(0x14a8) = 0xd040020;
4185 MCHBAR32(0x14ac) = 0x8090220;
4186 MCHBAR32(0x14b0) = 0x1111310;
4187 MCHBAR32(0x14b4) = 0x1111420;
4188 MCHBAR32(0x14b8) = 0x8090220;
4189 MCHBAR32(0x14bc) = 0x1010001;
4190 MCHBAR32(0x14c0) = 0x1110000;
4191 MCHBAR32(0x14c4) = 0x3010020;
4192 MCHBAR32(0x14c8) = 0x7090220;
4193 MCHBAR32(0x14cc) = 0x1081310;
4194 MCHBAR32(0x14d0) = 0x1081420;
4195 MCHBAR32(0x14d4) = 0x7090220;
4196 MCHBAR32(0x14d8) = 0x1010001;
4197 MCHBAR32(0x14dc) = 0x1110000;
4198 MCHBAR32(0x14e0) = 0xb040020;
4199 MCHBAR32(0x14e4) = 0x2030220;
4200 MCHBAR32(0x14e8) = 0x1051310;
4201 MCHBAR32(0x14ec) = 0x1051420;
4202 MCHBAR32(0x14f0) = 0x2030220;
4203 MCHBAR32(0x14f4) = 0x1010001;
4204 MCHBAR32(0x14f8) = 0x1110000;
4205 MCHBAR32(0x14fc) = 0x5020020;
4206 MCHBAR32(0x1500) = 0x5090220;
4207 MCHBAR32(0x1504) = 0x2071310;
4208 MCHBAR32(0x1508) = 0x2071420;
4209 MCHBAR32(0x150c) = 0x5090220;
4210 MCHBAR32(0x1510) = 0x1010001;
4211 MCHBAR32(0x1514) = 0x1110000;
4212 MCHBAR32(0x1518) = 0x7040120;
4213 MCHBAR32(0x151c) = 0x2090220;
4214 MCHBAR32(0x1520) = 0x70b1210;
4215 MCHBAR32(0x1524) = 0x70b1310;
4216 MCHBAR32(0x1528) = 0x2090220;
4217 MCHBAR32(0x152c) = 0x1010001;
4218 MCHBAR32(0x1530) = 0x1110000;
4219 MCHBAR32(0x1534) = 0x1010110;
4220 MCHBAR32(0x1538) = 0x1081310;
4221 MCHBAR32(0x153c) = 0x5041200;
4222 MCHBAR32(0x1540) = 0x5041310;
4223 MCHBAR32(0x1544) = 0x1081310;
4224 MCHBAR32(0x1548) = 0x1010001;
4225 MCHBAR32(0x154c) = 0x1110000;
4226 MCHBAR32(0x1550) = 0x1040120;
4227 MCHBAR32(0x1554) = 0x4051210;
4228 MCHBAR32(0x1558) = 0xd051200;
4229 MCHBAR32(0x155c) = 0xd051200;
4230 MCHBAR32(0x1560) = 0x4051210;
4231 MCHBAR32(0x1564) = 0x1010001;
4232 MCHBAR32(0x1568) = 0x1110000;
4233 MCHBAR16(0x1222) = 0x220a;
4234 MCHBAR16(0x123c) = 0x1fc0;
4235 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004236 }
4237
Felix Heldf83d80b2018-07-29 05:30:30 +02004238 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004239 MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004240 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004241
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004242 MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004243
4244 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004245 MCHBAR8_AND(0x2ca8, ~3);
4246 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02004247 /* This issues a CPU reset without resetting the platform */
4248 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Felix Held04be2dd2018-07-29 04:53:22 +02004249 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004250 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004251 }
4252
Felix Held04be2dd2018-07-29 04:53:22 +02004253 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004254 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004255 pci_write_config32(PCI_DEV (0xff, 0, 0), 0x60, 0x20220);
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004256 MCHBAR16(0x2c20); // !!!!
4257 MCHBAR16(0x2c10); // !!!!
4258 MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004259 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004260 udelay(1000);
4261 write_1d0(0, 0x33d, 0, 0);
4262 write_500(&info, 0, 0, 0xb61, 0, 0);
4263 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004264 MCHBAR32(0x1a30) = 0x0;
4265 MCHBAR32(0x1a34) = 0x0;
4266 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4267 (info.populated_ranks[0][0][0] * 0xa0);
4268 MCHBAR16(0x616) = 0x26a;
4269 MCHBAR32(0x134) = 0x856000;
4270 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004271 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4272 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004273 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004274 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4275 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004276 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004277 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004278 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4279 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004280 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4281 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4282 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4283 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4284 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4285 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4286 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4287 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4288 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4289 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004290 }
4291
4292 write_1d0(0x4, 0x151, 4, 1);
4293 write_1d0(0, 0x142, 3, 1);
4294 rdmsr(0x1ac); // !!!!
4295 write_500(&info, 1, 1, 0x6b3, 4, 1);
4296 write_500(&info, 1, 1, 0x6cf, 4, 1);
4297
4298 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4299
4300 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4301 populated_ranks[0]
4302 [0][0]) << 0),
4303 0x1d1, 3, 1);
4304 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004305 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4306 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004307 }
4308
4309 set_334(0);
4310
4311 program_base_timings(&info);
4312
Felix Held04be2dd2018-07-29 04:53:22 +02004313 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004314
4315 write_1d0(0x2, 0x1d5, 2, 1);
4316 write_1d0(0x20, 0x166, 7, 1);
4317 write_1d0(0x0, 0xeb, 3, 1);
4318 write_1d0(0x0, 0xf3, 6, 1);
4319
4320 for (channel = 0; channel < NUM_CHANNELS; channel++)
4321 for (lane = 0; lane < 9; lane++) {
4322 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4323 u8 a;
4324 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4325 write_500(&info, channel, a, addr, 6, 1);
4326 }
4327
4328 udelay(1000);
4329
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004330 if (s3resume) {
4331 if (info.cached_training == NULL) {
4332 u32 reg32;
4333 printk(BIOS_ERR,
4334 "Couldn't find training data. Rebooting\n");
4335 reg32 = inl(DEFAULT_PMBASE + 0x04);
4336 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004337 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004338 }
4339 int tm;
4340 info.training = *info.cached_training;
4341 for (tm = 0; tm < 4; tm++)
4342 for (channel = 0; channel < NUM_CHANNELS; channel++)
4343 for (slot = 0; slot < NUM_SLOTS; slot++)
4344 for (rank = 0; rank < NUM_RANKS; rank++)
4345 for (lane = 0; lane < 9; lane++)
4346 write_500(&info,
4347 channel,
4348 info.training.
4349 lane_timings
4350 [tm][channel]
4351 [slot][rank]
4352 [lane],
4353 get_timing_register_addr
4354 (lane, tm,
4355 slot, rank),
4356 9, 0);
4357 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4358 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4359 }
4360
Felix Heldf83d80b2018-07-29 05:30:30 +02004361 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004362 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004363 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004364 MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004365
4366 program_board_delay(&info);
4367
Felix Held04be2dd2018-07-29 04:53:22 +02004368 MCHBAR8(0x5ff) = 0x0;
4369 MCHBAR8(0x5ff) = 0x80;
4370 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004371
Felix Held04be2dd2018-07-29 04:53:22 +02004372 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004373 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004374 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004375 gav(read_1d0(0x14b, 7)); // = 0x81023100
4376 write_1d0(0x30, 0x14b, 7, 1);
4377 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4378 write_1d0(7, 0xd6, 6, 1);
4379 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4380 write_1d0(7, 0x328, 6, 1);
4381
4382 for (channel = 0; channel < NUM_CHANNELS; channel++)
4383 set_4cf(&info, channel,
4384 info.populated_ranks[channel][0][0] ? 8 : 0);
4385
4386 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4387 write_1d0(2, 0x116, 4, 1);
4388 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4389 write_1d0(0, 0xae, 6, 1);
4390 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4391 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004392 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4393 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004394 MCHBAR32_AND(0x140, ~0x07000000);
4395 MCHBAR32_AND(0x138, ~0x07000000);
4396 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004397 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004398 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004399 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004400
4401 {
4402 u32 t;
4403 u8 val_a1;
4404 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4405 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4406 rmw_1d0(0x320, 0x07,
4407 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4408 rmw_1d0(0x14b, 0x78,
4409 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4410 4), 7,
4411 1);
4412 rmw_1d0(0xce, 0x38,
4413 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4414 4), 6,
4415 1);
4416 }
4417
4418 for (channel = 0; channel < NUM_CHANNELS; channel++)
4419 set_4cf(&info, channel,
4420 info.populated_ranks[channel][0][0] ? 9 : 1);
4421
4422 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004423 MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004424 write_1d0(2, 0xae, 6, 1);
4425 write_1d0(2, 0x300, 6, 1);
4426 write_1d0(2, 0x121, 3, 1);
4427 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4428 write_1d0(4, 0xd6, 6, 1);
4429 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4430 write_1d0(4, 0x328, 6, 1);
4431
4432 for (channel = 0; channel < NUM_CHANNELS; channel++)
4433 set_4cf(&info, channel,
4434 info.populated_ranks[channel][0][0] ? 9 : 0);
4435
Felix Held04be2dd2018-07-29 04:53:22 +02004436 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4437 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004438 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004439 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004440 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4441 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4442 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4443 write_1d0(0, 0x21c, 6, 1);
4444 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4445 write_1d0(0x35, 0x14b, 7, 1);
4446
4447 for (channel = 0; channel < NUM_CHANNELS; channel++)
4448 set_4cf(&info, channel,
4449 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4450
4451 set_334(1);
4452
Felix Held04be2dd2018-07-29 04:53:22 +02004453 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004454
4455 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4456 write_500(&info, channel,
4457 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4458 1);
4459 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4460 }
Felix Held04be2dd2018-07-29 04:53:22 +02004461 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4462 MCHBAR16(0x6c0) = 0x14a0;
4463 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4464 MCHBAR16(0x232) = 0x8;
4465 /* 0x40004 or 0 depending on ? */
4466 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4467 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4468 MCHBAR32(0x128) = 0x2150d05;
4469 MCHBAR8(0x12c) = 0x1f;
4470 MCHBAR8(0x12d) = 0x56;
4471 MCHBAR8(0x12e) = 0x31;
4472 MCHBAR8(0x12f) = 0x0;
4473 MCHBAR8(0x271) = 0x2;
4474 MCHBAR8(0x671) = 0x2;
4475 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004476 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004477 MCHBAR32(0x294 + (channel << 10)) =
4478 (info.populated_ranks_mask[channel] & 3) << 16;
4479 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4480 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004481 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004482 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4483 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004484
4485 if (!s3resume)
4486 jedec_init(&info);
4487
4488 int totalrank = 0;
4489 for (channel = 0; channel < NUM_CHANNELS; channel++)
4490 for (slot = 0; slot < NUM_SLOTS; slot++)
4491 for (rank = 0; rank < NUM_RANKS; rank++)
4492 if (info.populated_ranks[channel][slot][rank]) {
4493 jedec_read(&info, channel, slot, rank,
4494 totalrank, 0xa, 0x400);
4495 totalrank++;
4496 }
4497
Felix Held04be2dd2018-07-29 04:53:22 +02004498 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004499
Felix Heldf83d80b2018-07-29 05:30:30 +02004500 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4501 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004502
4503 if (!s3resume) {
4504 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004505 MCHBAR32(0x294 + (channel << 10)) =
4506 (info.populated_ranks_mask[channel] & 3) << 16;
4507 MCHBAR16(0x298 + (channel << 10)) =
4508 info.populated_ranks[channel][0][0] |
4509 (info.populated_ranks[channel][0][1] << 5);
4510 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004511 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004512 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004513
4514 {
4515 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004516 a = MCHBAR8(0x243);
4517 b = MCHBAR8(0x643);
4518 MCHBAR8(0x243) = a | 2;
4519 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004520 }
4521
4522 write_1d0(7, 0x19b, 3, 1);
4523 write_1d0(7, 0x1c0, 3, 1);
4524 write_1d0(4, 0x1c6, 4, 1);
4525 write_1d0(4, 0x1cc, 4, 1);
4526 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4527 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004528 MCHBAR32(0x584) = 0xfffff;
4529 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004530
4531 for (channel = 0; channel < NUM_CHANNELS; channel++)
4532 for (slot = 0; slot < NUM_SLOTS; slot++)
4533 for (rank = 0; rank < NUM_RANKS; rank++)
4534 if (info.
4535 populated_ranks[channel][slot]
4536 [rank])
4537 config_rank(&info, s3resume,
4538 channel, slot,
4539 rank);
4540
Felix Held04be2dd2018-07-29 04:53:22 +02004541 MCHBAR8(0x243) = 0x1;
4542 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004543 }
4544
4545 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004546 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004547 write_26c(0, 0x820);
4548 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004549 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004550 /* end */
4551
4552 if (s3resume) {
4553 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004554 MCHBAR32(0x294 + (channel << 10)) =
4555 (info.populated_ranks_mask[channel] & 3) << 16;
4556 MCHBAR16(0x298 + (channel << 10)) =
4557 info.populated_ranks[channel][0][0] |
4558 (info.populated_ranks[channel][0][1] << 5);
4559 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004560 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004561 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004562 }
4563
Felix Held04be2dd2018-07-29 04:53:22 +02004564 MCHBAR32_AND(0xfa4, ~0x01000002);
4565 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004566
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004567 /* Before training. */
4568 timestamp_add_now(103);
4569
4570 if (!s3resume)
4571 ram_training(&info);
4572
4573 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004574 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004575
4576 dump_timings(&info);
4577
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004578 program_modules_memory_map(&info, 0);
4579 program_total_memory_map(&info);
4580
4581 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004582 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004583 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004584 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004585 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004586 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004587 else
Felix Held04be2dd2018-07-29 04:53:22 +02004588 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004589
Felix Held04be2dd2018-07-29 04:53:22 +02004590 MCHBAR32_AND(0xfac, ~0x80000000);
4591 MCHBAR32(0xfb4) = 0x4800;
4592 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4593 MCHBAR32(0xe94) = 0x7ffff;
4594 MCHBAR32(0xfc0) = 0x80002040;
4595 MCHBAR32(0xfc4) = 0x701246;
4596 MCHBAR8_AND(0xfc8, ~0x70);
4597 MCHBAR32_OR(0xe5c, 0x1000000);
4598 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4599 MCHBAR32(0x50) = 0x700b0;
4600 MCHBAR32(0x3c) = 0x10;
4601 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4602 MCHBAR8_OR(0xff4, 0x2);
4603 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004604
Felix Held29a9c072018-07-29 01:34:45 +02004605#if 1
Felix Held04be2dd2018-07-29 04:53:22 +02004606 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4607 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4608 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004609
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004610 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4611 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4612 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004613
4614#else
4615 {
4616 u32 eax;
Felix Held04be2dd2018-07-29 04:53:22 +02004617 // = 0xe911714b
4618 eax = read32p(0xffc + (MCHBAR32(0xd00) & ~1)) | 0x08000000;
4619 write32p(0xffc + (MCHBAR32(0xd00) & ~1), eax);
4620 // = 0xe911714b
4621 eax = read32p(0xffc + (MCHBAR32(0xdc0) & ~1)) | 0x40000000;
4622 write32p(0xffc + (MCHBAR32(0xdc0) & ~1), eax);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004623 }
4624#endif
4625
4626 {
4627 u32 eax;
4628
4629 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004630 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4631 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4632 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004633 }
4634
4635 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004636 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004637 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004638 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004639 else
Felix Held04be2dd2018-07-29 04:53:22 +02004640 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004641
Felix Held04be2dd2018-07-29 04:53:22 +02004642 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004643
Felix Held04be2dd2018-07-29 04:53:22 +02004644 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004645 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004646 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004647 else
Felix Held04be2dd2018-07-29 04:53:22 +02004648 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004649 }
4650
Felix Held04be2dd2018-07-29 04:53:22 +02004651 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004652
4653 {
4654 u8 al;
4655 al = 0xd;
4656 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4657 al += 2;
4658 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004659 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004660 }
4661
4662 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004663 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4664 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4665 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4666 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004667 }
4668 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004669 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004670 reg1c = read32p(DEFAULT_EPBAR | 0x01c); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004671 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004672 write32p(DEFAULT_EPBAR | 0x01c, reg1c); // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004673 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004674 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004675 MCHBAR8_OR(0x1210, 2);
4676 MCHBAR32(0x1200) = 0x8800440;
4677 MCHBAR32(0x1204) = 0x53ff0453;
4678 MCHBAR32(0x1208) = 0x19002043;
4679 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004680
4681 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004682 MCHBAR16(0x1214) = 0x220;
4683 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004684 }
4685
Felix Held04be2dd2018-07-29 04:53:22 +02004686 MCHBAR8_OR(0x1214, 0x4);
4687 MCHBAR8(0x120c) = 0x1;
4688 MCHBAR8(0x1218) = 0x3;
4689 MCHBAR8(0x121a) = 0x3;
4690 MCHBAR8(0x121c) = 0x3;
4691 MCHBAR16(0xc14) = 0x0;
4692 MCHBAR16(0xc20) = 0x0;
4693 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004694
4695 /* revision dependent here. */
4696
Felix Held04be2dd2018-07-29 04:53:22 +02004697 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004698
4699 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004700 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004701
Felix Held04be2dd2018-07-29 04:53:22 +02004702 MCHBAR16_OR(0x1230, 0x8000);
4703 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004704
4705 u8 bl, ebpb;
4706 u16 reg_1020;
4707
Felix Held04be2dd2018-07-29 04:53:22 +02004708 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4709 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004710
Felix Held04be2dd2018-07-29 04:53:22 +02004711 MCHBAR32(0x1000) = 0x100;
4712 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004713
4714 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004715 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004716 bl = reg_1020 >> 8;
4717 ebpb = reg_1020 & 0xff;
4718 } else {
4719 ebpb = 0;
4720 bl = 8;
4721 }
4722
4723 rdmsr(0x1a2);
4724
Felix Held04be2dd2018-07-29 04:53:22 +02004725 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004726
Felix Held04be2dd2018-07-29 04:53:22 +02004727 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004728
Felix Held04be2dd2018-07-29 04:53:22 +02004729 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004730
Felix Held04be2dd2018-07-29 04:53:22 +02004731 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004732 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004733 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4734 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004735 }
4736
4737 setup_heci_uma(&info);
4738
4739 if (info.uma_enabled) {
4740 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004741 MCHBAR32_OR(0x11b0, 0x4000);
4742 MCHBAR32_OR(0x11b4, 0x4000);
4743 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004744
Felix Held04be2dd2018-07-29 04:53:22 +02004745 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4746 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4747 MCHBAR16_OR(0x1170, 0x1000);
4748
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004749 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004750
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004751 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004752 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004753 ;
4754 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004755 }
4756
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004757 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4758 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004759 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004760 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004761
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004762 udelay(1000);
4763 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004764 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4765
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004766 if (!s3resume)
4767 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004768 if (s3resume && cbmem_wasnot_inited) {
4769 u32 reg32;
4770 printk(BIOS_ERR, "Failed S3 resume.\n");
4771 ram_check(0x100000, 0x200000);
4772
4773 /* Clear SLP_TYPE. */
4774 reg32 = inl(DEFAULT_PMBASE + 0x04);
4775 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4776
4777 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004778 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004779 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004780}