blob: 54ef278840a5013dbf81b002af4a2de7b5f61960 [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>
21#include <cpu/x86/msr.h>
22#include <cbmem.h>
23#include <arch/cbfs.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010024#include <ip_checksum.h>
25#include <pc80/mc146818rtc.h>
26#include <device/pci_def.h>
Patrick Rudolph266a1f72016-06-09 18:13:34 +020027#include <device/device.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010028#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010029#include <spd.h>
30#include "raminit.h"
Patrick Rudolph266a1f72016-06-09 18:13:34 +020031#include "chip.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010032#include <timestamp.h>
33#include <cpu/x86/mtrr.h>
34#include <cpu/intel/speedstep.h>
35#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010036#include <mrc_cache.h>
Matthias Gazzaridfa51252018-05-19 00:44:20 +020037#include <arch/early_variables.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010038
39#include "nehalem.h"
40
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020041#include <southbridge/intel/ibexpeak/me.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010042#include <delay.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010043
44#define NORTHBRIDGE PCI_DEV(0, 0, 0)
45#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
46#define GMA PCI_DEV (0, 0x2, 0x0)
47#define HECIDEV PCI_DEV(0, 0x16, 0)
48#define HECIBAR 0x10
49
50#define FOR_ALL_RANKS \
51 for (channel = 0; channel < NUM_CHANNELS; channel++) \
52 for (slot = 0; slot < NUM_SLOTS; slot++) \
53 for (rank = 0; rank < NUM_RANKS; rank++)
54
55#define FOR_POPULATED_RANKS \
56 for (channel = 0; channel < NUM_CHANNELS; channel++) \
57 for (slot = 0; slot < NUM_SLOTS; slot++) \
58 for (rank = 0; rank < NUM_RANKS; rank++) \
59 if (info->populated_ranks[channel][slot][rank])
60
61#define FOR_POPULATED_RANKS_BACKWARDS \
62 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
63 for (slot = 0; slot < NUM_SLOTS; slot++) \
64 for (rank = 0; rank < NUM_RANKS; rank++) \
65 if (info->populated_ranks[channel][slot][rank])
66
67/* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */
68typedef struct {
69 u8 smallest;
70 u8 largest;
71} timing_bounds_t[2][2][2][9];
72
Arthur Heymansdc71e252018-01-29 10:14:48 +010073#define MRC_CACHE_VERSION 1
74
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010075struct ram_training {
76 /* [TM][CHANNEL][SLOT][RANK][LANE] */
77 u16 lane_timings[4][2][2][2][9];
78 u16 reg_178;
79 u16 reg_10b;
80
81 u8 reg178_center;
82 u8 reg178_smallest;
83 u8 reg178_largest;
84 timing_bounds_t timing_bounds[2];
85 u16 timing_offset[2][2][2][9];
86 u16 timing2_offset[2][2][2][9];
87 u16 timing2_bounds[2][2][2][9][2];
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +010088 u8 reg274265[2][3]; /* [CHANNEL][REGISTER] */
89 u8 reg2ca9_bit0;
90 u32 reg_6dc;
91 u32 reg_6e8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010092};
93
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010094#include <lib.h> /* Prototypes */
95
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010096
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010097static void clflush(u32 addr)
98{
99 asm volatile ("clflush (%0)"::"r" (addr));
100}
101
102typedef struct _u128 {
103 u64 lo;
104 u64 hi;
105} u128;
106
107static void read128(u32 addr, u64 * out)
108{
109 u128 ret;
110 u128 stor;
111 asm volatile ("movdqu %%xmm0, %0\n"
112 "movdqa (%2), %%xmm0\n"
113 "movdqu %%xmm0, %1\n"
114 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
115 out[0] = ret.lo;
116 out[1] = ret.hi;
117}
118
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100119/* OK */
120static void write_1d0(u32 val, u16 addr, int bits, int flag)
121{
Felix Held04be2dd2018-07-29 04:53:22 +0200122 MCHBAR32(0x1d0) = 0;
123 while (MCHBAR32(0x1d0) & 0x800000)
124 ;
125 MCHBAR32(0x1d4) =
126 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
127 MCHBAR32(0x1d0) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200128 while (MCHBAR32(0x1d0) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200129 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100130}
131
132/* OK */
133static u16 read_1d0(u16 addr, int split)
134{
135 u32 val;
Felix Held04be2dd2018-07-29 04:53:22 +0200136 MCHBAR32(0x1d0) = 0;
137 while (MCHBAR32(0x1d0) & 0x800000)
138 ;
139 MCHBAR32(0x1d0) =
140 0x80000000 | (((MCHBAR8(0x246) >> 2) & 3) + 0x361 - addr);
141 while (MCHBAR32(0x1d0) & 0x800000)
142 ;
143 val = MCHBAR32(0x1d8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100144 write_1d0(0, 0x33d, 0, 0);
145 write_1d0(0, 0x33d, 0, 0);
146 val &= ((1 << split) - 1);
147 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
148 return val;
149}
150
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800151static void write32p(uintptr_t addr, uint32_t val)
152{
153 write32((void *)addr, val);
154}
155
156static uint32_t read32p(uintptr_t addr)
157{
158 return read32((void *)addr);
159}
160
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100161static void sfence(void)
162{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100163 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100164}
165
166static inline u16 get_lane_offset(int slot, int rank, int lane)
167{
168 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
169 0x452 * (lane == 8);
170}
171
172static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
173{
174 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
175 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
176}
177
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100178static u32 gav_real(int line, u32 in)
179{
180 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
181 return in;
182}
183
184#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200185
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100186struct raminfo {
187 u16 clock_speed_index; /* clock_speed (REAL, not DDR) / 133.(3) - 3 */
188 u16 fsb_frequency; /* in 1.(1)/2 MHz. */
189 u8 is_x16_module[2][2]; /* [CHANNEL][SLOT] */
190 u8 density[2][2]; /* [CHANNEL][SLOT] */
191 u8 populated_ranks[2][2][2]; /* [CHANNEL][SLOT][RANK] */
192 int rank_start[2][2][2];
193 u8 cas_latency;
194 u8 board_lane_delay[9];
195 u8 use_ecc;
196 u8 revision;
197 u8 max_supported_clock_speed_index;
198 u8 uma_enabled;
199 u8 spd[2][2][151]; /* [CHANNEL][SLOT][BYTE] */
200 u8 silicon_revision;
201 u8 populated_ranks_mask[2];
202 u8 max_slots_used_in_channel;
203 u8 mode4030[2];
204 u16 avg4044[2];
205 u16 max4048[2];
206 unsigned total_memory_mb;
207 unsigned interleaved_part_mb;
208 unsigned non_interleaved_part_mb;
209
210 u32 heci_bar;
211 u64 heci_uma_addr;
212 unsigned memory_reserved_for_heci_mb;
213
214 struct ram_training training;
215 u32 last_500_command[2];
216
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100217 u32 delay46_ps[2];
218 u32 delay54_ps[2];
219 u8 revision_flag_1;
220 u8 some_delay_1_cycle_floor;
221 u8 some_delay_2_halfcycles_ceil;
222 u8 some_delay_3_ps_rounded;
223
224 const struct ram_training *cached_training;
225};
226
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200227/* Global allocation of timings_car */
228timing_bounds_t timings_car[64] CAR_GLOBAL;
229
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100230static void
231write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
232 int flag);
233
234/* OK */
235static u16
236read_500(struct raminfo *info, int channel, u16 addr, int split)
237{
238 u32 val;
239 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200240 MCHBAR32(0x500 + (channel << 10)) = 0;
241 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
242 ;
243 MCHBAR32(0x500 + (channel << 10)) =
244 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
245 + 0xb88 - addr);
246 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
247 ;
248 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100249 return val & ((1 << split) - 1);
250}
251
252/* OK */
253static void
254write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
255 int flag)
256{
257 if (info->last_500_command[channel] == 0x80000000) {
258 info->last_500_command[channel] = 0x40000000;
259 write_500(info, channel, 0, 0xb61, 0, 0);
260 }
Felix Held04be2dd2018-07-29 04:53:22 +0200261 MCHBAR32(0x500 + (channel << 10)) = 0;
262 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
263 ;
264 MCHBAR32(0x504 + (channel << 10)) =
265 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
266 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200267 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200268 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100269}
270
271static int rw_test(int rank)
272{
273 const u32 mask = 0xf00fc33c;
274 int ok = 0xff;
275 int i;
276 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800277 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100278 sfence();
279 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800280 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100281 sfence();
282 for (i = 0; i < 32; i++) {
283 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800284 write32p((rank << 28) | (i << 3), pat);
285 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100286 }
287 sfence();
288 for (i = 0; i < 32; i++) {
289 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
290 int j;
291 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800292 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100293 for (j = 0; j < 4; j++)
294 if (((val >> (j * 8)) & 0xff) != pat)
295 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800296 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100297 for (j = 0; j < 4; j++)
298 if (((val >> (j * 8)) & 0xff) != pat)
299 ok &= ~(16 << j);
300 }
301 sfence();
302 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800303 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100304 sfence();
305 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800306 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100307
308 return ok;
309}
310
311static void
312program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
313{
314 int lane;
315 for (lane = 0; lane < 8; lane++) {
316 write_500(info, channel,
317 base +
318 info->training.
319 lane_timings[2][channel][slot][rank][lane],
320 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
321 write_500(info, channel,
322 base +
323 info->training.
324 lane_timings[3][channel][slot][rank][lane],
325 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
326 }
327}
328
329static void write_26c(int channel, u16 si)
330{
Felix Held04be2dd2018-07-29 04:53:22 +0200331 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
332 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
333 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100334}
335
336static u32 get_580(int channel, u8 addr)
337{
338 u32 ret;
339 gav(read_1d0(0x142, 3));
Felix Held04be2dd2018-07-29 04:53:22 +0200340 MCHBAR8(0x5ff) = 0x0;
341 MCHBAR8(0x5ff) = 0x80;
342 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
343 MCHBAR8_OR(0x580 + (channel << 10), 1);
344 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
345 ;
346 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100347 return ret;
348}
349
350const int cached_config = 0;
351
352#define NUM_CHANNELS 2
353#define NUM_SLOTS 2
354#define NUM_RANKS 2
355#define RANK_SHIFT 28
356#define CHANNEL_SHIFT 10
357
358#include "raminit_tables.c"
359
360static void seq9(struct raminfo *info, int channel, int slot, int rank)
361{
362 int i, lane;
363
364 for (i = 0; i < 2; i++)
365 for (lane = 0; lane < 8; lane++)
366 write_500(info, channel,
367 info->training.lane_timings[i +
368 1][channel][slot]
369 [rank][lane], get_timing_register_addr(lane,
370 i + 1,
371 slot,
372 rank),
373 9, 0);
374
375 write_1d0(1, 0x103, 6, 1);
376 for (lane = 0; lane < 8; lane++)
377 write_500(info, channel,
378 info->training.
379 lane_timings[0][channel][slot][rank][lane],
380 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
381
382 for (i = 0; i < 2; i++) {
383 for (lane = 0; lane < 8; lane++)
384 write_500(info, channel,
385 info->training.lane_timings[i +
386 1][channel][slot]
387 [rank][lane], get_timing_register_addr(lane,
388 i + 1,
389 slot,
390 rank),
391 9, 0);
392 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
393 }
394
395 gav(read_1d0(0x142, 3)); // = 0x10408118
Felix Held04be2dd2018-07-29 04:53:22 +0200396 MCHBAR8(0x5ff) = 0x0;
397 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100398 write_1d0(0x2, 0x142, 3, 1);
399 for (lane = 0; lane < 8; lane++) {
400 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
401 info->training.lane_timings[2][channel][slot][rank][lane] =
402 read_500(info, channel,
403 get_timing_register_addr(lane, 2, slot, rank), 9);
404 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
405 info->training.lane_timings[3][channel][slot][rank][lane] =
406 info->training.lane_timings[2][channel][slot][rank][lane] +
407 0x20;
408 }
409}
410
411static int count_ranks_in_channel(struct raminfo *info, int channel)
412{
413 int slot, rank;
414 int res = 0;
415 for (slot = 0; slot < NUM_SLOTS; slot++)
416 for (rank = 0; rank < NUM_SLOTS; rank++)
417 res += info->populated_ranks[channel][slot][rank];
418 return res;
419}
420
421static void
422config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
423{
424 int add;
425
426 write_1d0(0, 0x178, 7, 1);
427 seq9(info, channel, slot, rank);
428 program_timings(info, 0x80, channel, slot, rank);
429
430 if (channel == 0)
431 add = count_ranks_in_channel(info, 1);
432 else
433 add = 0;
434 if (!s3resume)
435 gav(rw_test(rank + add));
436 program_timings(info, 0x00, channel, slot, rank);
437 if (!s3resume)
438 gav(rw_test(rank + add));
439 if (!s3resume)
440 gav(rw_test(rank + add));
441 write_1d0(0, 0x142, 3, 1);
442 write_1d0(0, 0x103, 6, 1);
443
444 gav(get_580(channel, 0xc | (rank << 5)));
445 gav(read_1d0(0x142, 3));
446
Felix Held04be2dd2018-07-29 04:53:22 +0200447 MCHBAR8(0x5ff) = 0x0;
448 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100449}
450
451static void set_4cf(struct raminfo *info, int channel, u8 val)
452{
453 gav(read_500(info, channel, 0x4cf, 4)); // = 0xc2300cf9
454 write_500(info, channel, val, 0x4cf, 4, 1);
455 gav(read_500(info, channel, 0x659, 4)); // = 0x80300839
456 write_500(info, channel, val, 0x659, 4, 1);
457 gav(read_500(info, channel, 0x697, 4)); // = 0x80300839
458 write_500(info, channel, val, 0x697, 4, 1);
459}
460
461static void set_334(int zero)
462{
463 int j, k, channel;
464 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
465 u32 vd8[2][16];
466
467 for (channel = 0; channel < NUM_CHANNELS; channel++) {
468 for (j = 0; j < 4; j++) {
469 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
470 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
471 u16 c;
472 if ((j == 0 || j == 3) && zero)
473 c = 0;
474 else if (j == 3)
475 c = 0x5f;
476 else
477 c = 0x5f5f;
478
479 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200480 MCHBAR32(0x138 + 8 * k) =
481 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100482 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200483 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100484 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200485 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100486 }
487
Felix Held22ca8cb2018-07-29 05:09:44 +0200488 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
489 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200490 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
491 zero ? 0 : (0x18191819 & lmask);
492 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
493 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
494 zero ? 0 : (a & lmask);
495 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
496 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100497 }
498 }
499
Felix Held04be2dd2018-07-29 04:53:22 +0200500 MCHBAR32_OR(0x130, 1);
501 while (MCHBAR8(0x130) & 1)
502 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100503}
504
505static void rmw_1d0(u16 addr, u32 and, u32 or, int split, int flag)
506{
507 u32 v;
508 v = read_1d0(addr, split);
509 write_1d0((v & and) | or, addr, split, flag);
510}
511
512static int find_highest_bit_set(u16 val)
513{
514 int i;
515 for (i = 15; i >= 0; i--)
516 if (val & (1 << i))
517 return i;
518 return -1;
519}
520
521static int find_lowest_bit_set32(u32 val)
522{
523 int i;
524 for (i = 0; i < 32; i++)
525 if (val & (1 << i))
526 return i;
527 return -1;
528}
529
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100530enum {
531 DEVICE_TYPE = 2,
532 MODULE_TYPE = 3,
533 DENSITY = 4,
534 RANKS_AND_DQ = 7,
535 MEMORY_BUS_WIDTH = 8,
536 TIMEBASE_DIVIDEND = 10,
537 TIMEBASE_DIVISOR = 11,
538 CYCLETIME = 12,
539
540 CAS_LATENCIES_LSB = 14,
541 CAS_LATENCIES_MSB = 15,
542 CAS_LATENCY_TIME = 16,
543 THERMAL_AND_REFRESH = 31,
544 REFERENCE_RAW_CARD_USED = 62,
545 RANK1_ADDRESS_MAPPING = 63
546};
547
548static void calculate_timings(struct raminfo *info)
549{
550 unsigned cycletime;
551 unsigned cas_latency_time;
552 unsigned supported_cas_latencies;
553 unsigned channel, slot;
554 unsigned clock_speed_index;
555 unsigned min_cas_latency;
556 unsigned cas_latency;
557 unsigned max_clock_index;
558
559 /* Find common CAS latency */
560 supported_cas_latencies = 0x3fe;
561 for (channel = 0; channel < NUM_CHANNELS; channel++)
562 for (slot = 0; slot < NUM_SLOTS; slot++)
563 if (info->populated_ranks[channel][slot][0])
564 supported_cas_latencies &=
565 2 *
566 (info->
567 spd[channel][slot][CAS_LATENCIES_LSB] |
568 (info->
569 spd[channel][slot][CAS_LATENCIES_MSB] <<
570 8));
571
572 max_clock_index = min(3, info->max_supported_clock_speed_index);
573
574 cycletime = min_cycletime[max_clock_index];
575 cas_latency_time = min_cas_latency_time[max_clock_index];
576
577 for (channel = 0; channel < NUM_CHANNELS; channel++)
578 for (slot = 0; slot < NUM_SLOTS; slot++)
579 if (info->populated_ranks[channel][slot][0]) {
580 unsigned timebase;
581 timebase =
582 1000 *
583 info->
584 spd[channel][slot][TIMEBASE_DIVIDEND] /
585 info->spd[channel][slot][TIMEBASE_DIVISOR];
586 cycletime =
587 max(cycletime,
588 timebase *
589 info->spd[channel][slot][CYCLETIME]);
590 cas_latency_time =
591 max(cas_latency_time,
592 timebase *
593 info->
594 spd[channel][slot][CAS_LATENCY_TIME]);
595 }
596 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
597 if (cycletime == min_cycletime[clock_speed_index])
598 break;
599 if (cycletime > min_cycletime[clock_speed_index]) {
600 clock_speed_index--;
601 cycletime = min_cycletime[clock_speed_index];
602 break;
603 }
604 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100605 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100606 cas_latency = 0;
607 while (supported_cas_latencies) {
608 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
609 if (cas_latency <= min_cas_latency)
610 break;
611 supported_cas_latencies &=
612 ~(1 << find_highest_bit_set(supported_cas_latencies));
613 }
614
615 if (cas_latency != min_cas_latency && clock_speed_index)
616 clock_speed_index--;
617
618 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
619 die("Couldn't configure DRAM");
620 info->clock_speed_index = clock_speed_index;
621 info->cas_latency = cas_latency;
622}
623
624static void program_base_timings(struct raminfo *info)
625{
626 unsigned channel;
627 unsigned slot, rank, lane;
628 unsigned extended_silicon_revision;
629 int i;
630
631 extended_silicon_revision = info->silicon_revision;
632 if (info->silicon_revision == 0)
633 for (channel = 0; channel < NUM_CHANNELS; channel++)
634 for (slot = 0; slot < NUM_SLOTS; slot++)
635 if ((info->
636 spd[channel][slot][MODULE_TYPE] & 0xF) ==
637 3)
638 extended_silicon_revision = 4;
639
640 for (channel = 0; channel < NUM_CHANNELS; channel++) {
641 for (slot = 0; slot < NUM_SLOTS; slot++)
642 for (rank = 0; rank < NUM_SLOTS; rank++) {
643 int card_timing_2;
644 if (!info->populated_ranks[channel][slot][rank])
645 continue;
646
647 for (lane = 0; lane < 9; lane++) {
648 int tm_reg;
649 int card_timing;
650
651 card_timing = 0;
652 if ((info->
653 spd[channel][slot][MODULE_TYPE] &
654 0xF) == 3) {
655 int reference_card;
656 reference_card =
657 info->
658 spd[channel][slot]
659 [REFERENCE_RAW_CARD_USED] &
660 0x1f;
661 if (reference_card == 3)
662 card_timing =
663 u16_ffd1188[0][lane]
664 [info->
665 clock_speed_index];
666 if (reference_card == 5)
667 card_timing =
668 u16_ffd1188[1][lane]
669 [info->
670 clock_speed_index];
671 }
672
673 info->training.
674 lane_timings[0][channel][slot][rank]
675 [lane] =
676 u8_FFFD1218[info->
677 clock_speed_index];
678 info->training.
679 lane_timings[1][channel][slot][rank]
680 [lane] = 256;
681
682 for (tm_reg = 2; tm_reg < 4; tm_reg++)
683 info->training.
684 lane_timings[tm_reg]
685 [channel][slot][rank][lane]
686 =
687 u8_FFFD1240[channel]
688 [extended_silicon_revision]
689 [lane][2 * slot +
690 rank][info->
691 clock_speed_index]
692 + info->max4048[channel]
693 +
694 u8_FFFD0C78[channel]
695 [extended_silicon_revision]
696 [info->
697 mode4030[channel]][slot]
698 [rank][info->
699 clock_speed_index]
700 + card_timing;
701 for (tm_reg = 0; tm_reg < 4; tm_reg++)
702 write_500(info, channel,
703 info->training.
704 lane_timings[tm_reg]
705 [channel][slot][rank]
706 [lane],
707 get_timing_register_addr
708 (lane, tm_reg, slot,
709 rank), 9, 0);
710 }
711
712 card_timing_2 = 0;
713 if (!(extended_silicon_revision != 4
714 || (info->
715 populated_ranks_mask[channel] & 5) ==
716 5)) {
717 if ((info->
718 spd[channel][slot]
719 [REFERENCE_RAW_CARD_USED] & 0x1F)
720 == 3)
721 card_timing_2 =
722 u16_FFFE0EB8[0][info->
723 clock_speed_index];
724 if ((info->
725 spd[channel][slot]
726 [REFERENCE_RAW_CARD_USED] & 0x1F)
727 == 5)
728 card_timing_2 =
729 u16_FFFE0EB8[1][info->
730 clock_speed_index];
731 }
732
733 for (i = 0; i < 3; i++)
734 write_500(info, channel,
735 (card_timing_2 +
736 info->max4048[channel]
737 +
738 u8_FFFD0EF8[channel]
739 [extended_silicon_revision]
740 [info->
741 mode4030[channel]][info->
742 clock_speed_index]),
743 u16_fffd0c50[i][slot][rank],
744 8, 1);
745 write_500(info, channel,
746 (info->max4048[channel] +
747 u8_FFFD0C78[channel]
748 [extended_silicon_revision][info->
749 mode4030
750 [channel]]
751 [slot][rank][info->
752 clock_speed_index]),
753 u16_fffd0c70[slot][rank], 7, 1);
754 }
755 if (!info->populated_ranks_mask[channel])
756 continue;
757 for (i = 0; i < 3; i++)
758 write_500(info, channel,
759 (info->max4048[channel] +
760 info->avg4044[channel]
761 +
762 u8_FFFD17E0[channel]
763 [extended_silicon_revision][info->
764 mode4030
765 [channel]][info->
766 clock_speed_index]),
767 u16_fffd0c68[i], 8, 1);
768 }
769}
770
771static unsigned int fsbcycle_ps(struct raminfo *info)
772{
773 return 900000 / info->fsb_frequency;
774}
775
776/* The time of DDR transfer in ps. */
777static unsigned int halfcycle_ps(struct raminfo *info)
778{
779 return 3750 / (info->clock_speed_index + 3);
780}
781
782/* The time of clock cycle in ps. */
783static unsigned int cycle_ps(struct raminfo *info)
784{
785 return 2 * halfcycle_ps(info);
786}
787
788/* Frequency in 1.(1)=10/9 MHz units. */
789static unsigned frequency_11(struct raminfo *info)
790{
791 return (info->clock_speed_index + 3) * 120;
792}
793
794/* Frequency in 0.1 MHz units. */
795static unsigned frequency_01(struct raminfo *info)
796{
797 return 100 * frequency_11(info) / 9;
798}
799
800static unsigned ps_to_halfcycles(struct raminfo *info, unsigned int ps)
801{
802 return (frequency_11(info) * 2) * ps / 900000;
803}
804
805static unsigned ns_to_cycles(struct raminfo *info, unsigned int ns)
806{
807 return (frequency_11(info)) * ns / 900;
808}
809
810static void compute_derived_timings(struct raminfo *info)
811{
812 unsigned channel, slot, rank;
813 int extended_silicon_revision;
814 int some_delay_1_ps;
815 int some_delay_2_ps;
816 int some_delay_2_halfcycles_ceil;
817 int some_delay_2_halfcycles_floor;
818 int some_delay_3_ps;
819 int some_delay_3_halfcycles;
820 int some_delay_3_ps_rounded;
821 int some_delay_1_cycle_ceil;
822 int some_delay_1_cycle_floor;
823
824 some_delay_3_halfcycles = 0;
825 some_delay_3_ps_rounded = 0;
826 extended_silicon_revision = info->silicon_revision;
827 if (!info->silicon_revision)
828 for (channel = 0; channel < NUM_CHANNELS; channel++)
829 for (slot = 0; slot < NUM_SLOTS; slot++)
830 if ((info->
831 spd[channel][slot][MODULE_TYPE] & 0xF) ==
832 3)
833 extended_silicon_revision = 4;
834 if (info->board_lane_delay[7] < 5)
835 info->board_lane_delay[7] = 5;
836 info->revision_flag_1 = 2;
837 if (info->silicon_revision == 2 || info->silicon_revision == 3)
838 info->revision_flag_1 = 0;
839 if (info->revision < 16)
840 info->revision_flag_1 = 0;
841
842 if (info->revision < 8)
843 info->revision_flag_1 = 0;
844 if (info->revision >= 8 && (info->silicon_revision == 0
845 || info->silicon_revision == 1))
846 some_delay_2_ps = 735;
847 else
848 some_delay_2_ps = 750;
849
850 if (info->revision >= 0x10 && (info->silicon_revision == 0
851 || info->silicon_revision == 1))
852 some_delay_1_ps = 3929;
853 else
854 some_delay_1_ps = 3490;
855
856 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
857 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
858 if (some_delay_1_ps % cycle_ps(info))
859 some_delay_1_cycle_ceil++;
860 else
861 some_delay_1_cycle_floor--;
862 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
863 if (info->revision_flag_1)
864 some_delay_2_ps = halfcycle_ps(info) >> 6;
865 some_delay_2_ps +=
866 max(some_delay_1_ps - 30,
867 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
868 375;
869 some_delay_3_ps =
870 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
871 if (info->revision_flag_1) {
872 if (some_delay_3_ps < 150)
873 some_delay_3_halfcycles = 0;
874 else
875 some_delay_3_halfcycles =
876 (some_delay_3_ps << 6) / halfcycle_ps(info);
877 some_delay_3_ps_rounded =
878 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
879 }
880 some_delay_2_halfcycles_ceil =
881 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
882 2 * (some_delay_1_cycle_ceil - 1);
883 if (info->revision_flag_1 && some_delay_3_ps < 150)
884 some_delay_2_halfcycles_ceil++;
885 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
886 if (info->revision < 0x10)
887 some_delay_2_halfcycles_floor =
888 some_delay_2_halfcycles_ceil - 1;
889 if (!info->revision_flag_1)
890 some_delay_2_halfcycles_floor++;
891 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
892 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
893 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
894 || (info->populated_ranks[1][0][0]
895 && info->populated_ranks[1][1][0]))
896 info->max_slots_used_in_channel = 2;
897 else
898 info->max_slots_used_in_channel = 1;
899 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200900 MCHBAR32(0x244 + (channel << 10)) =
901 ((info->revision < 8) ? 1 : 0x200) |
902 ((2 - info->max_slots_used_in_channel) << 17) |
903 (channel << 21) |
904 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100905 if (info->max_slots_used_in_channel == 1) {
906 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
907 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
908 } else {
909 info->mode4030[0] = ((count_ranks_in_channel(info, 0) == 1) || (count_ranks_in_channel(info, 0) == 2)) ? 2 : 3; /* 2 if 1 or 2 ranks */
910 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
911 || (count_ranks_in_channel(info, 1) ==
912 2)) ? 2 : 3;
913 }
914 for (channel = 0; channel < NUM_CHANNELS; channel++) {
915 int max_of_unk;
916 int min_of_unk_2;
917
918 int i, count;
919 int sum;
920
921 if (!info->populated_ranks_mask[channel])
922 continue;
923
924 max_of_unk = 0;
925 min_of_unk_2 = 32767;
926
927 sum = 0;
928 count = 0;
929 for (i = 0; i < 3; i++) {
930 int unk1;
931 if (info->revision < 8)
932 unk1 =
933 u8_FFFD1891[0][channel][info->
934 clock_speed_index]
935 [i];
936 else if (!
937 (info->revision >= 0x10
938 || info->revision_flag_1))
939 unk1 =
940 u8_FFFD1891[1][channel][info->
941 clock_speed_index]
942 [i];
943 else
944 unk1 = 0;
945 for (slot = 0; slot < NUM_SLOTS; slot++)
946 for (rank = 0; rank < NUM_RANKS; rank++) {
947 int a = 0;
948 int b = 0;
949
950 if (!info->
951 populated_ranks[channel][slot]
952 [rank])
953 continue;
954 if (extended_silicon_revision == 4
955 && (info->
956 populated_ranks_mask[channel] &
957 5) != 5) {
958 if ((info->
959 spd[channel][slot]
960 [REFERENCE_RAW_CARD_USED] &
961 0x1F) == 3) {
962 a = u16_ffd1178[0]
963 [info->
964 clock_speed_index];
965 b = u16_fe0eb8[0][info->
966 clock_speed_index];
967 } else
968 if ((info->
969 spd[channel][slot]
970 [REFERENCE_RAW_CARD_USED]
971 & 0x1F) == 5) {
972 a = u16_ffd1178[1]
973 [info->
974 clock_speed_index];
975 b = u16_fe0eb8[1][info->
976 clock_speed_index];
977 }
978 }
979 min_of_unk_2 = min(min_of_unk_2, a);
980 min_of_unk_2 = min(min_of_unk_2, b);
981 if (rank == 0) {
982 sum += a;
983 count++;
984 }
985 {
986 int t;
987 t = b +
988 u8_FFFD0EF8[channel]
989 [extended_silicon_revision]
990 [info->
991 mode4030[channel]][info->
992 clock_speed_index];
993 if (unk1 >= t)
994 max_of_unk =
995 max(max_of_unk,
996 unk1 - t);
997 }
998 }
999 {
1000 int t =
1001 u8_FFFD17E0[channel]
1002 [extended_silicon_revision][info->
1003 mode4030
1004 [channel]]
1005 [info->clock_speed_index] + min_of_unk_2;
1006 if (unk1 >= t)
1007 max_of_unk = max(max_of_unk, unk1 - t);
1008 }
1009 }
1010
1011 info->avg4044[channel] = sum / count;
1012 info->max4048[channel] = max_of_unk;
1013 }
1014}
1015
1016static void jedec_read(struct raminfo *info,
1017 int channel, int slot, int rank,
1018 int total_rank, u8 addr3, unsigned int value)
1019{
1020 /* Handle mirrored mapping. */
1021 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001022 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1023 ((addr3 >> 1) & 0x10);
1024 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1025 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001026
1027 /* Handle mirrored mapping. */
1028 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1029 value =
1030 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1031 << 1);
1032
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001033 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001034
Felix Held04be2dd2018-07-29 04:53:22 +02001035 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1036 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001037
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001038 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001039}
1040
1041enum {
1042 MR1_RZQ12 = 512,
1043 MR1_RZQ2 = 64,
1044 MR1_RZQ4 = 4,
1045 MR1_ODS34OHM = 2
1046};
1047
1048enum {
1049 MR0_BT_INTERLEAVED = 8,
1050 MR0_DLL_RESET_ON = 256
1051};
1052
1053enum {
1054 MR2_RTT_WR_DISABLED = 0,
1055 MR2_RZQ2 = 1 << 10
1056};
1057
1058static void jedec_init(struct raminfo *info)
1059{
1060 int write_recovery;
1061 int channel, slot, rank;
1062 int total_rank;
1063 int dll_on;
1064 int self_refresh_temperature;
1065 int auto_self_refresh;
1066
1067 auto_self_refresh = 1;
1068 self_refresh_temperature = 1;
1069 if (info->board_lane_delay[3] <= 10) {
1070 if (info->board_lane_delay[3] <= 8)
1071 write_recovery = info->board_lane_delay[3] - 4;
1072 else
1073 write_recovery = 5;
1074 } else {
1075 write_recovery = 6;
1076 }
1077 FOR_POPULATED_RANKS {
1078 auto_self_refresh &=
1079 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1080 self_refresh_temperature &=
1081 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1082 }
1083 if (auto_self_refresh == 1)
1084 self_refresh_temperature = 0;
1085
1086 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1087 || (info->populated_ranks[0][0][0]
1088 && info->populated_ranks[0][1][0])
1089 || (info->populated_ranks[1][0][0]
1090 && info->populated_ranks[1][1][0]));
1091
1092 total_rank = 0;
1093
1094 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1095 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1096 int rzq_reg58e;
1097
1098 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1099 rzq_reg58e = 64;
1100 rtt = MR1_RZQ2;
1101 if (info->clock_speed_index != 0) {
1102 rzq_reg58e = 4;
1103 if (info->populated_ranks_mask[channel] == 3)
1104 rtt = MR1_RZQ4;
1105 }
1106 } else {
1107 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1108 rtt = MR1_RZQ12;
1109 rzq_reg58e = 64;
1110 rtt_wr = MR2_RZQ2;
1111 } else {
1112 rzq_reg58e = 4;
1113 rtt = MR1_RZQ4;
1114 }
1115 }
1116
Felix Held04be2dd2018-07-29 04:53:22 +02001117 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1118 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1119 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1120 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1121 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001122
1123 for (slot = 0; slot < NUM_SLOTS; slot++)
1124 for (rank = 0; rank < NUM_RANKS; rank++)
1125 if (info->populated_ranks[channel][slot][rank]) {
1126 jedec_read(info, channel, slot, rank,
1127 total_rank, 0x28,
1128 rtt_wr | (info->
1129 clock_speed_index
1130 << 3)
1131 | (auto_self_refresh << 6) |
1132 (self_refresh_temperature <<
1133 7));
1134 jedec_read(info, channel, slot, rank,
1135 total_rank, 0x38, 0);
1136 jedec_read(info, channel, slot, rank,
1137 total_rank, 0x18,
1138 rtt | MR1_ODS34OHM);
1139 jedec_read(info, channel, slot, rank,
1140 total_rank, 6,
1141 (dll_on << 12) |
1142 (write_recovery << 9)
1143 | ((info->cas_latency - 4) <<
1144 4) | MR0_BT_INTERLEAVED |
1145 MR0_DLL_RESET_ON);
1146 total_rank++;
1147 }
1148 }
1149}
1150
1151static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1152{
1153 unsigned channel, slot, rank;
1154 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1155 unsigned int channel_0_non_interleaved;
1156
1157 FOR_ALL_RANKS {
1158 if (info->populated_ranks[channel][slot][rank]) {
1159 total_mb[channel] +=
1160 pre_jedec ? 256 : (256 << info->
1161 density[channel][slot] >> info->
1162 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001163 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1164 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1165 (info->is_x16_module[channel][slot] |
1166 ((info->density[channel][slot] + 1) << 1))) |
1167 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001168 }
Felix Held04be2dd2018-07-29 04:53:22 +02001169 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1170 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001171 }
1172
1173 info->total_memory_mb = total_mb[0] + total_mb[1];
1174
1175 info->interleaved_part_mb =
1176 pre_jedec ? 0 : 2 * min(total_mb[0], total_mb[1]);
1177 info->non_interleaved_part_mb =
1178 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1179 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001180 MCHBAR32(0x100) = channel_0_non_interleaved |
1181 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001182 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001183 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001184}
1185
1186static void program_board_delay(struct raminfo *info)
1187{
1188 int cas_latency_shift;
1189 int some_delay_ns;
1190 int some_delay_3_half_cycles;
1191
1192 unsigned channel, i;
1193 int high_multiplier;
1194 int lane_3_delay;
1195 int cas_latency_derived;
1196
1197 high_multiplier = 0;
1198 some_delay_ns = 200;
1199 some_delay_3_half_cycles = 4;
1200 cas_latency_shift = info->silicon_revision == 0
1201 || info->silicon_revision == 1 ? 1 : 0;
1202 if (info->revision < 8) {
1203 some_delay_ns = 600;
1204 cas_latency_shift = 0;
1205 }
1206 {
1207 int speed_bit;
1208 speed_bit =
1209 ((info->clock_speed_index > 1
1210 || (info->silicon_revision != 2
1211 && info->silicon_revision != 3))) ^ (info->revision >=
1212 0x10);
1213 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1214 3, 1);
1215 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1216 3, 1);
1217 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1218 && (info->silicon_revision == 2
1219 || info->silicon_revision == 3))
1220 rmw_1d0(0x116, 5, 2, 4, 1);
1221 }
Felix Held04be2dd2018-07-29 04:53:22 +02001222 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1223 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001224
Felix Held04be2dd2018-07-29 04:53:22 +02001225 MCHBAR8(0x124) = info->board_lane_delay[4] +
1226 ((frequency_01(info) + 999) / 1000);
1227 MCHBAR16(0x125) = 0x1360;
1228 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001229 if (info->fsb_frequency < frequency_11(info) / 2) {
1230 unsigned some_delay_2_half_cycles;
1231 high_multiplier = 1;
1232 some_delay_2_half_cycles = ps_to_halfcycles(info,
1233 ((3 *
1234 fsbcycle_ps(info))
1235 >> 1) +
1236 (halfcycle_ps(info)
1237 *
1238 reg178_min[info->
1239 clock_speed_index]
1240 >> 6)
1241 +
1242 4 *
1243 halfcycle_ps(info)
1244 + 2230);
1245 some_delay_3_half_cycles =
1246 min((some_delay_2_half_cycles +
1247 (frequency_11(info) * 2) * (28 -
1248 some_delay_2_half_cycles) /
1249 (frequency_11(info) * 2 -
1250 4 * (info->fsb_frequency))) >> 3, 7);
1251 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001252 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001253 some_delay_3_half_cycles = 3;
1254 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001255 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1256 MCHBAR32(0x224 + (channel << 10)) =
1257 (info->max_slots_used_in_channel - 1) |
1258 ((info->cas_latency - 5 - info->clock_speed_index)
1259 << 21) | ((info->max_slots_used_in_channel +
1260 info->cas_latency - cas_latency_shift - 4) << 16) |
1261 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1262 ((info->cas_latency - info->clock_speed_index +
1263 info->max_slots_used_in_channel - 6) << 8);
1264 MCHBAR32(0x228 + (channel << 10)) =
1265 info->max_slots_used_in_channel;
1266 MCHBAR8(0x239 + (channel << 10)) = 32;
1267 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1268 (some_delay_3_half_cycles << 25) | 0x840000;
1269 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1270 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1271 MCHBAR32(0x24c + (channel << 10)) =
1272 ((!!info->clock_speed_index) << 17) |
1273 (((2 + info->clock_speed_index -
1274 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001275
Felix Held04be2dd2018-07-29 04:53:22 +02001276 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1277 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1278 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001279
1280 write_500(info, channel,
1281 ((!info->populated_ranks[channel][1][1])
1282 | (!info->populated_ranks[channel][1][0] << 1)
1283 | (!info->populated_ranks[channel][0][1] << 2)
1284 | (!info->populated_ranks[channel][0][0] << 3)),
1285 0x4c9, 4, 1);
1286 }
1287
Felix Held22ca8cb2018-07-29 05:09:44 +02001288 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001289 {
1290 u8 freq_divisor = 2;
1291 if (info->fsb_frequency == frequency_11(info))
1292 freq_divisor = 3;
1293 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1294 freq_divisor = 1;
1295 else
1296 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001297 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001298 }
1299
1300 if (info->board_lane_delay[3] <= 10) {
1301 if (info->board_lane_delay[3] <= 8)
1302 lane_3_delay = info->board_lane_delay[3];
1303 else
1304 lane_3_delay = 10;
1305 } else {
1306 lane_3_delay = 12;
1307 }
1308 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1309 if (info->clock_speed_index > 1)
1310 cas_latency_derived++;
1311 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001312 MCHBAR32(0x240 + (channel << 10)) =
1313 ((info->clock_speed_index == 0) * 0x11000) |
1314 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1315 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001316 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1317 0x609, 6, 1);
1318 write_500(info, channel,
1319 info->clock_speed_index + 2 * info->cas_latency - 7,
1320 0x601, 6, 1);
1321
Felix Held04be2dd2018-07-29 04:53:22 +02001322 MCHBAR32(0x250 + (channel << 10)) =
1323 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1324 (info->board_lane_delay[7] << 2) |
1325 (info->board_lane_delay[4] << 16) |
1326 (info->board_lane_delay[1] << 25) |
1327 (info->board_lane_delay[1] << 29) | 1;
1328 MCHBAR32(0x254 + (channel << 10)) =
1329 (info->board_lane_delay[1] >> 3) |
1330 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1331 0x80 | (info->board_lane_delay[6] << 1) |
1332 (info->board_lane_delay[2] << 28) |
1333 (cas_latency_derived << 16) | 0x4700000;
1334 MCHBAR32(0x258 + (channel << 10)) =
1335 ((info->board_lane_delay[5] + info->clock_speed_index +
1336 9) << 12) | ((info->clock_speed_index -
1337 info->cas_latency + 12) << 8) |
1338 (info->board_lane_delay[2] << 17) |
1339 (info->board_lane_delay[4] << 24) | 0x47;
1340 MCHBAR32(0x25c + (channel << 10)) =
1341 (info->board_lane_delay[1] << 1) |
1342 (info->board_lane_delay[0] << 8) | 0x1da50000;
1343 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1344 MCHBAR8(0x5f8 + (channel << 10)) =
1345 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001346 }
1347
1348 program_modules_memory_map(info, 1);
1349
Felix Held04be2dd2018-07-29 04:53:22 +02001350 MCHBAR16(0x610) = (min(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
1351 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1352 MCHBAR16_OR(0x612, 0x100);
1353 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001354 for (i = 0; i < 8; i++) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001355 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0x80 + 4 * i,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001356 (info->total_memory_mb - 64) | !i | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001357 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0xc0 + 4 * i, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001358 }
1359}
1360
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001361#define DEFAULT_PCI_MMIO_SIZE 2048
1362#define HOST_BRIDGE PCI_DEVFN(0, 0)
1363
1364static unsigned int get_mmio_size(void)
1365{
1366 const struct device *dev;
1367 const struct northbridge_intel_nehalem_config *cfg = NULL;
1368
1369 dev = dev_find_slot(0, HOST_BRIDGE);
1370 if (dev)
1371 cfg = dev->chip_info;
1372
1373 /* If this is zero, it just means devicetree.cb didn't set it */
1374 if (!cfg || cfg->pci_mmio_size == 0)
1375 return DEFAULT_PCI_MMIO_SIZE;
1376 else
1377 return cfg->pci_mmio_size;
1378}
1379
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001380#define BETTER_MEMORY_MAP 0
1381
1382static void program_total_memory_map(struct raminfo *info)
1383{
1384 unsigned int TOM, TOLUD, TOUUD;
1385 unsigned int quickpath_reserved;
1386 unsigned int REMAPbase;
1387 unsigned int uma_base_igd;
1388 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001389 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001390 int memory_remap;
1391 unsigned int memory_map[8];
1392 int i;
1393 unsigned int current_limit;
1394 unsigned int tseg_base;
1395 int uma_size_igd = 0, uma_size_gtt = 0;
1396
1397 memset(memory_map, 0, sizeof(memory_map));
1398
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001399 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001400 u16 t = pci_read_config16(NORTHBRIDGE, D0F0_GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001401 gav(t);
1402 const int uma_sizes_gtt[16] =
1403 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1404 /* Igd memory */
1405 const int uma_sizes_igd[16] = {
1406 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1407 256, 512
1408 };
1409
1410 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1411 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1412 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001413
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001414 mmio_size = get_mmio_size();
1415
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001416 TOM = info->total_memory_mb;
1417 if (TOM == 4096)
1418 TOM = 4032;
1419 TOUUD = ALIGN_DOWN(TOM - info->memory_reserved_for_heci_mb, 64);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001420 TOLUD = ALIGN_DOWN(min(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
Elyes HAOUASa342f392018-10-17 10:56:26 +02001421 , TOUUD), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001422 memory_remap = 0;
1423 if (TOUUD - TOLUD > 64) {
1424 memory_remap = 1;
1425 REMAPbase = max(4096, TOUUD);
1426 TOUUD = TOUUD - TOLUD + 4096;
1427 }
1428 if (TOUUD > 4096)
1429 memory_map[2] = TOUUD | 1;
1430 quickpath_reserved = 0;
1431
1432 {
1433 u32 t;
1434
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001435 gav(t = pci_read_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 0x68));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001436 if (t & 0x800)
1437 quickpath_reserved =
1438 (1 << find_lowest_bit_set32(t >> 20));
1439 }
1440 if (memory_remap)
1441 TOUUD -= quickpath_reserved;
1442
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001443 uma_base_igd = TOLUD - uma_size_igd;
1444 uma_base_gtt = uma_base_igd - uma_size_gtt;
1445 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1446 if (!memory_remap)
1447 tseg_base -= quickpath_reserved;
1448 tseg_base = ALIGN_DOWN(tseg_base, 8);
1449
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001450 pci_write_config16(NORTHBRIDGE, D0F0_TOLUD, TOLUD << 4);
1451 pci_write_config16(NORTHBRIDGE, D0F0_TOM, TOM >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001452 if (memory_remap) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001453 pci_write_config16(NORTHBRIDGE, D0F0_REMAPBASE, REMAPbase >> 6);
1454 pci_write_config16(NORTHBRIDGE, D0F0_REMAPLIMIT, (TOUUD - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001455 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001456 pci_write_config16(NORTHBRIDGE, D0F0_TOUUD, TOUUD);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001457
1458 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001459 pci_write_config32(NORTHBRIDGE, D0F0_IGD_BASE, uma_base_igd << 20);
1460 pci_write_config32(NORTHBRIDGE, D0F0_GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001461 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001462 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001463
1464 current_limit = 0;
1465 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1466 memory_map[1] = 4096;
1467 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
1468 current_limit = max(current_limit, memory_map[i] & ~1);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001469 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0x80,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001470 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1471 1, 64) | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001472 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0xc0, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001473 }
1474}
1475
1476static void collect_system_info(struct raminfo *info)
1477{
1478 u32 capid0[3];
1479 int i;
1480 unsigned channel;
1481
1482 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001483 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1484 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001485
1486 if (!info->heci_bar)
1487 gav(info->heci_bar =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001488 pci_read_config32(HECIDEV, HECIBAR) & 0xFFFFFFF8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001489 if (!info->memory_reserved_for_heci_mb) {
1490 /* Wait for ME to be ready */
1491 intel_early_me_init();
1492 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1493 }
1494
1495 for (i = 0; i < 3; i++)
1496 gav(capid0[i] =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001497 pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 | (i << 2)));
1498 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001499 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1500
1501 if ((capid0[1] >> 11) & 1)
1502 info->uma_enabled = 0;
1503 else
1504 gav(info->uma_enabled =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001505 pci_read_config8(NORTHBRIDGE, D0F0_DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001506 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1507 info->silicon_revision = 0;
1508
1509 if (capid0[2] & 2) {
1510 info->silicon_revision = 0;
1511 info->max_supported_clock_speed_index = 2;
1512 for (channel = 0; channel < NUM_CHANNELS; channel++)
1513 if (info->populated_ranks[channel][0][0]
1514 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1515 3) {
1516 info->silicon_revision = 2;
1517 info->max_supported_clock_speed_index = 1;
1518 }
1519 } else {
1520 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1521 case 1:
1522 case 2:
1523 info->silicon_revision = 3;
1524 break;
1525 case 3:
1526 info->silicon_revision = 0;
1527 break;
1528 case 0:
1529 info->silicon_revision = 2;
1530 break;
1531 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001532 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001533 case 0x40:
1534 info->silicon_revision = 0;
1535 break;
1536 case 0x48:
1537 info->silicon_revision = 1;
1538 break;
1539 }
1540 }
1541}
1542
1543static void write_training_data(struct raminfo *info)
1544{
1545 int tm, channel, slot, rank, lane;
1546 if (info->revision < 8)
1547 return;
1548
1549 for (tm = 0; tm < 4; tm++)
1550 for (channel = 0; channel < NUM_CHANNELS; channel++)
1551 for (slot = 0; slot < NUM_SLOTS; slot++)
1552 for (rank = 0; rank < NUM_RANKS; rank++)
1553 for (lane = 0; lane < 9; lane++)
1554 write_500(info, channel,
1555 info->
1556 cached_training->
1557 lane_timings[tm]
1558 [channel][slot][rank]
1559 [lane],
1560 get_timing_register_addr
1561 (lane, tm, slot,
1562 rank), 9, 0);
1563 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1564 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1565}
1566
1567static void dump_timings(struct raminfo *info)
1568{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001569 int channel, slot, rank, lane, i;
1570 printk(BIOS_DEBUG, "Timings:\n");
1571 FOR_POPULATED_RANKS {
1572 printk(BIOS_DEBUG, "channel %d, slot %d, rank %d\n", channel,
1573 slot, rank);
1574 for (lane = 0; lane < 9; lane++) {
1575 printk(BIOS_DEBUG, "lane %d: ", lane);
1576 for (i = 0; i < 4; i++) {
1577 printk(BIOS_DEBUG, "%x (%x) ",
1578 read_500(info, channel,
1579 get_timing_register_addr
1580 (lane, i, slot, rank),
1581 9),
1582 info->training.
1583 lane_timings[i][channel][slot][rank]
1584 [lane]);
1585 }
1586 printk(BIOS_DEBUG, "\n");
1587 }
1588 }
1589 printk(BIOS_DEBUG, "[178] = %x (%x)\n", read_1d0(0x178, 7),
1590 info->training.reg_178);
1591 printk(BIOS_DEBUG, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
1592 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001593}
1594
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001595/* Read timings and other registers that need to be restored verbatim and
1596 put them to CBMEM.
1597 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001598static void save_timings(struct raminfo *info)
1599{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001600 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001601 int channel, slot, rank, lane, i;
1602
1603 train = info->training;
1604 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1605 for (i = 0; i < 4; i++)
1606 train.lane_timings[i][channel][slot][rank][lane] =
1607 read_500(info, channel,
1608 get_timing_register_addr(lane, i, slot,
1609 rank), 9);
1610 train.reg_178 = read_1d0(0x178, 7);
1611 train.reg_10b = read_1d0(0x10b, 6);
1612
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001613 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1614 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001615 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001616 train.reg274265[channel][0] = reg32 >> 16;
1617 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001618 train.reg274265[channel][2] =
1619 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001620 }
Felix Held04be2dd2018-07-29 04:53:22 +02001621 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1622 train.reg_6dc = MCHBAR32(0x6dc);
1623 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001624
1625 printk (BIOS_SPEW, "[6dc] = %x\n", train.reg_6dc);
1626 printk (BIOS_SPEW, "[6e8] = %x\n", train.reg_6e8);
1627
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001628 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001629 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1630 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001631}
1632
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001633static const struct ram_training *get_cached_training(void)
1634{
Arthur Heymansdc71e252018-01-29 10:14:48 +01001635 struct region_device rdev;
1636 if (mrc_cache_get_current(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1637 &rdev))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001638 return 0;
Arthur Heymansdc71e252018-01-29 10:14:48 +01001639 return (void *)rdev_mmap_full(&rdev);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001640}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001641
1642/* FIXME: add timeout. */
1643static void wait_heci_ready(void)
1644{
Felix Held04be2dd2018-07-29 04:53:22 +02001645 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1646 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001647 write32((DEFAULT_HECIBAR + 0x4),
1648 (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001649}
1650
1651/* FIXME: add timeout. */
1652static void wait_heci_cb_avail(int len)
1653{
1654 union {
1655 struct mei_csr csr;
1656 u32 raw;
1657 } csr;
1658
Felix Held22ca8cb2018-07-29 05:09:44 +02001659 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1660 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001661
1662 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001663 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001664 while (len >
1665 csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
Felix Held22ca8cb2018-07-29 05:09:44 +02001666 csr.csr.buffer_read_ptr))
1667 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001668}
1669
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001670static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001671{
1672 int len = (head->length + 3) / 4;
1673 int i;
1674
1675 wait_heci_cb_avail(len + 1);
1676
1677 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001678 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001679 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001680 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001681
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001682 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1683 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001684}
1685
1686static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001687send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001688{
1689 struct mei_header head;
1690 int maxlen;
1691
1692 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001693 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001694
1695 while (len) {
1696 int cur = len;
1697 if (cur > maxlen) {
1698 cur = maxlen;
1699 head.is_complete = 0;
1700 } else
1701 head.is_complete = 1;
1702 head.length = cur;
1703 head.reserved = 0;
1704 head.client_address = clientaddress;
1705 head.host_address = hostaddress;
1706 send_heci_packet(&head, (u32 *) msg);
1707 len -= cur;
1708 msg += cur;
1709 }
1710}
1711
1712/* FIXME: Add timeout. */
1713static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001714recv_heci_packet(struct raminfo *info, struct mei_header *head, u32 *packet,
1715 u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001716{
1717 union {
1718 struct mei_csr csr;
1719 u32 raw;
1720 } csr;
1721 int i = 0;
1722
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001723 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001724 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001725 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001726 }
Felix Held04be2dd2018-07-29 04:53:22 +02001727 while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr)
1728 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001729 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001730 if (!head->length) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001731 write32(DEFAULT_HECIBAR + 0x4,
1732 read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001733 *packet_size = 0;
1734 return 0;
1735 }
1736 if (head->length + 4 > 4 * csr.csr.buffer_depth
1737 || head->length > *packet_size) {
1738 *packet_size = 0;
1739 return -1;
1740 }
1741
1742 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001743 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Felix Held22ca8cb2018-07-29 05:09:44 +02001744 while (((head->length + 3) >> 2) >
1745 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr))
1746 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001747
1748 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001749 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001750 *packet_size = head->length;
1751 if (!csr.csr.ready)
1752 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001753 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001754 return 0;
1755}
1756
1757/* FIXME: Add timeout. */
1758static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001759recv_heci_message(struct raminfo *info, u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001760{
1761 struct mei_header head;
1762 int current_position;
1763
1764 current_position = 0;
1765 while (1) {
1766 u32 current_size;
1767 current_size = *message_size - current_position;
1768 if (recv_heci_packet
1769 (info, &head, message + (current_position >> 2),
1770 &current_size) == -1)
1771 break;
1772 if (!current_size)
1773 break;
1774 current_position += current_size;
1775 if (head.is_complete) {
1776 *message_size = current_position;
1777 return 0;
1778 }
1779
1780 if (current_position >= *message_size)
1781 break;
1782 }
1783 *message_size = 0;
1784 return -1;
1785}
1786
1787static void send_heci_uma_message(struct raminfo *info)
1788{
1789 struct uma_reply {
1790 u8 group_id;
1791 u8 command;
1792 u8 reserved;
1793 u8 result;
1794 u8 field2;
1795 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001796 } __packed reply;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001797 struct uma_message {
1798 u8 group_id;
1799 u8 cmd;
1800 u8 reserved;
1801 u8 result;
1802 u32 c2;
1803 u64 heci_uma_addr;
1804 u32 memory_reserved_for_heci_mb;
1805 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001806 } __packed msg = {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001807 0, MKHI_SET_UMA, 0, 0,
1808 0x82,
1809 info->heci_uma_addr, info->memory_reserved_for_heci_mb, 0};
1810 u32 reply_size;
1811
1812 send_heci_message((u8 *) & msg, sizeof(msg), 0, 7);
1813
1814 reply_size = sizeof(reply);
1815 if (recv_heci_message(info, (u32 *) & reply, &reply_size) == -1)
1816 return;
1817
1818 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1819 die("HECI init failed\n");
1820}
1821
1822static void setup_heci_uma(struct raminfo *info)
1823{
1824 u32 reg44;
1825
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001826 reg44 = pci_read_config32(HECIDEV, 0x44); // = 0x80010020
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001827 info->memory_reserved_for_heci_mb = 0;
1828 info->heci_uma_addr = 0;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001829 if (!((reg44 & 0x10000) && !(pci_read_config32(HECIDEV, 0x40) & 0x20)))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001830 return;
1831
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001832 info->heci_bar = pci_read_config32(HECIDEV, 0x10) & 0xFFFFFFF0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001833 info->memory_reserved_for_heci_mb = reg44 & 0x3f;
1834 info->heci_uma_addr =
1835 ((u64)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001836 ((((u64) pci_read_config16(NORTHBRIDGE, D0F0_TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001837 info->memory_reserved_for_heci_mb)) << 20;
1838
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001839 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001840 if (info->memory_reserved_for_heci_mb) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001841 write32(DEFAULT_DMIBAR + 0x14,
1842 read32(DEFAULT_DMIBAR + 0x14) & ~0x80);
1843 write32(DEFAULT_RCBA + 0x14,
1844 read32(DEFAULT_RCBA + 0x14) & ~0x80);
1845 write32(DEFAULT_DMIBAR + 0x20,
1846 read32(DEFAULT_DMIBAR + 0x20) & ~0x80);
1847 write32(DEFAULT_RCBA + 0x20,
1848 read32(DEFAULT_RCBA + 0x20) & ~0x80);
1849 write32(DEFAULT_DMIBAR + 0x2c,
1850 read32(DEFAULT_DMIBAR + 0x2c) & ~0x80);
1851 write32(DEFAULT_RCBA + 0x30,
1852 read32(DEFAULT_RCBA + 0x30) & ~0x80);
1853 write32(DEFAULT_DMIBAR + 0x38,
1854 read32(DEFAULT_DMIBAR + 0x38) & ~0x80);
1855 write32(DEFAULT_RCBA + 0x40,
1856 read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001857
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001858 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
1859 write32(DEFAULT_DMIBAR + 0x38, 0x87000080); // OK
Felix Held04be2dd2018-07-29 04:53:22 +02001860 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
1861 read16(DEFAULT_DMIBAR + 0x3e) & 2)
1862 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001863 }
1864
Felix Held04be2dd2018-07-29 04:53:22 +02001865 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001866
1867 send_heci_uma_message(info);
1868
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001869 pci_write_config32(HECIDEV, 0x10, 0x0);
1870 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001871
1872}
1873
1874static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1875{
1876 int ranks_in_channel;
1877 ranks_in_channel = info->populated_ranks[channel][0][0]
1878 + info->populated_ranks[channel][0][1]
1879 + info->populated_ranks[channel][1][0]
1880 + info->populated_ranks[channel][1][1];
1881
1882 /* empty channel */
1883 if (ranks_in_channel == 0)
1884 return 1;
1885
1886 if (ranks_in_channel != ranks)
1887 return 0;
1888 /* single slot */
1889 if (info->populated_ranks[channel][0][0] !=
1890 info->populated_ranks[channel][1][0])
1891 return 1;
1892 if (info->populated_ranks[channel][0][1] !=
1893 info->populated_ranks[channel][1][1])
1894 return 1;
1895 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1896 return 0;
1897 if (info->density[channel][0] != info->density[channel][1])
1898 return 0;
1899 return 1;
1900}
1901
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001902static void read_4090(struct raminfo *info)
1903{
1904 int i, channel, slot, rank, lane;
1905 for (i = 0; i < 2; i++)
1906 for (slot = 0; slot < NUM_SLOTS; slot++)
1907 for (rank = 0; rank < NUM_RANKS; rank++)
1908 for (lane = 0; lane < 9; lane++)
1909 info->training.
1910 lane_timings[0][i][slot][rank][lane]
1911 = 32;
1912
1913 for (i = 1; i < 4; i++)
1914 for (channel = 0; channel < NUM_CHANNELS; channel++)
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[i][channel]
1920 [slot][rank][lane] =
1921 read_500(info, channel,
1922 get_timing_register_addr
1923 (lane, i, slot,
1924 rank), 9)
1925 + (i == 1) * 11; // !!!!
1926 }
1927
1928}
1929
1930static u32 get_etalon2(int flip, u32 addr)
1931{
1932 const u16 invmask[] = {
1933 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1934 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1935 };
1936 u32 ret;
1937 u32 comp4 = addr / 480;
1938 addr %= 480;
1939 u32 comp1 = addr & 0xf;
1940 u32 comp2 = (addr >> 4) & 1;
1941 u32 comp3 = addr >> 5;
1942
1943 if (comp4)
1944 ret = 0x1010101 << (comp4 - 1);
1945 else
1946 ret = 0;
1947 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1948 ret = ~ret;
1949
1950 return ret;
1951}
1952
1953static void disable_cache(void)
1954{
1955 msr_t msr = {.lo = 0, .hi = 0 };
1956
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001957 wrmsr(MTRR_PHYS_BASE(3), msr);
1958 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001959}
1960
1961static void enable_cache(unsigned int base, unsigned int size)
1962{
1963 msr_t msr;
1964 msr.lo = base | MTRR_TYPE_WRPROT;
1965 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001966 wrmsr(MTRR_PHYS_BASE(3), msr);
1967 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001968 & 0xffffffff);
1969 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001970 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001971}
1972
1973static void flush_cache(u32 start, u32 size)
1974{
1975 u32 end;
1976 u32 addr;
1977
1978 end = start + (ALIGN_DOWN(size + 4096, 4096));
1979 for (addr = start; addr < end; addr += 64)
1980 clflush(addr);
1981}
1982
1983static void clear_errors(void)
1984{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001985 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001986}
1987
1988static void write_testing(struct raminfo *info, int totalrank, int flip)
1989{
1990 int nwrites = 0;
1991 /* in 8-byte units. */
1992 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001993 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001994
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001995 base = (u8 *)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001996 for (offset = 0; offset < 9 * 480; offset += 2) {
1997 write32(base + offset * 8, get_etalon2(flip, offset));
1998 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1999 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
2000 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
2001 nwrites += 4;
2002 if (nwrites >= 320) {
2003 clear_errors();
2004 nwrites = 0;
2005 }
2006 }
2007}
2008
2009static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
2010{
2011 u8 failmask = 0;
2012 int i;
2013 int comp1, comp2, comp3;
2014 u32 failxor[2] = { 0, 0 };
2015
2016 enable_cache((total_rank << 28), 1728 * 5 * 4);
2017
2018 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
2019 for (comp1 = 0; comp1 < 4; comp1++)
2020 for (comp2 = 0; comp2 < 60; comp2++) {
2021 u32 re[4];
2022 u32 curroffset =
2023 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
2024 read128((total_rank << 28) | (curroffset << 3),
2025 (u64 *) re);
2026 failxor[0] |=
2027 get_etalon2(flip, curroffset) ^ re[0];
2028 failxor[1] |=
2029 get_etalon2(flip, curroffset) ^ re[1];
2030 failxor[0] |=
2031 get_etalon2(flip, curroffset | 1) ^ re[2];
2032 failxor[1] |=
2033 get_etalon2(flip, curroffset | 1) ^ re[3];
2034 }
2035 for (i = 0; i < 8; i++)
2036 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2037 failmask |= 1 << i;
2038 }
2039 disable_cache();
2040 flush_cache((total_rank << 28), 1728 * 5 * 4);
2041 return failmask;
2042}
2043
2044const u32 seed1[0x18] = {
2045 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2046 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2047 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2048 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2049 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2050 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2051};
2052
2053static u32 get_seed2(int a, int b)
2054{
2055 const u32 seed2[5] = {
2056 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2057 0x5b6db6db,
2058 };
2059 u32 r;
2060 r = seed2[(a + (a >= 10)) / 5];
2061 return b ? ~r : r;
2062}
2063
2064static int make_shift(int comp2, int comp5, int x)
2065{
2066 const u8 seed3[32] = {
2067 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2068 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2069 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2070 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2071 };
2072
2073 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2074}
2075
2076static u32 get_etalon(int flip, u32 addr)
2077{
2078 u32 mask_byte = 0;
2079 int comp1 = (addr >> 1) & 1;
2080 int comp2 = (addr >> 3) & 0x1f;
2081 int comp3 = (addr >> 8) & 0xf;
2082 int comp4 = (addr >> 12) & 0xf;
2083 int comp5 = (addr >> 16) & 0x1f;
2084 u32 mask_bit = ~(0x10001 << comp3);
2085 u32 part1;
2086 u32 part2;
2087 int byte;
2088
2089 part2 =
2090 ((seed1[comp5] >>
2091 make_shift(comp2, comp5,
2092 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2093 part1 =
2094 ((seed1[comp5] >>
2095 make_shift(comp2, comp5,
2096 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2097
2098 for (byte = 0; byte < 4; byte++)
2099 if ((get_seed2(comp5, comp4) >>
2100 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2101 mask_byte |= 0xff << (8 * byte);
2102
2103 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2104 (comp3 + 16));
2105}
2106
2107static void
2108write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2109 char flip)
2110{
2111 int i;
2112 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002113 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2114 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002115}
2116
2117static u8
2118check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2119 char flip)
2120{
2121 u8 failmask = 0;
2122 u32 failxor[2];
2123 int i;
2124 int comp1, comp2, comp3;
2125
2126 failxor[0] = 0;
2127 failxor[1] = 0;
2128
2129 enable_cache(totalrank << 28, 134217728);
2130 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2131 for (comp1 = 0; comp1 < 16; comp1++)
2132 for (comp2 = 0; comp2 < 64; comp2++) {
2133 u32 addr =
2134 (totalrank << 28) | (region << 25) | (block
2135 << 16)
2136 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2137 2);
2138 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002139 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002140 }
2141 for (i = 0; i < 8; i++)
2142 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2143 failmask |= 1 << i;
2144 }
2145 disable_cache();
2146 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2147 return failmask;
2148}
2149
2150static int check_bounded(unsigned short *vals, u16 bound)
2151{
2152 int i;
2153
2154 for (i = 0; i < 8; i++)
2155 if (vals[i] < bound)
2156 return 0;
2157 return 1;
2158}
2159
2160enum state {
2161 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2162};
2163
2164static int validate_state(enum state *in)
2165{
2166 int i;
2167 for (i = 0; i < 8; i++)
2168 if (in[i] != COMPLETE)
2169 return 0;
2170 return 1;
2171}
2172
2173static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002174do_fsm(enum state *state, u16 *counter,
2175 u8 fail_mask, int margin, int uplimit,
2176 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002177{
2178 int lane;
2179
2180 for (lane = 0; lane < 8; lane++) {
2181 int is_fail = (fail_mask >> lane) & 1;
2182 switch (state[lane]) {
2183 case BEFORE_USABLE:
2184 if (!is_fail) {
2185 counter[lane] = 1;
2186 state[lane] = AT_USABLE;
2187 break;
2188 }
2189 counter[lane] = 0;
2190 state[lane] = BEFORE_USABLE;
2191 break;
2192 case AT_USABLE:
2193 if (!is_fail) {
2194 ++counter[lane];
2195 if (counter[lane] >= margin) {
2196 state[lane] = AT_MARGIN;
2197 res_low[lane] = val - margin + 1;
2198 break;
2199 }
2200 state[lane] = 1;
2201 break;
2202 }
2203 counter[lane] = 0;
2204 state[lane] = BEFORE_USABLE;
2205 break;
2206 case AT_MARGIN:
2207 if (is_fail) {
2208 state[lane] = COMPLETE;
2209 res_high[lane] = val - 1;
2210 } else {
2211 counter[lane]++;
2212 state[lane] = AT_MARGIN;
2213 if (val == uplimit) {
2214 state[lane] = COMPLETE;
2215 res_high[lane] = uplimit;
2216 }
2217 }
2218 break;
2219 case COMPLETE:
2220 break;
2221 }
2222 }
2223}
2224
2225static void
2226train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2227 u8 total_rank, u8 reg_178, int first_run, int niter,
2228 timing_bounds_t * timings)
2229{
2230 int lane;
2231 enum state state[8];
2232 u16 count[8];
2233 u8 lower_usable[8];
2234 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002235 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002236 u8 secondary_total_rank;
2237 u8 reg1b3;
2238
2239 if (info->populated_ranks_mask[1]) {
2240 if (channel == 1)
2241 secondary_total_rank =
2242 info->populated_ranks[1][0][0] +
2243 info->populated_ranks[1][0][1]
2244 + info->populated_ranks[1][1][0] +
2245 info->populated_ranks[1][1][1];
2246 else
2247 secondary_total_rank = 0;
2248 } else
2249 secondary_total_rank = total_rank;
2250
2251 {
2252 int i;
2253 for (i = 0; i < 8; i++)
2254 state[i] = BEFORE_USABLE;
2255 }
2256
2257 if (!first_run) {
2258 int is_all_ok = 1;
2259 for (lane = 0; lane < 8; lane++)
2260 if (timings[reg_178][channel][slot][rank][lane].
2261 smallest ==
2262 timings[reg_178][channel][slot][rank][lane].
2263 largest) {
2264 timings[reg_178][channel][slot][rank][lane].
2265 smallest = 0;
2266 timings[reg_178][channel][slot][rank][lane].
2267 largest = 0;
2268 is_all_ok = 0;
2269 }
2270 if (is_all_ok) {
2271 int i;
2272 for (i = 0; i < 8; i++)
2273 state[i] = COMPLETE;
2274 }
2275 }
2276
2277 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2278 u8 failmask = 0;
2279 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2280 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2281 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002282 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002283 do_fsm(state, count, failmask, 5, 47, lower_usable,
2284 upper_usable, reg1b3);
2285 }
2286
2287 if (reg1b3) {
2288 write_1d0(0, 0x1b3, 6, 1);
2289 write_1d0(0, 0x1a3, 6, 1);
2290 for (lane = 0; lane < 8; lane++) {
2291 if (state[lane] == COMPLETE) {
2292 timings[reg_178][channel][slot][rank][lane].
2293 smallest =
2294 lower_usable[lane] +
2295 (info->training.
2296 lane_timings[0][channel][slot][rank][lane]
2297 & 0x3F) - 32;
2298 timings[reg_178][channel][slot][rank][lane].
2299 largest =
2300 upper_usable[lane] +
2301 (info->training.
2302 lane_timings[0][channel][slot][rank][lane]
2303 & 0x3F) - 32;
2304 }
2305 }
2306 }
2307
2308 if (!first_run) {
2309 for (lane = 0; lane < 8; lane++)
2310 if (state[lane] == COMPLETE) {
2311 write_500(info, channel,
2312 timings[reg_178][channel][slot][rank]
2313 [lane].smallest,
2314 get_timing_register_addr(lane, 0,
2315 slot, rank),
2316 9, 1);
2317 write_500(info, channel,
2318 timings[reg_178][channel][slot][rank]
2319 [lane].smallest +
2320 info->training.
2321 lane_timings[1][channel][slot][rank]
2322 [lane]
2323 -
2324 info->training.
2325 lane_timings[0][channel][slot][rank]
2326 [lane], get_timing_register_addr(lane,
2327 1,
2328 slot,
2329 rank),
2330 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002331 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002332 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002333 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002334
2335 do {
2336 u8 failmask = 0;
2337 int i;
2338 for (i = 0; i < niter; i++) {
2339 if (failmask == 0xFF)
2340 break;
2341 failmask |=
2342 check_testing_type2(info, total_rank, 2, i,
2343 0);
2344 failmask |=
2345 check_testing_type2(info, total_rank, 3, i,
2346 1);
2347 }
Felix Held04be2dd2018-07-29 04:53:22 +02002348 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002349 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002350 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002351 if ((1 << lane) & failmask) {
2352 if (timings[reg_178][channel]
2353 [slot][rank][lane].
2354 largest <=
2355 timings[reg_178][channel]
2356 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002357 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002358 [lane] = -1;
2359 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002360 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002361 [lane] = 0;
2362 timings[reg_178]
2363 [channel][slot]
2364 [rank][lane].
2365 smallest++;
2366 write_500(info, channel,
2367 timings
2368 [reg_178]
2369 [channel]
2370 [slot][rank]
2371 [lane].
2372 smallest,
2373 get_timing_register_addr
2374 (lane, 0,
2375 slot, rank),
2376 9, 1);
2377 write_500(info, channel,
2378 timings
2379 [reg_178]
2380 [channel]
2381 [slot][rank]
2382 [lane].
2383 smallest +
2384 info->
2385 training.
2386 lane_timings
2387 [1][channel]
2388 [slot][rank]
2389 [lane]
2390 -
2391 info->
2392 training.
2393 lane_timings
2394 [0][channel]
2395 [slot][rank]
2396 [lane],
2397 get_timing_register_addr
2398 (lane, 1,
2399 slot, rank),
2400 9, 1);
2401 }
2402 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002403 num_successfully_checked[lane]
2404 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002405 }
2406 }
Felix Held04be2dd2018-07-29 04:53:22 +02002407 while (!check_bounded(num_successfully_checked, 2))
2408 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002409
2410 for (lane = 0; lane < 8; lane++)
2411 if (state[lane] == COMPLETE) {
2412 write_500(info, channel,
2413 timings[reg_178][channel][slot][rank]
2414 [lane].largest,
2415 get_timing_register_addr(lane, 0,
2416 slot, rank),
2417 9, 1);
2418 write_500(info, channel,
2419 timings[reg_178][channel][slot][rank]
2420 [lane].largest +
2421 info->training.
2422 lane_timings[1][channel][slot][rank]
2423 [lane]
2424 -
2425 info->training.
2426 lane_timings[0][channel][slot][rank]
2427 [lane], get_timing_register_addr(lane,
2428 1,
2429 slot,
2430 rank),
2431 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002432 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002433 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002434 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002435
2436 do {
2437 int failmask = 0;
2438 int i;
2439 for (i = 0; i < niter; i++) {
2440 if (failmask == 0xFF)
2441 break;
2442 failmask |=
2443 check_testing_type2(info, total_rank, 2, i,
2444 0);
2445 failmask |=
2446 check_testing_type2(info, total_rank, 3, i,
2447 1);
2448 }
2449
Felix Held04be2dd2018-07-29 04:53:22 +02002450 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002451 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002452 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002453 if ((1 << lane) & failmask) {
2454 if (timings[reg_178][channel]
2455 [slot][rank][lane].
2456 largest <=
2457 timings[reg_178][channel]
2458 [slot][rank][lane].
2459 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002460 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002461 [lane] = -1;
2462 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002463 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002464 [lane] = 0;
2465 timings[reg_178]
2466 [channel][slot]
2467 [rank][lane].
2468 largest--;
2469 write_500(info, channel,
2470 timings
2471 [reg_178]
2472 [channel]
2473 [slot][rank]
2474 [lane].
2475 largest,
2476 get_timing_register_addr
2477 (lane, 0,
2478 slot, rank),
2479 9, 1);
2480 write_500(info, channel,
2481 timings
2482 [reg_178]
2483 [channel]
2484 [slot][rank]
2485 [lane].
2486 largest +
2487 info->
2488 training.
2489 lane_timings
2490 [1][channel]
2491 [slot][rank]
2492 [lane]
2493 -
2494 info->
2495 training.
2496 lane_timings
2497 [0][channel]
2498 [slot][rank]
2499 [lane],
2500 get_timing_register_addr
2501 (lane, 1,
2502 slot, rank),
2503 9, 1);
2504 }
2505 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002506 num_successfully_checked[lane]
2507 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002508 }
2509 }
2510 }
Felix Held04be2dd2018-07-29 04:53:22 +02002511 while (!check_bounded(num_successfully_checked, 3))
2512 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002513
2514 for (lane = 0; lane < 8; lane++) {
2515 write_500(info, channel,
2516 info->training.
2517 lane_timings[0][channel][slot][rank][lane],
2518 get_timing_register_addr(lane, 0, slot, rank),
2519 9, 1);
2520 write_500(info, channel,
2521 info->training.
2522 lane_timings[1][channel][slot][rank][lane],
2523 get_timing_register_addr(lane, 1, slot, rank),
2524 9, 1);
2525 if (timings[reg_178][channel][slot][rank][lane].
2526 largest <=
2527 timings[reg_178][channel][slot][rank][lane].
2528 smallest) {
2529 timings[reg_178][channel][slot][rank][lane].
2530 largest = 0;
2531 timings[reg_178][channel][slot][rank][lane].
2532 smallest = 0;
2533 }
2534 }
2535 }
2536}
2537
2538static void set_10b(struct raminfo *info, u8 val)
2539{
2540 int channel;
2541 int slot, rank;
2542 int lane;
2543
2544 if (read_1d0(0x10b, 6) == val)
2545 return;
2546
2547 write_1d0(val, 0x10b, 6, 1);
2548
2549 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2550 u16 reg_500;
2551 reg_500 = read_500(info, channel,
2552 get_timing_register_addr(lane, 0, slot,
2553 rank), 9);
2554 if (val == 1) {
2555 if (lut16[info->clock_speed_index] <= reg_500)
2556 reg_500 -= lut16[info->clock_speed_index];
2557 else
2558 reg_500 = 0;
2559 } else {
2560 reg_500 += lut16[info->clock_speed_index];
2561 }
2562 write_500(info, channel, reg_500,
2563 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2564 }
2565}
2566
2567static void set_ecc(int onoff)
2568{
2569 int channel;
2570 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2571 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002572 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002573 if (onoff)
2574 t |= 1;
2575 else
2576 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002577 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002578 }
2579}
2580
2581static void set_178(u8 val)
2582{
2583 if (val >= 31)
2584 val = val - 31;
2585 else
2586 val = 63 - val;
2587
2588 write_1d0(2 * val, 0x178, 7, 1);
2589}
2590
2591static void
2592write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2593 int type)
2594{
2595 int lane;
2596
2597 for (lane = 0; lane < 8; lane++)
2598 write_500(info, channel,
2599 info->training.
2600 lane_timings[type][channel][slot][rank][lane],
2601 get_timing_register_addr(lane, type, slot, rank), 9,
2602 0);
2603}
2604
2605static void
2606try_timing_offsets(struct raminfo *info, int channel,
2607 int slot, int rank, int totalrank)
2608{
2609 u16 count[8];
2610 enum state state[8];
2611 u8 lower_usable[8], upper_usable[8];
2612 int lane;
2613 int i;
2614 int flip = 1;
2615 int timing_offset;
2616
2617 for (i = 0; i < 8; i++)
2618 state[i] = BEFORE_USABLE;
2619
2620 memset(count, 0, sizeof(count));
2621
2622 for (lane = 0; lane < 8; lane++)
2623 write_500(info, channel,
2624 info->training.
2625 lane_timings[2][channel][slot][rank][lane] + 32,
2626 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2627
2628 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2629 timing_offset++) {
2630 u8 failmask;
2631 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2632 failmask = 0;
2633 for (i = 0; i < 2 && failmask != 0xff; i++) {
2634 flip = !flip;
2635 write_testing(info, totalrank, flip);
2636 failmask |= check_testing(info, totalrank, flip);
2637 }
2638 do_fsm(state, count, failmask, 10, 63, lower_usable,
2639 upper_usable, timing_offset);
2640 }
2641 write_1d0(0, 0x1bb, 6, 1);
2642 dump_timings(info);
2643 if (!validate_state(state))
2644 die("Couldn't discover DRAM timings (1)\n");
2645
2646 for (lane = 0; lane < 8; lane++) {
2647 u8 bias = 0;
2648
2649 if (info->silicon_revision) {
2650 int usable_length;
2651
2652 usable_length = upper_usable[lane] - lower_usable[lane];
2653 if (usable_length >= 20) {
2654 bias = usable_length / 2 - 10;
2655 if (bias >= 2)
2656 bias = 2;
2657 }
2658 }
2659 write_500(info, channel,
2660 info->training.
2661 lane_timings[2][channel][slot][rank][lane] +
2662 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2663 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2664 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2665 info->training.lane_timings[2][channel][slot][rank][lane] +
2666 lower_usable[lane];
2667 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2668 info->training.lane_timings[2][channel][slot][rank][lane] +
2669 upper_usable[lane];
2670 info->training.timing2_offset[channel][slot][rank][lane] =
2671 info->training.lane_timings[2][channel][slot][rank][lane];
2672 }
2673}
2674
2675static u8
2676choose_training(struct raminfo *info, int channel, int slot, int rank,
2677 int lane, timing_bounds_t * timings, u8 center_178)
2678{
2679 u16 central_weight;
2680 u16 side_weight;
2681 unsigned int sum = 0, count = 0;
2682 u8 span;
2683 u8 lower_margin, upper_margin;
2684 u8 reg_178;
2685 u8 result;
2686
2687 span = 12;
2688 central_weight = 20;
2689 side_weight = 20;
2690 if (info->silicon_revision == 1 && channel == 1) {
2691 central_weight = 5;
2692 side_weight = 20;
2693 if ((info->
2694 populated_ranks_mask[1] ^ (info->
2695 populated_ranks_mask[1] >> 2)) &
2696 1)
2697 span = 18;
2698 }
2699 if ((info->populated_ranks_mask[0] & 5) == 5) {
2700 central_weight = 20;
2701 side_weight = 20;
2702 }
2703 if (info->clock_speed_index >= 2
2704 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2705 if (info->silicon_revision == 1) {
2706 switch (channel) {
2707 case 0:
2708 if (lane == 1) {
2709 central_weight = 10;
2710 side_weight = 20;
2711 }
2712 break;
2713 case 1:
2714 if (lane == 6) {
2715 side_weight = 5;
2716 central_weight = 20;
2717 }
2718 break;
2719 }
2720 }
2721 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2722 side_weight = 5;
2723 central_weight = 20;
2724 }
2725 }
2726 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2727 reg_178 += span) {
2728 u8 smallest;
2729 u8 largest;
2730 largest = timings[reg_178][channel][slot][rank][lane].largest;
2731 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2732 if (largest - smallest + 1 >= 5) {
2733 unsigned int weight;
2734 if (reg_178 == center_178)
2735 weight = central_weight;
2736 else
2737 weight = side_weight;
2738 sum += weight * (largest + smallest);
2739 count += weight;
2740 }
2741 }
2742 dump_timings(info);
2743 if (count == 0)
2744 die("Couldn't discover DRAM timings (2)\n");
2745 result = sum / (2 * count);
2746 lower_margin =
2747 result - timings[center_178][channel][slot][rank][lane].smallest;
2748 upper_margin =
2749 timings[center_178][channel][slot][rank][lane].largest - result;
2750 if (upper_margin < 10 && lower_margin > 10)
2751 result -= min(lower_margin - 10, 10 - upper_margin);
2752 if (upper_margin > 10 && lower_margin < 10)
2753 result += min(upper_margin - 10, 10 - lower_margin);
2754 return result;
2755}
2756
2757#define STANDARD_MIN_MARGIN 5
2758
2759static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2760{
2761 u16 margin[64];
2762 int lane, rank, slot, channel;
2763 u8 reg178;
2764 int count = 0, sum = 0;
2765
2766 for (reg178 = reg178_min[info->clock_speed_index];
2767 reg178 < reg178_max[info->clock_speed_index];
2768 reg178 += reg178_step[info->clock_speed_index]) {
2769 margin[reg178] = -1;
2770 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2771 int curmargin =
2772 timings[reg178][channel][slot][rank][lane].largest -
2773 timings[reg178][channel][slot][rank][lane].
2774 smallest + 1;
2775 if (curmargin < margin[reg178])
2776 margin[reg178] = curmargin;
2777 }
2778 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2779 u16 weight;
2780 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2781 sum += weight * reg178;
2782 count += weight;
2783 }
2784 }
2785 dump_timings(info);
2786 if (count == 0)
2787 die("Couldn't discover DRAM timings (3)\n");
2788
2789 u8 threshold;
2790
2791 for (threshold = 30; threshold >= 5; threshold--) {
2792 int usable_length = 0;
2793 int smallest_fount = 0;
2794 for (reg178 = reg178_min[info->clock_speed_index];
2795 reg178 < reg178_max[info->clock_speed_index];
2796 reg178 += reg178_step[info->clock_speed_index])
2797 if (margin[reg178] >= threshold) {
2798 usable_length +=
2799 reg178_step[info->clock_speed_index];
2800 info->training.reg178_largest =
2801 reg178 -
2802 2 * reg178_step[info->clock_speed_index];
2803
2804 if (!smallest_fount) {
2805 smallest_fount = 1;
2806 info->training.reg178_smallest =
2807 reg178 +
2808 reg178_step[info->
2809 clock_speed_index];
2810 }
2811 }
2812 if (usable_length >= 0x21)
2813 break;
2814 }
2815
2816 return sum / count;
2817}
2818
2819static int check_cached_sanity(struct raminfo *info)
2820{
2821 int lane;
2822 int slot, rank;
2823 int channel;
2824
2825 if (!info->cached_training)
2826 return 0;
2827
2828 for (channel = 0; channel < NUM_CHANNELS; channel++)
2829 for (slot = 0; slot < NUM_SLOTS; slot++)
2830 for (rank = 0; rank < NUM_RANKS; rank++)
2831 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2832 u16 cached_value, estimation_value;
2833 cached_value =
2834 info->cached_training->
2835 lane_timings[1][channel][slot][rank]
2836 [lane];
2837 if (cached_value >= 0x18
2838 && cached_value <= 0x1E7) {
2839 estimation_value =
2840 info->training.
2841 lane_timings[1][channel]
2842 [slot][rank][lane];
2843 if (estimation_value <
2844 cached_value - 24)
2845 return 0;
2846 if (estimation_value >
2847 cached_value + 24)
2848 return 0;
2849 }
2850 }
2851 return 1;
2852}
2853
2854static int try_cached_training(struct raminfo *info)
2855{
2856 u8 saved_243[2];
2857 u8 tm;
2858
2859 int channel, slot, rank, lane;
2860 int flip = 1;
2861 int i, j;
2862
2863 if (!check_cached_sanity(info))
2864 return 0;
2865
2866 info->training.reg178_center = info->cached_training->reg178_center;
2867 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2868 info->training.reg178_largest = info->cached_training->reg178_largest;
2869 memcpy(&info->training.timing_bounds,
2870 &info->cached_training->timing_bounds,
2871 sizeof(info->training.timing_bounds));
2872 memcpy(&info->training.timing_offset,
2873 &info->cached_training->timing_offset,
2874 sizeof(info->training.timing_offset));
2875
2876 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002877 saved_243[0] = MCHBAR8(0x243);
2878 saved_243[1] = MCHBAR8(0x643);
2879 MCHBAR8(0x243) = saved_243[0] | 2;
2880 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002881 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002882 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002883 if (read_1d0(0x10b, 6) & 1)
2884 set_10b(info, 0);
2885 for (tm = 0; tm < 2; tm++) {
2886 int totalrank;
2887
2888 set_178(tm ? info->cached_training->reg178_largest : info->
2889 cached_training->reg178_smallest);
2890
2891 totalrank = 0;
2892 /* Check timing ranges. With i == 0 we check smallest one and with
2893 i == 1 the largest bound. With j == 0 we check that on the bound
2894 it still works whereas with j == 1 we check that just outside of
2895 bound we fail.
2896 */
2897 FOR_POPULATED_RANKS_BACKWARDS {
2898 for (i = 0; i < 2; i++) {
2899 for (lane = 0; lane < 8; lane++) {
2900 write_500(info, channel,
2901 info->cached_training->
2902 timing2_bounds[channel][slot]
2903 [rank][lane][i],
2904 get_timing_register_addr(lane,
2905 3,
2906 slot,
2907 rank),
2908 9, 1);
2909
2910 if (!i)
2911 write_500(info, channel,
2912 info->
2913 cached_training->
2914 timing2_offset
2915 [channel][slot][rank]
2916 [lane],
2917 get_timing_register_addr
2918 (lane, 2, slot, rank),
2919 9, 1);
2920 write_500(info, channel,
2921 i ? info->cached_training->
2922 timing_bounds[tm][channel]
2923 [slot][rank][lane].
2924 largest : info->
2925 cached_training->
2926 timing_bounds[tm][channel]
2927 [slot][rank][lane].smallest,
2928 get_timing_register_addr(lane,
2929 0,
2930 slot,
2931 rank),
2932 9, 1);
2933 write_500(info, channel,
2934 info->cached_training->
2935 timing_offset[channel][slot]
2936 [rank][lane] +
2937 (i ? info->cached_training->
2938 timing_bounds[tm][channel]
2939 [slot][rank][lane].
2940 largest : info->
2941 cached_training->
2942 timing_bounds[tm][channel]
2943 [slot][rank][lane].
2944 smallest) - 64,
2945 get_timing_register_addr(lane,
2946 1,
2947 slot,
2948 rank),
2949 9, 1);
2950 }
2951 for (j = 0; j < 2; j++) {
2952 u8 failmask;
2953 u8 expected_failmask;
2954 char reg1b3;
2955
2956 reg1b3 = (j == 1) + 4;
2957 reg1b3 =
2958 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2959 write_1d0(reg1b3, 0x1bb, 6, 1);
2960 write_1d0(reg1b3, 0x1b3, 6, 1);
2961 write_1d0(reg1b3, 0x1a3, 6, 1);
2962
2963 flip = !flip;
2964 write_testing(info, totalrank, flip);
2965 failmask =
2966 check_testing(info, totalrank,
2967 flip);
2968 expected_failmask =
2969 j == 0 ? 0x00 : 0xff;
2970 if (failmask != expected_failmask)
2971 goto fail;
2972 }
2973 }
2974 totalrank++;
2975 }
2976 }
2977
2978 set_178(info->cached_training->reg178_center);
2979 if (info->use_ecc)
2980 set_ecc(1);
2981 write_training_data(info);
2982 write_1d0(0, 322, 3, 1);
2983 info->training = *info->cached_training;
2984
2985 write_1d0(0, 0x1bb, 6, 1);
2986 write_1d0(0, 0x1b3, 6, 1);
2987 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002988 MCHBAR8(0x243) = saved_243[0];
2989 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002990
2991 return 1;
2992
2993fail:
2994 FOR_POPULATED_RANKS {
2995 write_500_timings_type(info, channel, slot, rank, 1);
2996 write_500_timings_type(info, channel, slot, rank, 2);
2997 write_500_timings_type(info, channel, slot, rank, 3);
2998 }
2999
3000 write_1d0(0, 0x1bb, 6, 1);
3001 write_1d0(0, 0x1b3, 6, 1);
3002 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003003 MCHBAR8(0x243) = saved_243[0];
3004 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003005
3006 return 0;
3007}
3008
3009static void do_ram_training(struct raminfo *info)
3010{
3011 u8 saved_243[2];
3012 int totalrank = 0;
3013 u8 reg_178;
3014 int niter;
3015
Matthias Gazzaridfa51252018-05-19 00:44:20 +02003016 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003017 int lane, rank, slot, channel;
3018 u8 reg178_center;
3019
3020 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003021 saved_243[0] = MCHBAR8(0x243);
3022 saved_243[1] = MCHBAR8(0x643);
3023 MCHBAR8(0x243) = saved_243[0] | 2;
3024 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003025 switch (info->clock_speed_index) {
3026 case 0:
3027 niter = 5;
3028 break;
3029 case 1:
3030 niter = 10;
3031 break;
3032 default:
3033 niter = 19;
3034 break;
3035 }
3036 set_ecc(0);
3037
3038 FOR_POPULATED_RANKS_BACKWARDS {
3039 int i;
3040
3041 write_500_timings_type(info, channel, slot, rank, 0);
3042
3043 write_testing(info, totalrank, 0);
3044 for (i = 0; i < niter; i++) {
3045 write_testing_type2(info, totalrank, 2, i, 0);
3046 write_testing_type2(info, totalrank, 3, i, 1);
3047 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003048 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003049 totalrank++;
3050 }
3051
3052 if (reg178_min[info->clock_speed_index] <
3053 reg178_max[info->clock_speed_index])
3054 memset(timings[reg178_min[info->clock_speed_index]], 0,
3055 sizeof(timings[0]) *
3056 (reg178_max[info->clock_speed_index] -
3057 reg178_min[info->clock_speed_index]));
3058 for (reg_178 = reg178_min[info->clock_speed_index];
3059 reg_178 < reg178_max[info->clock_speed_index];
3060 reg_178 += reg178_step[info->clock_speed_index]) {
3061 totalrank = 0;
3062 set_178(reg_178);
3063 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3064 for (slot = 0; slot < NUM_SLOTS; slot++)
3065 for (rank = 0; rank < NUM_RANKS; rank++) {
3066 memset(&timings[reg_178][channel][slot]
3067 [rank][0].smallest, 0, 16);
3068 if (info->
3069 populated_ranks[channel][slot]
3070 [rank]) {
3071 train_ram_at_178(info, channel,
3072 slot, rank,
3073 totalrank,
3074 reg_178, 1,
3075 niter,
3076 timings);
3077 totalrank++;
3078 }
3079 }
3080 }
3081
3082 reg178_center = choose_reg178(info, timings);
3083
3084 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3085 info->training.timing_bounds[0][channel][slot][rank][lane].
3086 smallest =
3087 timings[info->training.
3088 reg178_smallest][channel][slot][rank][lane].
3089 smallest;
3090 info->training.timing_bounds[0][channel][slot][rank][lane].
3091 largest =
3092 timings[info->training.
3093 reg178_smallest][channel][slot][rank][lane].largest;
3094 info->training.timing_bounds[1][channel][slot][rank][lane].
3095 smallest =
3096 timings[info->training.
3097 reg178_largest][channel][slot][rank][lane].smallest;
3098 info->training.timing_bounds[1][channel][slot][rank][lane].
3099 largest =
3100 timings[info->training.
3101 reg178_largest][channel][slot][rank][lane].largest;
3102 info->training.timing_offset[channel][slot][rank][lane] =
3103 info->training.lane_timings[1][channel][slot][rank][lane]
3104 -
3105 info->training.lane_timings[0][channel][slot][rank][lane] +
3106 64;
3107 }
3108
3109 if (info->silicon_revision == 1
3110 && (info->
3111 populated_ranks_mask[1] ^ (info->
3112 populated_ranks_mask[1] >> 2)) & 1) {
3113 int ranks_after_channel1;
3114
3115 totalrank = 0;
3116 for (reg_178 = reg178_center - 18;
3117 reg_178 <= reg178_center + 18; reg_178 += 18) {
3118 totalrank = 0;
3119 set_178(reg_178);
3120 for (slot = 0; slot < NUM_SLOTS; slot++)
3121 for (rank = 0; rank < NUM_RANKS; rank++) {
3122 if (info->
3123 populated_ranks[1][slot][rank]) {
3124 train_ram_at_178(info, 1, slot,
3125 rank,
3126 totalrank,
3127 reg_178, 0,
3128 niter,
3129 timings);
3130 totalrank++;
3131 }
3132 }
3133 }
3134 ranks_after_channel1 = totalrank;
3135
3136 for (reg_178 = reg178_center - 12;
3137 reg_178 <= reg178_center + 12; reg_178 += 12) {
3138 totalrank = ranks_after_channel1;
3139 set_178(reg_178);
3140 for (slot = 0; slot < NUM_SLOTS; slot++)
3141 for (rank = 0; rank < NUM_RANKS; rank++)
3142 if (info->
3143 populated_ranks[0][slot][rank]) {
3144 train_ram_at_178(info, 0, slot,
3145 rank,
3146 totalrank,
3147 reg_178, 0,
3148 niter,
3149 timings);
3150 totalrank++;
3151 }
3152
3153 }
3154 } else {
3155 for (reg_178 = reg178_center - 12;
3156 reg_178 <= reg178_center + 12; reg_178 += 12) {
3157 totalrank = 0;
3158 set_178(reg_178);
3159 FOR_POPULATED_RANKS_BACKWARDS {
3160 train_ram_at_178(info, channel, slot, rank,
3161 totalrank, reg_178, 0, niter,
3162 timings);
3163 totalrank++;
3164 }
3165 }
3166 }
3167
3168 set_178(reg178_center);
3169 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3170 u16 tm0;
3171
3172 tm0 =
3173 choose_training(info, channel, slot, rank, lane, timings,
3174 reg178_center);
3175 write_500(info, channel, tm0,
3176 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3177 write_500(info, channel,
3178 tm0 +
3179 info->training.
3180 lane_timings[1][channel][slot][rank][lane] -
3181 info->training.
3182 lane_timings[0][channel][slot][rank][lane],
3183 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3184 }
3185
3186 totalrank = 0;
3187 FOR_POPULATED_RANKS_BACKWARDS {
3188 try_timing_offsets(info, channel, slot, rank, totalrank);
3189 totalrank++;
3190 }
Felix Held04be2dd2018-07-29 04:53:22 +02003191 MCHBAR8(0x243) = saved_243[0];
3192 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003193 write_1d0(0, 0x142, 3, 1);
3194 info->training.reg178_center = reg178_center;
3195}
3196
3197static void ram_training(struct raminfo *info)
3198{
3199 u16 saved_fc4;
3200
Felix Held04be2dd2018-07-29 04:53:22 +02003201 saved_fc4 = MCHBAR16(0xfc4);
3202 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003203
3204 if (info->revision >= 8)
3205 read_4090(info);
3206
3207 if (!try_cached_training(info))
3208 do_ram_training(info);
3209 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3210 && info->clock_speed_index < 2)
3211 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003212 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003213}
3214
3215static unsigned gcd(unsigned a, unsigned b)
3216{
3217 unsigned t;
3218 if (a > b) {
3219 t = a;
3220 a = b;
3221 b = t;
3222 }
3223 /* invariant a < b. */
3224 while (a) {
3225 t = b % a;
3226 b = a;
3227 a = t;
3228 }
3229 return b;
3230}
3231
3232static inline int div_roundup(int a, int b)
3233{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003234 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003235}
3236
3237static unsigned lcm(unsigned a, unsigned b)
3238{
3239 return (a * b) / gcd(a, b);
3240}
3241
3242struct stru1 {
3243 u8 freqs_reversed;
3244 u8 freq_diff_reduced;
3245 u8 freq_min_reduced;
3246 u8 divisor_f4_to_fmax;
3247 u8 divisor_f3_to_fmax;
3248 u8 freq4_to_max_remainder;
3249 u8 freq3_to_2_remainder;
3250 u8 freq3_to_2_remaindera;
3251 u8 freq4_to_2_remainder;
3252 int divisor_f3_to_f1, divisor_f4_to_f2;
3253 int common_time_unit_ps;
3254 int freq_max_reduced;
3255};
3256
3257static void
3258compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3259 int num_cycles_2, int num_cycles_1, int round_it,
3260 int add_freqs, struct stru1 *result)
3261{
3262 int g;
3263 int common_time_unit_ps;
3264 int freq1_reduced, freq2_reduced;
3265 int freq_min_reduced;
3266 int freq_max_reduced;
3267 int freq3, freq4;
3268
3269 g = gcd(freq1, freq2);
3270 freq1_reduced = freq1 / g;
3271 freq2_reduced = freq2 / g;
3272 freq_min_reduced = min(freq1_reduced, freq2_reduced);
3273 freq_max_reduced = max(freq1_reduced, freq2_reduced);
3274
3275 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3276 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3277 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3278 if (add_freqs) {
3279 freq3 += freq2_reduced;
3280 freq4 += freq1_reduced;
3281 }
3282
3283 if (round_it) {
3284 result->freq3_to_2_remainder = 0;
3285 result->freq3_to_2_remaindera = 0;
3286 result->freq4_to_max_remainder = 0;
3287 result->divisor_f4_to_f2 = 0;
3288 result->divisor_f3_to_f1 = 0;
3289 } else {
3290 if (freq2_reduced < freq1_reduced) {
3291 result->freq3_to_2_remainder =
3292 result->freq3_to_2_remaindera =
3293 freq3 % freq1_reduced - freq1_reduced + 1;
3294 result->freq4_to_max_remainder =
3295 -(freq4 % freq1_reduced);
3296 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3297 result->divisor_f4_to_f2 =
3298 (freq4 -
3299 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3300 result->freq4_to_2_remainder =
3301 -(char)((freq1_reduced - freq2_reduced) +
3302 ((u8) freq4 -
3303 (freq1_reduced -
3304 freq2_reduced)) % (u8) freq2_reduced);
3305 } else {
3306 if (freq2_reduced > freq1_reduced) {
3307 result->freq4_to_max_remainder =
3308 (freq4 % freq2_reduced) - freq2_reduced + 1;
3309 result->freq4_to_2_remainder =
3310 freq4 % freq_max_reduced -
3311 freq_max_reduced + 1;
3312 } else {
3313 result->freq4_to_max_remainder =
3314 -(freq4 % freq2_reduced);
3315 result->freq4_to_2_remainder =
3316 -(char)(freq4 % freq_max_reduced);
3317 }
3318 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3319 result->divisor_f3_to_f1 =
3320 (freq3 -
3321 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3322 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3323 result->freq3_to_2_remaindera =
3324 -(char)((freq_max_reduced - freq_min_reduced) +
3325 (freq3 -
3326 (freq_max_reduced -
3327 freq_min_reduced)) % freq1_reduced);
3328 }
3329 }
3330 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3331 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3332 if (round_it) {
3333 if (freq2_reduced > freq1_reduced) {
3334 if (freq3 % freq_max_reduced)
3335 result->divisor_f3_to_fmax++;
3336 }
3337 if (freq2_reduced < freq1_reduced) {
3338 if (freq4 % freq_max_reduced)
3339 result->divisor_f4_to_fmax++;
3340 }
3341 }
3342 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3343 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3344 result->freq_min_reduced = freq_min_reduced;
3345 result->common_time_unit_ps = common_time_unit_ps;
3346 result->freq_max_reduced = freq_max_reduced;
3347}
3348
3349static void
3350set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3351 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3352 int num_cycles_4, int reverse)
3353{
3354 struct stru1 vv;
3355 char multiplier;
3356
3357 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3358 0, 1, &vv);
3359
3360 multiplier =
3361 div_roundup(max
3362 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3363 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3364 div_roundup(num_cycles_1,
3365 vv.common_time_unit_ps) +
3366 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3367 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3368
3369 u32 y =
3370 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3371 vv.freq_max_reduced * multiplier)
3372 | (vv.
3373 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3374 multiplier) << 16) | ((u8) (vv.
3375 freq_min_reduced
3376 *
3377 multiplier)
3378 << 24);
3379 u32 x =
3380 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3381 divisor_f3_to_f1
3382 << 16)
3383 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3384 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003385 MCHBAR32(reg) = y;
3386 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003387 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003388 MCHBAR32(reg + 4) = y;
3389 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003390 }
3391}
3392
3393static void
3394set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3395 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3396 int num_cycles_4)
3397{
3398 struct stru1 ratios1;
3399 struct stru1 ratios2;
3400
3401 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3402 0, 1, &ratios2);
3403 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3404 0, 1, &ratios1);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003405 printk (BIOS_SPEW, "[%x] <= %x\n", reg,
3406 ratios1.freq4_to_max_remainder | (ratios2.
3407 freq4_to_max_remainder
3408 << 8)
3409 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3410 divisor_f4_to_fmax
3411 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003412 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3413 (ratios2.freq4_to_max_remainder << 8) |
3414 (ratios1.divisor_f4_to_fmax << 16) |
3415 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003416}
3417
3418static void
3419set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3420 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3421{
3422 struct stru1 ratios;
3423
3424 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3425 round_it, add_freqs, &ratios);
3426 switch (mode) {
3427 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003428 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3429 (ratios.freqs_reversed << 8);
3430 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3431 (ratios.freq4_to_max_remainder << 8) |
3432 (ratios.divisor_f3_to_fmax << 16) |
3433 (ratios.divisor_f4_to_fmax << 20) |
3434 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003435 break;
3436
3437 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003438 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3439 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003440 break;
3441
3442 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003443 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3444 (ratios.freq4_to_max_remainder << 8) |
3445 (ratios.divisor_f3_to_fmax << 16) |
3446 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003447 break;
3448
3449 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003450 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3451 (ratios.divisor_f4_to_fmax << 8) |
3452 (ratios.freqs_reversed << 12) |
3453 (ratios.freq_min_reduced << 16) |
3454 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003455 break;
3456 }
3457}
3458
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003459static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003460{
3461 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3462 0, 1);
3463 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3464 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3465 1);
3466 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3467 frequency_11(info), 1231, 1524, 0, 1);
3468 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3469 frequency_11(info) / 2, 1278, 2008, 0, 1);
3470 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3471 1167, 1539, 0, 1);
3472 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3473 frequency_11(info) / 2, 1403, 1318, 0, 1);
3474 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3475 1);
3476 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3477 1);
3478 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3479 1, 1);
3480 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3481 1);
3482 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3483 frequency_11(info) / 2, 4000, 0, 0, 0);
3484 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3485 frequency_11(info) / 2, 4000, 4000, 0, 0);
3486
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003487 if (s3resume) {
3488 printk (BIOS_SPEW, "[6dc] <= %x\n", info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003489 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003490 } else
3491 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3492 info->delay46_ps[0], 0,
3493 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003494 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3495 frequency_11(info), 2500, 0, 0, 0);
3496 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3497 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003498 if (s3resume) {
3499 printk (BIOS_SPEW, "[6e8] <= %x\n", info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003500 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003501 } else
3502 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3503 info->delay46_ps[1], 0,
3504 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003505 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3506 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3507 470, 0);
3508 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3509 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3510 454, 459, 0);
3511 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3512 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3513 2588, 0);
3514 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3515 2405, 0);
3516 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3517 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3518 480, 0);
3519 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003520 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3521 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003522}
3523
3524static u16 get_max_timing(struct raminfo *info, int channel)
3525{
3526 int slot, rank, lane;
3527 u16 ret = 0;
3528
Felix Held04be2dd2018-07-29 04:53:22 +02003529 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003530 return 384;
3531
3532 if (info->revision < 8)
3533 return 256;
3534
3535 for (slot = 0; slot < NUM_SLOTS; slot++)
3536 for (rank = 0; rank < NUM_RANKS; rank++)
3537 if (info->populated_ranks[channel][slot][rank])
3538 for (lane = 0; lane < 8 + info->use_ecc; lane++)
3539 ret = max(ret, read_500(info, channel,
3540 get_timing_register_addr
3541 (lane, 0, slot,
3542 rank), 9));
3543 return ret;
3544}
3545
3546static void set_274265(struct raminfo *info)
3547{
3548 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3549 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3550 int delay_e_over_cycle_ps;
3551 int cycletime_ps;
3552 int channel;
3553
3554 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003555 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003556 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3557 cycletime_ps =
3558 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3559 delay_d_ps =
3560 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3561 - info->some_delay_3_ps_rounded + 200;
3562 if (!
3563 ((info->silicon_revision == 0
3564 || info->silicon_revision == 1)
3565 && (info->revision >= 8)))
3566 delay_d_ps += halfcycle_ps(info) * 2;
3567 delay_d_ps +=
3568 halfcycle_ps(info) * (!info->revision_flag_1 +
3569 info->some_delay_2_halfcycles_ceil +
3570 2 * info->some_delay_1_cycle_floor +
3571 info->clock_speed_index +
3572 2 * info->cas_latency - 7 + 11);
3573 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3574
Felix Held04be2dd2018-07-29 04:53:22 +02003575 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3576 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3577 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003578 delay_d_ps += 650;
3579 delay_c_ps = delay_d_ps + 1800;
3580 if (delay_c_ps <= delay_a_ps)
3581 delay_e_ps = 0;
3582 else
3583 delay_e_ps =
3584 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3585 cycletime_ps);
3586
3587 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3588 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3589 delay_f_cycles =
3590 div_roundup(2500 - delay_e_over_cycle_ps,
3591 2 * halfcycle_ps(info));
3592 if (delay_f_cycles > delay_e_cycles) {
3593 info->delay46_ps[channel] = delay_e_ps;
3594 delay_e_cycles = 0;
3595 } else {
3596 info->delay46_ps[channel] =
3597 delay_e_over_cycle_ps +
3598 2 * halfcycle_ps(info) * delay_f_cycles;
3599 delay_e_cycles -= delay_f_cycles;
3600 }
3601
3602 if (info->delay46_ps[channel] < 2500) {
3603 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003604 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003605 }
3606 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3607 if (delay_b_ps <= delay_a_ps)
3608 delay_b_ps = 0;
3609 else
3610 delay_b_ps -= delay_a_ps;
3611 info->delay54_ps[channel] =
3612 cycletime_ps * div_roundup(delay_b_ps,
3613 cycletime_ps) -
3614 2 * halfcycle_ps(info) * delay_e_cycles;
3615 if (info->delay54_ps[channel] < 2500)
3616 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003617 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003618 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3619 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003620 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003621 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003622 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003623 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3624 4 * halfcycle_ps(info)) - 6;
3625 MCHBAR32((channel << 10) + 0x274) =
3626 info->training.reg274265[channel][1] |
3627 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003628 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003629 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3630 4 * halfcycle_ps(info)) + 1;
3631 MCHBAR16((channel << 10) + 0x265) =
3632 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003633 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003634 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003635 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003636 else
Felix Held04be2dd2018-07-29 04:53:22 +02003637 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003638}
3639
3640static void restore_274265(struct raminfo *info)
3641{
3642 int channel;
3643
3644 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003645 MCHBAR32((channel << 10) + 0x274) =
3646 (info->cached_training->reg274265[channel][0] << 16) |
3647 info->cached_training->reg274265[channel][1];
3648 MCHBAR16((channel << 10) + 0x265) =
3649 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003650 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003651 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003652 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003653 else
Felix Held04be2dd2018-07-29 04:53:22 +02003654 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003655}
3656
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003657static void dmi_setup(void)
3658{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003659 gav(read8(DEFAULT_DMIBAR + 0x254));
3660 write8(DEFAULT_DMIBAR + 0x254, 0x1);
3661 write16(DEFAULT_DMIBAR + 0x1b8, 0x18f2);
Felix Heldf83d80b2018-07-29 05:30:30 +02003662 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003663
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003664 write32(DEFAULT_DMIBAR + 0xd68, read32(DEFAULT_DMIBAR + 0xd68) | 0x08000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003665
3666 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3667 DEFAULT_GPIOBASE | 0x38);
3668 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3669}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003670
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003671void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003672{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003673 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003674 u16 ggc;
3675 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003676
Felix Held04be2dd2018-07-29 04:53:22 +02003677 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003678 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3679 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003680 MCHBAR8(0x2ca8) = 0;
Vladimir Serbinenkoe1eef692014-02-19 22:08:51 +01003681 outb(0x6, 0xcf9);
Patrick Georgi546953c2014-11-29 10:38:17 +01003682 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003683 }
Felix Held29a9c072018-07-29 01:34:45 +02003684#if 0
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003685 if (!s3resume) {
3686 pre_raminit_3(x2ca8);
3687 }
Vladimir Serbinenkof62669c2014-01-09 10:59:38 +01003688 pre_raminit_4a(x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003689#endif
3690
3691 dmi_setup();
3692
Felix Held04be2dd2018-07-29 04:53:22 +02003693 MCHBAR16(0x1170) = 0xa880;
3694 MCHBAR8(0x11c1) = 0x1;
3695 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003696 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003697
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003698 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3699 /* 0 for 32MB */
3700 gfxsize = 0;
3701 }
3702
3703 ggc = 0xb00 | ((gfxsize + 5) << 4);
3704
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003705 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003706
3707 u16 deven;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003708 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003709
3710 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003711 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003712 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003713 MCHBAR16_OR(0x2c30, 0x200);
3714 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003715 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003716 pci_read_config8(GMA, 0x62); // = 0x2
3717 pci_write_config8(GMA, 0x62, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003718 read8(DEFAULT_RCBA + 0x2318);
3719 write8(DEFAULT_RCBA + 0x2318, 0x47);
3720 read8(DEFAULT_RCBA + 0x2320);
3721 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003722 }
3723
Felix Heldf83d80b2018-07-29 05:30:30 +02003724 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003725
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003726 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003727 gav(read32(DEFAULT_RCBA + 0x3428));
3728 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003729}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003730
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003731void raminit(const int s3resume, const u8 *spd_addrmap)
3732{
3733 unsigned channel, slot, lane, rank;
3734 int i;
3735 struct raminfo info;
3736 u8 x2ca8;
3737 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003738 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003739
Felix Heldf83d80b2018-07-29 05:30:30 +02003740 /* only used for dummy reads */
3741 volatile u8 tmp8;
3742 volatile u16 tmp16;
3743 volatile u32 tmp32;
3744
Felix Held04be2dd2018-07-29 04:53:22 +02003745 x2ca8 = MCHBAR8(0x2ca8);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003746 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003747
3748 memset(&info, 0x5a, sizeof(info));
3749
3750 info.last_500_command[0] = 0;
3751 info.last_500_command[1] = 0;
3752
3753 info.fsb_frequency = 135 * 2;
3754 info.board_lane_delay[0] = 0x14;
3755 info.board_lane_delay[1] = 0x07;
3756 info.board_lane_delay[2] = 0x07;
3757 info.board_lane_delay[3] = 0x08;
3758 info.board_lane_delay[4] = 0x56;
3759 info.board_lane_delay[5] = 0x04;
3760 info.board_lane_delay[6] = 0x04;
3761 info.board_lane_delay[7] = 0x05;
3762 info.board_lane_delay[8] = 0x10;
3763
3764 info.training.reg_178 = 0;
3765 info.training.reg_10b = 0;
3766
3767 info.heci_bar = 0;
3768 info.memory_reserved_for_heci_mb = 0;
3769
3770 /* before SPD */
3771 timestamp_add_now(101);
3772
Felix Held29a9c072018-07-29 01:34:45 +02003773 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003774 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003775
3776 collect_system_info(&info);
3777
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003778 /* Enable SMBUS. */
3779 enable_smbus();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003780
3781 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3782
3783 info.use_ecc = 1;
3784 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003785 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003786 int v;
3787 int try;
3788 int addr;
3789 const u8 useful_addresses[] = {
3790 DEVICE_TYPE,
3791 MODULE_TYPE,
3792 DENSITY,
3793 RANKS_AND_DQ,
3794 MEMORY_BUS_WIDTH,
3795 TIMEBASE_DIVIDEND,
3796 TIMEBASE_DIVISOR,
3797 CYCLETIME,
3798 CAS_LATENCIES_LSB,
3799 CAS_LATENCIES_MSB,
3800 CAS_LATENCY_TIME,
3801 0x11, 0x12, 0x13, 0x14, 0x15,
3802 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3803 0x1c, 0x1d,
3804 THERMAL_AND_REFRESH,
3805 0x20,
3806 REFERENCE_RAW_CARD_USED,
3807 RANK1_ADDRESS_MAPPING,
3808 0x75, 0x76, 0x77, 0x78,
3809 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3810 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3811 0x85, 0x86, 0x87, 0x88,
3812 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3813 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3814 0x95
3815 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003816 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003817 continue;
3818 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003819 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003820 DEVICE_TYPE);
3821 if (v >= 0)
3822 break;
3823 }
3824 if (v < 0)
3825 continue;
3826 for (addr = 0;
3827 addr <
3828 sizeof(useful_addresses) /
3829 sizeof(useful_addresses[0]); addr++)
3830 gav(info.
3831 spd[channel][0][useful_addresses
3832 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003833 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003834 useful_addresses
3835 [addr]));
3836 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3837 die("Only DDR3 is supported");
3838
3839 v = info.spd[channel][0][RANKS_AND_DQ];
3840 info.populated_ranks[channel][0][0] = 1;
3841 info.populated_ranks[channel][0][1] =
3842 ((v >> 3) & 7);
3843 if (((v >> 3) & 7) > 1)
3844 die("At most 2 ranks are supported");
3845 if ((v & 7) == 0 || (v & 7) > 2)
3846 die("Only x8 and x16 modules are supported");
3847 if ((info.
3848 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3849 && (info.
3850 spd[channel][slot][MODULE_TYPE] & 0xF)
3851 != 3)
3852 die("Registered memory is not supported");
3853 info.is_x16_module[channel][0] = (v & 7) - 1;
3854 info.density[channel][slot] =
3855 info.spd[channel][slot][DENSITY] & 0xF;
3856 if (!
3857 (info.
3858 spd[channel][slot][MEMORY_BUS_WIDTH] &
3859 0x18))
3860 info.use_ecc = 0;
3861 }
3862
3863 gav(0x55);
3864
3865 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3866 int v = 0;
3867 for (slot = 0; slot < NUM_SLOTS; slot++)
3868 for (rank = 0; rank < NUM_RANKS; rank++)
3869 v |= info.
3870 populated_ranks[channel][slot][rank]
3871 << (2 * slot + rank);
3872 info.populated_ranks_mask[channel] = v;
3873 }
3874
3875 gav(0x55);
3876
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003877 gav(pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003878 }
3879
3880 /* after SPD */
3881 timestamp_add_now(102);
3882
Felix Held04be2dd2018-07-29 04:53:22 +02003883 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003884
3885 collect_system_info(&info);
3886 calculate_timings(&info);
3887
Felix Held29a9c072018-07-29 01:34:45 +02003888#if 0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003889 pci_write_config8(NORTHBRIDGE, 0xdf, 0x82);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003890#endif
3891
3892 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003893 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003894 if (x2ca8 == 0 && (reg8 & 0x80)) {
3895 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3896 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3897 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3898 */
3899
3900 /* Clear bit7. */
3901
3902 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3903 (reg8 & ~(1 << 7)));
3904
3905 printk(BIOS_INFO,
3906 "Interrupted RAM init, reset required.\n");
3907 outb(0x6, 0xcf9);
Patrick Georgi546953c2014-11-29 10:38:17 +01003908 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003909 }
3910 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003911
3912 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003913 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3914 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003915
3916 compute_derived_timings(&info);
3917
3918 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003919 gav(MCHBAR8(0x164));
3920 MCHBAR8(0x164) = 0x26;
3921 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003922 }
3923
Felix Held04be2dd2018-07-29 04:53:22 +02003924 MCHBAR32_OR(0x18b4, 0x210000);
3925 MCHBAR32_OR(0x1890, 0x2000000);
3926 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003927
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003928 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x50)); // !!!!
3929 pci_write_config8(PCI_DEV(0xff, 2, 1), 0x54, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003930
Felix Held04be2dd2018-07-29 04:53:22 +02003931 gav(MCHBAR16(0x2c10));
3932 MCHBAR16(0x2c10) = 0x412;
3933 gav(MCHBAR16(0x2c10));
3934 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003935
Felix Held04be2dd2018-07-29 04:53:22 +02003936 gav(MCHBAR8(0x2ca8)); // !!!!
3937 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003938
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003939 pci_read_config32(PCI_DEV(0xff, 2, 1), 0x6c); // !!!!
3940 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x6c, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003941 gav(MCHBAR32(0x1c04)); // !!!!
3942 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003943
3944 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003945 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003946 }
3947
Felix Held04be2dd2018-07-29 04:53:22 +02003948 MCHBAR32(0x18d8) = 0x120000;
3949 MCHBAR32(0x18dc) = 0x30a484a;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003950 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x0);
3951 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003952 MCHBAR32(0x18d8) = 0x40000;
3953 MCHBAR32(0x18dc) = 0xb000000;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003954 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x60000);
3955 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003956 MCHBAR32(0x18d8) = 0x180000;
3957 MCHBAR32(0x18dc) = 0xc0000142;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003958 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x20000);
3959 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003960 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003961
Felix Held04be2dd2018-07-29 04:53:22 +02003962 gav(MCHBAR32(0x18dc)); // !!!!
3963 MCHBAR32(0x18dc) = 0x3;
3964 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003965
3966 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003967 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003968 }
3969
Felix Held04be2dd2018-07-29 04:53:22 +02003970 MCHBAR32(0x188c) = 0x20bc09;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003971 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xd0, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003972 MCHBAR32(0x1a10) = 0x4200010e;
3973 MCHBAR32_OR(0x18b8, 0x200);
3974 gav(MCHBAR32(0x1918)); // !!!!
3975 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003976
Felix Held04be2dd2018-07-29 04:53:22 +02003977 gav(MCHBAR32(0x18b8)); // !!!!
3978 MCHBAR32(0x18b8) = 0xe00;
3979 gav(MCHBAR32(0x182c)); // !!!!
3980 MCHBAR32(0x182c) = 0x10202;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003981 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x94)); // !!!!
3982 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x94, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003983 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3984 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003985
Felix Held04be2dd2018-07-29 04:53:22 +02003986 MCHBAR32_AND(0x18b4, 0xffff7fff);
3987 gav(MCHBAR32(0x1a68)); // !!!!
3988 MCHBAR32(0x1a68) = 0x343800;
3989 gav(MCHBAR32(0x1e68)); // !!!!
3990 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003991
3992 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003993 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003994 }
3995
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003996 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x048); // !!!!
3997 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x048, 0x140000);
3998 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3999 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x058, 0x64555);
4000 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
4001 pci_read_config32(PCI_DEV (0xff, 0, 0), 0xd0); // !!!!
4002 pci_write_config32(PCI_DEV (0xff, 0, 0), 0xd0, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02004003 gav(MCHBAR32(0x1af0)); // !!!!
4004 gav(MCHBAR32(0x1af0)); // !!!!
4005 MCHBAR32(0x1af0) = 0x1f020003;
4006 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004007
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10004008 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004009 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004010 }
4011
Felix Held04be2dd2018-07-29 04:53:22 +02004012 gav(MCHBAR32(0x1890)); // !!!!
4013 MCHBAR32(0x1890) = 0x80102;
4014 gav(MCHBAR32(0x18b4)); // !!!!
4015 MCHBAR32(0x18b4) = 0x216000;
4016 MCHBAR32(0x18a4) = 0x22222222;
4017 MCHBAR32(0x18a8) = 0x22222222;
4018 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004019
4020 udelay(1000);
4021
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004022 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004023
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004024 if (x2ca8 == 0) {
4025 int j;
4026 if (s3resume && info.cached_training) {
4027 restore_274265(&info);
4028 printk(BIOS_DEBUG, "reg2ca9_bit0 = %x\n",
4029 info.cached_training->reg2ca9_bit0);
4030 for (i = 0; i < 2; i++)
4031 for (j = 0; j < 3; j++)
4032 printk(BIOS_DEBUG, "reg274265[%d][%d] = %x\n",
4033 i, j, info.cached_training->reg274265[i][j]);
4034 } else {
4035 set_274265(&info);
4036 printk(BIOS_DEBUG, "reg2ca9_bit0 = %x\n",
4037 info.training.reg2ca9_bit0);
4038 for (i = 0; i < 2; i++)
4039 for (j = 0; j < 3; j++)
4040 printk(BIOS_DEBUG, "reg274265[%d][%d] = %x\n",
4041 i, j, info.training.reg274265[i][j]);
4042 }
4043
4044 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004045
4046 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02004047 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004048 }
4049
4050 udelay(1000);
4051
4052 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02004053 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02004054 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004055 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4056 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4057 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004058
Felix Heldf83d80b2018-07-29 05:30:30 +02004059 tmp8 = MCHBAR8(0x1150);
4060 tmp8 = MCHBAR8(0x1151);
4061 tmp8 = MCHBAR8(0x1022);
4062 tmp8 = MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004063 MCHBAR32(0x1300) = 0x60606060;
4064 MCHBAR32(0x1304) = 0x60606060;
4065 MCHBAR32(0x1308) = 0x78797a7b;
4066 MCHBAR32(0x130c) = 0x7c7d7e7f;
4067 MCHBAR32(0x1310) = 0x60606060;
4068 MCHBAR32(0x1314) = 0x60606060;
4069 MCHBAR32(0x1318) = 0x60606060;
4070 MCHBAR32(0x131c) = 0x60606060;
4071 MCHBAR32(0x1320) = 0x50515253;
4072 MCHBAR32(0x1324) = 0x54555657;
4073 MCHBAR32(0x1328) = 0x58595a5b;
4074 MCHBAR32(0x132c) = 0x5c5d5e5f;
4075 MCHBAR32(0x1330) = 0x40414243;
4076 MCHBAR32(0x1334) = 0x44454647;
4077 MCHBAR32(0x1338) = 0x48494a4b;
4078 MCHBAR32(0x133c) = 0x4c4d4e4f;
4079 MCHBAR32(0x1340) = 0x30313233;
4080 MCHBAR32(0x1344) = 0x34353637;
4081 MCHBAR32(0x1348) = 0x38393a3b;
4082 MCHBAR32(0x134c) = 0x3c3d3e3f;
4083 MCHBAR32(0x1350) = 0x20212223;
4084 MCHBAR32(0x1354) = 0x24252627;
4085 MCHBAR32(0x1358) = 0x28292a2b;
4086 MCHBAR32(0x135c) = 0x2c2d2e2f;
4087 MCHBAR32(0x1360) = 0x10111213;
4088 MCHBAR32(0x1364) = 0x14151617;
4089 MCHBAR32(0x1368) = 0x18191a1b;
4090 MCHBAR32(0x136c) = 0x1c1d1e1f;
4091 MCHBAR32(0x1370) = 0x10203;
4092 MCHBAR32(0x1374) = 0x4050607;
4093 MCHBAR32(0x1378) = 0x8090a0b;
4094 MCHBAR32(0x137c) = 0xc0d0e0f;
4095 MCHBAR8(0x11cc) = 0x4e;
4096 MCHBAR32(0x1110) = 0x73970404;
4097 MCHBAR32(0x1114) = 0x72960404;
4098 MCHBAR32(0x1118) = 0x6f950404;
4099 MCHBAR32(0x111c) = 0x6d940404;
4100 MCHBAR32(0x1120) = 0x6a930404;
4101 MCHBAR32(0x1124) = 0x68a41404;
4102 MCHBAR32(0x1128) = 0x66a21404;
4103 MCHBAR32(0x112c) = 0x63a01404;
4104 MCHBAR32(0x1130) = 0x609e1404;
4105 MCHBAR32(0x1134) = 0x5f9c1404;
4106 MCHBAR32(0x1138) = 0x5c961404;
4107 MCHBAR32(0x113c) = 0x58a02404;
4108 MCHBAR32(0x1140) = 0x54942404;
4109 MCHBAR32(0x1190) = 0x900080a;
4110 MCHBAR16(0x11c0) = 0xc40b;
4111 MCHBAR16(0x11c2) = 0x303;
4112 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004113 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004114 MCHBAR32(0x11b8) = 0x70c3000;
4115 MCHBAR8(0x11ec) = 0xa;
4116 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004117 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004118 MCHBAR16(0x11ca) = 0xfa;
4119 MCHBAR32(0x11e4) = 0x4e20;
4120 MCHBAR8(0x11bc) = 0xf;
4121 MCHBAR16(0x11da) = 0x19;
4122 MCHBAR16(0x11ba) = 0x470c;
4123 MCHBAR32(0x1680) = 0xe6ffe4ff;
4124 MCHBAR32(0x1684) = 0xdeffdaff;
4125 MCHBAR32(0x1688) = 0xd4ffd0ff;
4126 MCHBAR32(0x168c) = 0xccffc6ff;
4127 MCHBAR32(0x1690) = 0xc0ffbeff;
4128 MCHBAR32(0x1694) = 0xb8ffb0ff;
4129 MCHBAR32(0x1698) = 0xa8ff0000;
4130 MCHBAR32(0x169c) = 0xc00;
4131 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004132 }
4133
Felix Held04be2dd2018-07-29 04:53:22 +02004134 MCHBAR32(0x124c) = 0x15040d00;
4135 MCHBAR32(0x1250) = 0x7f0000;
4136 MCHBAR32(0x1254) = 0x1e220004;
4137 MCHBAR32(0x1258) = 0x4000004;
4138 MCHBAR32(0x1278) = 0x0;
4139 MCHBAR32(0x125c) = 0x0;
4140 MCHBAR32(0x1260) = 0x0;
4141 MCHBAR32(0x1264) = 0x0;
4142 MCHBAR32(0x1268) = 0x0;
4143 MCHBAR32(0x126c) = 0x0;
4144 MCHBAR32(0x1270) = 0x0;
4145 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004146 }
4147
4148 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004149 MCHBAR16(0x1214) = 0x320;
4150 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004151 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4152 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004153 MCHBAR32(0x1400) = 0x13040020;
4154 MCHBAR32(0x1404) = 0xe090120;
4155 MCHBAR32(0x1408) = 0x5120220;
4156 MCHBAR32(0x140c) = 0x5120330;
4157 MCHBAR32(0x1410) = 0xe090220;
4158 MCHBAR32(0x1414) = 0x1010001;
4159 MCHBAR32(0x1418) = 0x1110000;
4160 MCHBAR32(0x141c) = 0x9020020;
4161 MCHBAR32(0x1420) = 0xd090220;
4162 MCHBAR32(0x1424) = 0x2090220;
4163 MCHBAR32(0x1428) = 0x2090330;
4164 MCHBAR32(0x142c) = 0xd090220;
4165 MCHBAR32(0x1430) = 0x1010001;
4166 MCHBAR32(0x1434) = 0x1110000;
4167 MCHBAR32(0x1438) = 0x11040020;
4168 MCHBAR32(0x143c) = 0x4030220;
4169 MCHBAR32(0x1440) = 0x1060220;
4170 MCHBAR32(0x1444) = 0x1060330;
4171 MCHBAR32(0x1448) = 0x4030220;
4172 MCHBAR32(0x144c) = 0x1010001;
4173 MCHBAR32(0x1450) = 0x1110000;
4174 MCHBAR32(0x1454) = 0x4010020;
4175 MCHBAR32(0x1458) = 0xb090220;
4176 MCHBAR32(0x145c) = 0x1090220;
4177 MCHBAR32(0x1460) = 0x1090330;
4178 MCHBAR32(0x1464) = 0xb090220;
4179 MCHBAR32(0x1468) = 0x1010001;
4180 MCHBAR32(0x146c) = 0x1110000;
4181 MCHBAR32(0x1470) = 0xf040020;
4182 MCHBAR32(0x1474) = 0xa090220;
4183 MCHBAR32(0x1478) = 0x1120220;
4184 MCHBAR32(0x147c) = 0x1120330;
4185 MCHBAR32(0x1480) = 0xa090220;
4186 MCHBAR32(0x1484) = 0x1010001;
4187 MCHBAR32(0x1488) = 0x1110000;
4188 MCHBAR32(0x148c) = 0x7020020;
4189 MCHBAR32(0x1490) = 0x1010220;
4190 MCHBAR32(0x1494) = 0x10210;
4191 MCHBAR32(0x1498) = 0x10320;
4192 MCHBAR32(0x149c) = 0x1010220;
4193 MCHBAR32(0x14a0) = 0x1010001;
4194 MCHBAR32(0x14a4) = 0x1110000;
4195 MCHBAR32(0x14a8) = 0xd040020;
4196 MCHBAR32(0x14ac) = 0x8090220;
4197 MCHBAR32(0x14b0) = 0x1111310;
4198 MCHBAR32(0x14b4) = 0x1111420;
4199 MCHBAR32(0x14b8) = 0x8090220;
4200 MCHBAR32(0x14bc) = 0x1010001;
4201 MCHBAR32(0x14c0) = 0x1110000;
4202 MCHBAR32(0x14c4) = 0x3010020;
4203 MCHBAR32(0x14c8) = 0x7090220;
4204 MCHBAR32(0x14cc) = 0x1081310;
4205 MCHBAR32(0x14d0) = 0x1081420;
4206 MCHBAR32(0x14d4) = 0x7090220;
4207 MCHBAR32(0x14d8) = 0x1010001;
4208 MCHBAR32(0x14dc) = 0x1110000;
4209 MCHBAR32(0x14e0) = 0xb040020;
4210 MCHBAR32(0x14e4) = 0x2030220;
4211 MCHBAR32(0x14e8) = 0x1051310;
4212 MCHBAR32(0x14ec) = 0x1051420;
4213 MCHBAR32(0x14f0) = 0x2030220;
4214 MCHBAR32(0x14f4) = 0x1010001;
4215 MCHBAR32(0x14f8) = 0x1110000;
4216 MCHBAR32(0x14fc) = 0x5020020;
4217 MCHBAR32(0x1500) = 0x5090220;
4218 MCHBAR32(0x1504) = 0x2071310;
4219 MCHBAR32(0x1508) = 0x2071420;
4220 MCHBAR32(0x150c) = 0x5090220;
4221 MCHBAR32(0x1510) = 0x1010001;
4222 MCHBAR32(0x1514) = 0x1110000;
4223 MCHBAR32(0x1518) = 0x7040120;
4224 MCHBAR32(0x151c) = 0x2090220;
4225 MCHBAR32(0x1520) = 0x70b1210;
4226 MCHBAR32(0x1524) = 0x70b1310;
4227 MCHBAR32(0x1528) = 0x2090220;
4228 MCHBAR32(0x152c) = 0x1010001;
4229 MCHBAR32(0x1530) = 0x1110000;
4230 MCHBAR32(0x1534) = 0x1010110;
4231 MCHBAR32(0x1538) = 0x1081310;
4232 MCHBAR32(0x153c) = 0x5041200;
4233 MCHBAR32(0x1540) = 0x5041310;
4234 MCHBAR32(0x1544) = 0x1081310;
4235 MCHBAR32(0x1548) = 0x1010001;
4236 MCHBAR32(0x154c) = 0x1110000;
4237 MCHBAR32(0x1550) = 0x1040120;
4238 MCHBAR32(0x1554) = 0x4051210;
4239 MCHBAR32(0x1558) = 0xd051200;
4240 MCHBAR32(0x155c) = 0xd051200;
4241 MCHBAR32(0x1560) = 0x4051210;
4242 MCHBAR32(0x1564) = 0x1010001;
4243 MCHBAR32(0x1568) = 0x1110000;
4244 MCHBAR16(0x1222) = 0x220a;
4245 MCHBAR16(0x123c) = 0x1fc0;
4246 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004247 }
4248
Felix Heldf83d80b2018-07-29 05:30:30 +02004249 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
4250 tmp32 = MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004251 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004252
Felix Heldf83d80b2018-07-29 05:30:30 +02004253 tmp8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004254
4255 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004256 MCHBAR8_AND(0x2ca8, ~3);
4257 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
4258 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004259 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004260 }
4261
Felix Held04be2dd2018-07-29 04:53:22 +02004262 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004263 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004264 pci_write_config32(PCI_DEV (0xff, 0, 0), 0x60, 0x20220);
Felix Heldf83d80b2018-07-29 05:30:30 +02004265 tmp16 = MCHBAR16(0x2c20); // !!!!
4266 tmp16 = MCHBAR16(0x2c10); // !!!!
4267 tmp16 = MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004268 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004269 udelay(1000);
4270 write_1d0(0, 0x33d, 0, 0);
4271 write_500(&info, 0, 0, 0xb61, 0, 0);
4272 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004273 MCHBAR32(0x1a30) = 0x0;
4274 MCHBAR32(0x1a34) = 0x0;
4275 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4276 (info.populated_ranks[0][0][0] * 0xa0);
4277 MCHBAR16(0x616) = 0x26a;
4278 MCHBAR32(0x134) = 0x856000;
4279 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004280 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4281 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004282 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004283 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4284 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004285 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004286 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004287 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4288 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004289 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4290 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4291 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4292 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4293 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4294 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4295 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4296 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4297 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4298 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004299 }
4300
4301 write_1d0(0x4, 0x151, 4, 1);
4302 write_1d0(0, 0x142, 3, 1);
4303 rdmsr(0x1ac); // !!!!
4304 write_500(&info, 1, 1, 0x6b3, 4, 1);
4305 write_500(&info, 1, 1, 0x6cf, 4, 1);
4306
4307 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4308
4309 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4310 populated_ranks[0]
4311 [0][0]) << 0),
4312 0x1d1, 3, 1);
4313 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004314 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4315 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004316 }
4317
4318 set_334(0);
4319
4320 program_base_timings(&info);
4321
Felix Held04be2dd2018-07-29 04:53:22 +02004322 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004323
4324 write_1d0(0x2, 0x1d5, 2, 1);
4325 write_1d0(0x20, 0x166, 7, 1);
4326 write_1d0(0x0, 0xeb, 3, 1);
4327 write_1d0(0x0, 0xf3, 6, 1);
4328
4329 for (channel = 0; channel < NUM_CHANNELS; channel++)
4330 for (lane = 0; lane < 9; lane++) {
4331 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4332 u8 a;
4333 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4334 write_500(&info, channel, a, addr, 6, 1);
4335 }
4336
4337 udelay(1000);
4338
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004339 if (s3resume) {
4340 if (info.cached_training == NULL) {
4341 u32 reg32;
4342 printk(BIOS_ERR,
4343 "Couldn't find training data. Rebooting\n");
4344 reg32 = inl(DEFAULT_PMBASE + 0x04);
4345 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4346 outb(0xe, 0xcf9);
Patrick Georgi546953c2014-11-29 10:38:17 +01004347 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004348 }
4349 int tm;
4350 info.training = *info.cached_training;
4351 for (tm = 0; tm < 4; tm++)
4352 for (channel = 0; channel < NUM_CHANNELS; channel++)
4353 for (slot = 0; slot < NUM_SLOTS; slot++)
4354 for (rank = 0; rank < NUM_RANKS; rank++)
4355 for (lane = 0; lane < 9; lane++)
4356 write_500(&info,
4357 channel,
4358 info.training.
4359 lane_timings
4360 [tm][channel]
4361 [slot][rank]
4362 [lane],
4363 get_timing_register_addr
4364 (lane, tm,
4365 slot, rank),
4366 9, 0);
4367 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4368 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4369 }
4370
Felix Heldf83d80b2018-07-29 05:30:30 +02004371 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004372 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004373 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
4374 tmp8 = MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004375
4376 program_board_delay(&info);
4377
Felix Held04be2dd2018-07-29 04:53:22 +02004378 MCHBAR8(0x5ff) = 0x0;
4379 MCHBAR8(0x5ff) = 0x80;
4380 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004381
Felix Held04be2dd2018-07-29 04:53:22 +02004382 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004383 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004384 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004385 gav(read_1d0(0x14b, 7)); // = 0x81023100
4386 write_1d0(0x30, 0x14b, 7, 1);
4387 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4388 write_1d0(7, 0xd6, 6, 1);
4389 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4390 write_1d0(7, 0x328, 6, 1);
4391
4392 for (channel = 0; channel < NUM_CHANNELS; channel++)
4393 set_4cf(&info, channel,
4394 info.populated_ranks[channel][0][0] ? 8 : 0);
4395
4396 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4397 write_1d0(2, 0x116, 4, 1);
4398 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4399 write_1d0(0, 0xae, 6, 1);
4400 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4401 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004402 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4403 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004404 MCHBAR32_AND(0x140, ~0x07000000);
4405 MCHBAR32_AND(0x138, ~0x07000000);
4406 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004407 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004408 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004409 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004410
4411 {
4412 u32 t;
4413 u8 val_a1;
4414 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4415 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4416 rmw_1d0(0x320, 0x07,
4417 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4418 rmw_1d0(0x14b, 0x78,
4419 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4420 4), 7,
4421 1);
4422 rmw_1d0(0xce, 0x38,
4423 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4424 4), 6,
4425 1);
4426 }
4427
4428 for (channel = 0; channel < NUM_CHANNELS; channel++)
4429 set_4cf(&info, channel,
4430 info.populated_ranks[channel][0][0] ? 9 : 1);
4431
4432 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Felix Heldf83d80b2018-07-29 05:30:30 +02004433 tmp32 = MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004434 write_1d0(2, 0xae, 6, 1);
4435 write_1d0(2, 0x300, 6, 1);
4436 write_1d0(2, 0x121, 3, 1);
4437 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4438 write_1d0(4, 0xd6, 6, 1);
4439 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4440 write_1d0(4, 0x328, 6, 1);
4441
4442 for (channel = 0; channel < NUM_CHANNELS; channel++)
4443 set_4cf(&info, channel,
4444 info.populated_ranks[channel][0][0] ? 9 : 0);
4445
Felix Held04be2dd2018-07-29 04:53:22 +02004446 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4447 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004448 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004449 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004450 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4451 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4452 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4453 write_1d0(0, 0x21c, 6, 1);
4454 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4455 write_1d0(0x35, 0x14b, 7, 1);
4456
4457 for (channel = 0; channel < NUM_CHANNELS; channel++)
4458 set_4cf(&info, channel,
4459 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4460
4461 set_334(1);
4462
Felix Held04be2dd2018-07-29 04:53:22 +02004463 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004464
4465 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4466 write_500(&info, channel,
4467 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4468 1);
4469 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4470 }
Felix Held04be2dd2018-07-29 04:53:22 +02004471 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4472 MCHBAR16(0x6c0) = 0x14a0;
4473 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4474 MCHBAR16(0x232) = 0x8;
4475 /* 0x40004 or 0 depending on ? */
4476 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4477 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4478 MCHBAR32(0x128) = 0x2150d05;
4479 MCHBAR8(0x12c) = 0x1f;
4480 MCHBAR8(0x12d) = 0x56;
4481 MCHBAR8(0x12e) = 0x31;
4482 MCHBAR8(0x12f) = 0x0;
4483 MCHBAR8(0x271) = 0x2;
4484 MCHBAR8(0x671) = 0x2;
4485 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004486 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004487 MCHBAR32(0x294 + (channel << 10)) =
4488 (info.populated_ranks_mask[channel] & 3) << 16;
4489 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4490 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004491 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004492 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4493 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004494
4495 if (!s3resume)
4496 jedec_init(&info);
4497
4498 int totalrank = 0;
4499 for (channel = 0; channel < NUM_CHANNELS; channel++)
4500 for (slot = 0; slot < NUM_SLOTS; slot++)
4501 for (rank = 0; rank < NUM_RANKS; rank++)
4502 if (info.populated_ranks[channel][slot][rank]) {
4503 jedec_read(&info, channel, slot, rank,
4504 totalrank, 0xa, 0x400);
4505 totalrank++;
4506 }
4507
Felix Held04be2dd2018-07-29 04:53:22 +02004508 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004509
Felix Heldf83d80b2018-07-29 05:30:30 +02004510 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4511 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004512
4513 if (!s3resume) {
4514 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004515 MCHBAR32(0x294 + (channel << 10)) =
4516 (info.populated_ranks_mask[channel] & 3) << 16;
4517 MCHBAR16(0x298 + (channel << 10)) =
4518 info.populated_ranks[channel][0][0] |
4519 (info.populated_ranks[channel][0][1] << 5);
4520 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004521 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004522 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004523
4524 {
4525 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004526 a = MCHBAR8(0x243);
4527 b = MCHBAR8(0x643);
4528 MCHBAR8(0x243) = a | 2;
4529 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004530 }
4531
4532 write_1d0(7, 0x19b, 3, 1);
4533 write_1d0(7, 0x1c0, 3, 1);
4534 write_1d0(4, 0x1c6, 4, 1);
4535 write_1d0(4, 0x1cc, 4, 1);
4536 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4537 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004538 MCHBAR32(0x584) = 0xfffff;
4539 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004540
4541 for (channel = 0; channel < NUM_CHANNELS; channel++)
4542 for (slot = 0; slot < NUM_SLOTS; slot++)
4543 for (rank = 0; rank < NUM_RANKS; rank++)
4544 if (info.
4545 populated_ranks[channel][slot]
4546 [rank])
4547 config_rank(&info, s3resume,
4548 channel, slot,
4549 rank);
4550
Felix Held04be2dd2018-07-29 04:53:22 +02004551 MCHBAR8(0x243) = 0x1;
4552 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004553 }
4554
4555 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004556 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004557 write_26c(0, 0x820);
4558 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004559 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004560 /* end */
4561
4562 if (s3resume) {
4563 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004564 MCHBAR32(0x294 + (channel << 10)) =
4565 (info.populated_ranks_mask[channel] & 3) << 16;
4566 MCHBAR16(0x298 + (channel << 10)) =
4567 info.populated_ranks[channel][0][0] |
4568 (info.populated_ranks[channel][0][1] << 5);
4569 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004570 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004571 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004572 }
4573
Felix Held04be2dd2018-07-29 04:53:22 +02004574 MCHBAR32_AND(0xfa4, ~0x01000002);
4575 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004576
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004577 /* Before training. */
4578 timestamp_add_now(103);
4579
4580 if (!s3resume)
4581 ram_training(&info);
4582
4583 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004584 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004585
4586 dump_timings(&info);
4587
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004588 program_modules_memory_map(&info, 0);
4589 program_total_memory_map(&info);
4590
4591 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004592 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004593 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004594 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004595 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004596 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004597 else
Felix Held04be2dd2018-07-29 04:53:22 +02004598 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004599
Felix Held04be2dd2018-07-29 04:53:22 +02004600 MCHBAR32_AND(0xfac, ~0x80000000);
4601 MCHBAR32(0xfb4) = 0x4800;
4602 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4603 MCHBAR32(0xe94) = 0x7ffff;
4604 MCHBAR32(0xfc0) = 0x80002040;
4605 MCHBAR32(0xfc4) = 0x701246;
4606 MCHBAR8_AND(0xfc8, ~0x70);
4607 MCHBAR32_OR(0xe5c, 0x1000000);
4608 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4609 MCHBAR32(0x50) = 0x700b0;
4610 MCHBAR32(0x3c) = 0x10;
4611 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4612 MCHBAR8_OR(0xff4, 0x2);
4613 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004614
Felix Held29a9c072018-07-29 01:34:45 +02004615#if 1
Felix Held04be2dd2018-07-29 04:53:22 +02004616 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4617 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4618 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004619
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004620 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4621 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4622 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004623
4624#else
4625 {
4626 u32 eax;
Felix Held04be2dd2018-07-29 04:53:22 +02004627 // = 0xe911714b
4628 eax = read32p(0xffc + (MCHBAR32(0xd00) & ~1)) | 0x08000000;
4629 write32p(0xffc + (MCHBAR32(0xd00) & ~1), eax);
4630 // = 0xe911714b
4631 eax = read32p(0xffc + (MCHBAR32(0xdc0) & ~1)) | 0x40000000;
4632 write32p(0xffc + (MCHBAR32(0xdc0) & ~1), eax);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004633 }
4634#endif
4635
4636 {
4637 u32 eax;
4638
4639 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004640 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4641 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4642 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004643 }
4644
4645 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004646 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004647 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004648 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004649 else
Felix Held04be2dd2018-07-29 04:53:22 +02004650 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004651
Felix Held04be2dd2018-07-29 04:53:22 +02004652 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004653
Felix Held04be2dd2018-07-29 04:53:22 +02004654 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004655 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004656 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004657 else
Felix Held04be2dd2018-07-29 04:53:22 +02004658 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004659 }
4660
Felix Held04be2dd2018-07-29 04:53:22 +02004661 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004662
4663 {
4664 u8 al;
4665 al = 0xd;
4666 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4667 al += 2;
4668 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004669 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004670 }
4671
4672 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004673 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4674 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4675 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4676 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004677 }
4678 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004679 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004680 reg1c = read32p(DEFAULT_EPBAR | 0x01c); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004681 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004682 write32p(DEFAULT_EPBAR | 0x01c, reg1c); // OK
Felix Heldf83d80b2018-07-29 05:30:30 +02004683 tmp8 = MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004684 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004685 MCHBAR8_OR(0x1210, 2);
4686 MCHBAR32(0x1200) = 0x8800440;
4687 MCHBAR32(0x1204) = 0x53ff0453;
4688 MCHBAR32(0x1208) = 0x19002043;
4689 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004690
4691 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004692 MCHBAR16(0x1214) = 0x220;
4693 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004694 }
4695
Felix Held04be2dd2018-07-29 04:53:22 +02004696 MCHBAR8_OR(0x1214, 0x4);
4697 MCHBAR8(0x120c) = 0x1;
4698 MCHBAR8(0x1218) = 0x3;
4699 MCHBAR8(0x121a) = 0x3;
4700 MCHBAR8(0x121c) = 0x3;
4701 MCHBAR16(0xc14) = 0x0;
4702 MCHBAR16(0xc20) = 0x0;
4703 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004704
4705 /* revision dependent here. */
4706
Felix Held04be2dd2018-07-29 04:53:22 +02004707 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004708
4709 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004710 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004711
Felix Held04be2dd2018-07-29 04:53:22 +02004712 MCHBAR16_OR(0x1230, 0x8000);
4713 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004714
4715 u8 bl, ebpb;
4716 u16 reg_1020;
4717
Felix Held04be2dd2018-07-29 04:53:22 +02004718 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4719 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004720
Felix Held04be2dd2018-07-29 04:53:22 +02004721 MCHBAR32(0x1000) = 0x100;
4722 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004723
4724 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004725 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004726 bl = reg_1020 >> 8;
4727 ebpb = reg_1020 & 0xff;
4728 } else {
4729 ebpb = 0;
4730 bl = 8;
4731 }
4732
4733 rdmsr(0x1a2);
4734
Felix Held04be2dd2018-07-29 04:53:22 +02004735 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004736
Felix Held04be2dd2018-07-29 04:53:22 +02004737 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004738
Felix Held04be2dd2018-07-29 04:53:22 +02004739 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004740
Felix Held04be2dd2018-07-29 04:53:22 +02004741 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004742 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004743 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4744 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004745 }
4746
4747 setup_heci_uma(&info);
4748
4749 if (info.uma_enabled) {
4750 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004751 MCHBAR32_OR(0x11b0, 0x4000);
4752 MCHBAR32_OR(0x11b4, 0x4000);
4753 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004754
Felix Held04be2dd2018-07-29 04:53:22 +02004755 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4756 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4757 MCHBAR16_OR(0x1170, 0x1000);
4758
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004759 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004760
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004761 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004762 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004763 ;
4764 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004765 }
4766
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004767 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4768 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004769 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004770 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004771
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004772 udelay(1000);
4773 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004774 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4775
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004776 if (!s3resume)
4777 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004778 if (s3resume && cbmem_wasnot_inited) {
4779 u32 reg32;
4780 printk(BIOS_ERR, "Failed S3 resume.\n");
4781 ram_check(0x100000, 0x200000);
4782
4783 /* Clear SLP_TYPE. */
4784 reg32 = inl(DEFAULT_PMBASE + 0x04);
4785 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4786
4787 /* Failed S3 resume, reset to come up cleanly */
4788 outb(0xe, 0xcf9);
Patrick Georgi546953c2014-11-29 10:38:17 +01004789 halt();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004790 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004791}