blob: 2051ff12ce9e4e9f2955a6f9ce622cff8243a984 [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>
Stefan Reinauer6a001132017-07-13 02:20:27 +020018#include <compiler.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010019#include <console/console.h>
20#include <string.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010021#include <arch/io.h>
22#include <cpu/x86/msr.h>
23#include <cbmem.h>
24#include <arch/cbfs.h>
25#include <cbfs.h>
26#include <ip_checksum.h>
27#include <pc80/mc146818rtc.h>
28#include <device/pci_def.h>
Patrick Rudolph266a1f72016-06-09 18:13:34 +020029#include <device/device.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010030#include <arch/cpu.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010031#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010032#include <spd.h>
33#include "raminit.h"
Patrick Rudolph266a1f72016-06-09 18:13:34 +020034#include "chip.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010035#include <timestamp.h>
36#include <cpu/x86/mtrr.h>
37#include <cpu/intel/speedstep.h>
38#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010039#include <mrc_cache.h>
Matthias Gazzaridfa51252018-05-19 00:44:20 +020040#include <arch/early_variables.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010041
42#include "nehalem.h"
43
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020044#include <southbridge/intel/ibexpeak/me.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010045#include <delay.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010046
47#define NORTHBRIDGE PCI_DEV(0, 0, 0)
48#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
49#define GMA PCI_DEV (0, 0x2, 0x0)
50#define HECIDEV PCI_DEV(0, 0x16, 0)
51#define HECIBAR 0x10
52
53#define FOR_ALL_RANKS \
54 for (channel = 0; channel < NUM_CHANNELS; channel++) \
55 for (slot = 0; slot < NUM_SLOTS; slot++) \
56 for (rank = 0; rank < NUM_RANKS; rank++)
57
58#define FOR_POPULATED_RANKS \
59 for (channel = 0; channel < NUM_CHANNELS; channel++) \
60 for (slot = 0; slot < NUM_SLOTS; slot++) \
61 for (rank = 0; rank < NUM_RANKS; rank++) \
62 if (info->populated_ranks[channel][slot][rank])
63
64#define FOR_POPULATED_RANKS_BACKWARDS \
65 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
66 for (slot = 0; slot < NUM_SLOTS; slot++) \
67 for (rank = 0; rank < NUM_RANKS; rank++) \
68 if (info->populated_ranks[channel][slot][rank])
69
70/* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */
71typedef struct {
72 u8 smallest;
73 u8 largest;
74} timing_bounds_t[2][2][2][9];
75
Arthur Heymansdc71e252018-01-29 10:14:48 +010076#define MRC_CACHE_VERSION 1
77
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010078struct ram_training {
79 /* [TM][CHANNEL][SLOT][RANK][LANE] */
80 u16 lane_timings[4][2][2][2][9];
81 u16 reg_178;
82 u16 reg_10b;
83
84 u8 reg178_center;
85 u8 reg178_smallest;
86 u8 reg178_largest;
87 timing_bounds_t timing_bounds[2];
88 u16 timing_offset[2][2][2][9];
89 u16 timing2_offset[2][2][2][9];
90 u16 timing2_bounds[2][2][2][9][2];
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +010091 u8 reg274265[2][3]; /* [CHANNEL][REGISTER] */
92 u8 reg2ca9_bit0;
93 u32 reg_6dc;
94 u32 reg_6e8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010095};
96
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010097#include <lib.h> /* Prototypes */
98
99static inline void write_mchbar32(u32 addr, u32 val)
100{
101 MCHBAR32(addr) = val;
102}
103
104static inline void write_mchbar16(u32 addr, u16 val)
105{
106 MCHBAR16(addr) = val;
107}
108
109static inline void write_mchbar8(u32 addr, u8 val)
110{
111 MCHBAR8(addr) = val;
112}
113
114
115static inline u32 read_mchbar32(u32 addr)
116{
117 return MCHBAR32(addr);
118}
119
120static inline u16 read_mchbar16(u32 addr)
121{
122 return MCHBAR16(addr);
123}
124
125static inline u8 read_mchbar8(u32 addr)
126{
127 return MCHBAR8(addr);
128}
129
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100130static void clflush(u32 addr)
131{
132 asm volatile ("clflush (%0)"::"r" (addr));
133}
134
135typedef struct _u128 {
136 u64 lo;
137 u64 hi;
138} u128;
139
140static void read128(u32 addr, u64 * out)
141{
142 u128 ret;
143 u128 stor;
144 asm volatile ("movdqu %%xmm0, %0\n"
145 "movdqa (%2), %%xmm0\n"
146 "movdqu %%xmm0, %1\n"
147 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
148 out[0] = ret.lo;
149 out[1] = ret.hi;
150}
151
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100152/* OK */
153static void write_1d0(u32 val, u16 addr, int bits, int flag)
154{
Felix Held04be2dd2018-07-29 04:53:22 +0200155 MCHBAR32(0x1d0) = 0;
156 while (MCHBAR32(0x1d0) & 0x800000)
157 ;
158 MCHBAR32(0x1d4) =
159 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
160 MCHBAR32(0x1d0) = 0x40000000 | addr;
161 while (read_mchbar32(0x1d0) & 0x800000)
162 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100163}
164
165/* OK */
166static u16 read_1d0(u16 addr, int split)
167{
168 u32 val;
Felix Held04be2dd2018-07-29 04:53:22 +0200169 MCHBAR32(0x1d0) = 0;
170 while (MCHBAR32(0x1d0) & 0x800000)
171 ;
172 MCHBAR32(0x1d0) =
173 0x80000000 | (((MCHBAR8(0x246) >> 2) & 3) + 0x361 - addr);
174 while (MCHBAR32(0x1d0) & 0x800000)
175 ;
176 val = MCHBAR32(0x1d8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100177 write_1d0(0, 0x33d, 0, 0);
178 write_1d0(0, 0x33d, 0, 0);
179 val &= ((1 << split) - 1);
180 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
181 return val;
182}
183
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800184static void write32p(uintptr_t addr, uint32_t val)
185{
186 write32((void *)addr, val);
187}
188
189static uint32_t read32p(uintptr_t addr)
190{
191 return read32((void *)addr);
192}
193
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100194static void sfence(void)
195{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100196 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100197}
198
199static inline u16 get_lane_offset(int slot, int rank, int lane)
200{
201 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
202 0x452 * (lane == 8);
203}
204
205static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
206{
207 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
208 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
209}
210
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100211static u32 gav_real(int line, u32 in)
212{
213 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
214 return in;
215}
216
217#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200218
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100219struct raminfo {
220 u16 clock_speed_index; /* clock_speed (REAL, not DDR) / 133.(3) - 3 */
221 u16 fsb_frequency; /* in 1.(1)/2 MHz. */
222 u8 is_x16_module[2][2]; /* [CHANNEL][SLOT] */
223 u8 density[2][2]; /* [CHANNEL][SLOT] */
224 u8 populated_ranks[2][2][2]; /* [CHANNEL][SLOT][RANK] */
225 int rank_start[2][2][2];
226 u8 cas_latency;
227 u8 board_lane_delay[9];
228 u8 use_ecc;
229 u8 revision;
230 u8 max_supported_clock_speed_index;
231 u8 uma_enabled;
232 u8 spd[2][2][151]; /* [CHANNEL][SLOT][BYTE] */
233 u8 silicon_revision;
234 u8 populated_ranks_mask[2];
235 u8 max_slots_used_in_channel;
236 u8 mode4030[2];
237 u16 avg4044[2];
238 u16 max4048[2];
239 unsigned total_memory_mb;
240 unsigned interleaved_part_mb;
241 unsigned non_interleaved_part_mb;
242
243 u32 heci_bar;
244 u64 heci_uma_addr;
245 unsigned memory_reserved_for_heci_mb;
246
247 struct ram_training training;
248 u32 last_500_command[2];
249
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100250 u32 delay46_ps[2];
251 u32 delay54_ps[2];
252 u8 revision_flag_1;
253 u8 some_delay_1_cycle_floor;
254 u8 some_delay_2_halfcycles_ceil;
255 u8 some_delay_3_ps_rounded;
256
257 const struct ram_training *cached_training;
258};
259
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200260/* Global allocation of timings_car */
261timing_bounds_t timings_car[64] CAR_GLOBAL;
262
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100263static void
264write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
265 int flag);
266
267/* OK */
268static u16
269read_500(struct raminfo *info, int channel, u16 addr, int split)
270{
271 u32 val;
272 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200273 MCHBAR32(0x500 + (channel << 10)) = 0;
274 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
275 ;
276 MCHBAR32(0x500 + (channel << 10)) =
277 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
278 + 0xb88 - addr);
279 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
280 ;
281 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100282 return val & ((1 << split) - 1);
283}
284
285/* OK */
286static void
287write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
288 int flag)
289{
290 if (info->last_500_command[channel] == 0x80000000) {
291 info->last_500_command[channel] = 0x40000000;
292 write_500(info, channel, 0, 0xb61, 0, 0);
293 }
Felix Held04be2dd2018-07-29 04:53:22 +0200294 MCHBAR32(0x500 + (channel << 10)) = 0;
295 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
296 ;
297 MCHBAR32(0x504 + (channel << 10)) =
298 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
299 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
300 while (read_mchbar32(0x500 + (channel << 10)) & 0x800000)
301 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100302}
303
304static int rw_test(int rank)
305{
306 const u32 mask = 0xf00fc33c;
307 int ok = 0xff;
308 int i;
309 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800310 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100311 sfence();
312 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800313 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100314 sfence();
315 for (i = 0; i < 32; i++) {
316 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800317 write32p((rank << 28) | (i << 3), pat);
318 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100319 }
320 sfence();
321 for (i = 0; i < 32; i++) {
322 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
323 int j;
324 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800325 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100326 for (j = 0; j < 4; j++)
327 if (((val >> (j * 8)) & 0xff) != pat)
328 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800329 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100330 for (j = 0; j < 4; j++)
331 if (((val >> (j * 8)) & 0xff) != pat)
332 ok &= ~(16 << j);
333 }
334 sfence();
335 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800336 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100337 sfence();
338 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800339 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100340
341 return ok;
342}
343
344static void
345program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
346{
347 int lane;
348 for (lane = 0; lane < 8; lane++) {
349 write_500(info, channel,
350 base +
351 info->training.
352 lane_timings[2][channel][slot][rank][lane],
353 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
354 write_500(info, channel,
355 base +
356 info->training.
357 lane_timings[3][channel][slot][rank][lane],
358 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
359 }
360}
361
362static void write_26c(int channel, u16 si)
363{
Felix Held04be2dd2018-07-29 04:53:22 +0200364 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
365 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
366 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100367}
368
369static u32 get_580(int channel, u8 addr)
370{
371 u32 ret;
372 gav(read_1d0(0x142, 3));
Felix Held04be2dd2018-07-29 04:53:22 +0200373 MCHBAR8(0x5ff) = 0x0;
374 MCHBAR8(0x5ff) = 0x80;
375 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
376 MCHBAR8_OR(0x580 + (channel << 10), 1);
377 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
378 ;
379 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100380 return ret;
381}
382
383const int cached_config = 0;
384
385#define NUM_CHANNELS 2
386#define NUM_SLOTS 2
387#define NUM_RANKS 2
388#define RANK_SHIFT 28
389#define CHANNEL_SHIFT 10
390
391#include "raminit_tables.c"
392
393static void seq9(struct raminfo *info, int channel, int slot, int rank)
394{
395 int i, lane;
396
397 for (i = 0; i < 2; i++)
398 for (lane = 0; lane < 8; lane++)
399 write_500(info, channel,
400 info->training.lane_timings[i +
401 1][channel][slot]
402 [rank][lane], get_timing_register_addr(lane,
403 i + 1,
404 slot,
405 rank),
406 9, 0);
407
408 write_1d0(1, 0x103, 6, 1);
409 for (lane = 0; lane < 8; lane++)
410 write_500(info, channel,
411 info->training.
412 lane_timings[0][channel][slot][rank][lane],
413 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
414
415 for (i = 0; i < 2; i++) {
416 for (lane = 0; lane < 8; lane++)
417 write_500(info, channel,
418 info->training.lane_timings[i +
419 1][channel][slot]
420 [rank][lane], get_timing_register_addr(lane,
421 i + 1,
422 slot,
423 rank),
424 9, 0);
425 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
426 }
427
428 gav(read_1d0(0x142, 3)); // = 0x10408118
Felix Held04be2dd2018-07-29 04:53:22 +0200429 MCHBAR8(0x5ff) = 0x0;
430 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100431 write_1d0(0x2, 0x142, 3, 1);
432 for (lane = 0; lane < 8; lane++) {
433 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
434 info->training.lane_timings[2][channel][slot][rank][lane] =
435 read_500(info, channel,
436 get_timing_register_addr(lane, 2, slot, rank), 9);
437 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
438 info->training.lane_timings[3][channel][slot][rank][lane] =
439 info->training.lane_timings[2][channel][slot][rank][lane] +
440 0x20;
441 }
442}
443
444static int count_ranks_in_channel(struct raminfo *info, int channel)
445{
446 int slot, rank;
447 int res = 0;
448 for (slot = 0; slot < NUM_SLOTS; slot++)
449 for (rank = 0; rank < NUM_SLOTS; rank++)
450 res += info->populated_ranks[channel][slot][rank];
451 return res;
452}
453
454static void
455config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
456{
457 int add;
458
459 write_1d0(0, 0x178, 7, 1);
460 seq9(info, channel, slot, rank);
461 program_timings(info, 0x80, channel, slot, rank);
462
463 if (channel == 0)
464 add = count_ranks_in_channel(info, 1);
465 else
466 add = 0;
467 if (!s3resume)
468 gav(rw_test(rank + add));
469 program_timings(info, 0x00, channel, slot, rank);
470 if (!s3resume)
471 gav(rw_test(rank + add));
472 if (!s3resume)
473 gav(rw_test(rank + add));
474 write_1d0(0, 0x142, 3, 1);
475 write_1d0(0, 0x103, 6, 1);
476
477 gav(get_580(channel, 0xc | (rank << 5)));
478 gav(read_1d0(0x142, 3));
479
Felix Held04be2dd2018-07-29 04:53:22 +0200480 MCHBAR8(0x5ff) = 0x0;
481 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100482}
483
484static void set_4cf(struct raminfo *info, int channel, u8 val)
485{
486 gav(read_500(info, channel, 0x4cf, 4)); // = 0xc2300cf9
487 write_500(info, channel, val, 0x4cf, 4, 1);
488 gav(read_500(info, channel, 0x659, 4)); // = 0x80300839
489 write_500(info, channel, val, 0x659, 4, 1);
490 gav(read_500(info, channel, 0x697, 4)); // = 0x80300839
491 write_500(info, channel, val, 0x697, 4, 1);
492}
493
494static void set_334(int zero)
495{
496 int j, k, channel;
497 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
498 u32 vd8[2][16];
499
500 for (channel = 0; channel < NUM_CHANNELS; channel++) {
501 for (j = 0; j < 4; j++) {
502 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
503 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
504 u16 c;
505 if ((j == 0 || j == 3) && zero)
506 c = 0;
507 else if (j == 3)
508 c = 0x5f;
509 else
510 c = 0x5f5f;
511
512 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200513 MCHBAR32(0x138 + 8 * k) =
514 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100515 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200516 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100517 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200518 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100519 }
520
521 write_mchbar32(0x334 + (channel << 10) + (j * 0x44),
522 zero ? 0 : val3[j]);
Felix Held04be2dd2018-07-29 04:53:22 +0200523 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
524 zero ? 0 : (0x18191819 & lmask);
525 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
526 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
527 zero ? 0 : (a & lmask);
528 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
529 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100530 }
531 }
532
Felix Held04be2dd2018-07-29 04:53:22 +0200533 MCHBAR32_OR(0x130, 1);
534 while (MCHBAR8(0x130) & 1)
535 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100536}
537
538static void rmw_1d0(u16 addr, u32 and, u32 or, int split, int flag)
539{
540 u32 v;
541 v = read_1d0(addr, split);
542 write_1d0((v & and) | or, addr, split, flag);
543}
544
545static int find_highest_bit_set(u16 val)
546{
547 int i;
548 for (i = 15; i >= 0; i--)
549 if (val & (1 << i))
550 return i;
551 return -1;
552}
553
554static int find_lowest_bit_set32(u32 val)
555{
556 int i;
557 for (i = 0; i < 32; i++)
558 if (val & (1 << i))
559 return i;
560 return -1;
561}
562
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100563enum {
564 DEVICE_TYPE = 2,
565 MODULE_TYPE = 3,
566 DENSITY = 4,
567 RANKS_AND_DQ = 7,
568 MEMORY_BUS_WIDTH = 8,
569 TIMEBASE_DIVIDEND = 10,
570 TIMEBASE_DIVISOR = 11,
571 CYCLETIME = 12,
572
573 CAS_LATENCIES_LSB = 14,
574 CAS_LATENCIES_MSB = 15,
575 CAS_LATENCY_TIME = 16,
576 THERMAL_AND_REFRESH = 31,
577 REFERENCE_RAW_CARD_USED = 62,
578 RANK1_ADDRESS_MAPPING = 63
579};
580
581static void calculate_timings(struct raminfo *info)
582{
583 unsigned cycletime;
584 unsigned cas_latency_time;
585 unsigned supported_cas_latencies;
586 unsigned channel, slot;
587 unsigned clock_speed_index;
588 unsigned min_cas_latency;
589 unsigned cas_latency;
590 unsigned max_clock_index;
591
592 /* Find common CAS latency */
593 supported_cas_latencies = 0x3fe;
594 for (channel = 0; channel < NUM_CHANNELS; channel++)
595 for (slot = 0; slot < NUM_SLOTS; slot++)
596 if (info->populated_ranks[channel][slot][0])
597 supported_cas_latencies &=
598 2 *
599 (info->
600 spd[channel][slot][CAS_LATENCIES_LSB] |
601 (info->
602 spd[channel][slot][CAS_LATENCIES_MSB] <<
603 8));
604
605 max_clock_index = min(3, info->max_supported_clock_speed_index);
606
607 cycletime = min_cycletime[max_clock_index];
608 cas_latency_time = min_cas_latency_time[max_clock_index];
609
610 for (channel = 0; channel < NUM_CHANNELS; channel++)
611 for (slot = 0; slot < NUM_SLOTS; slot++)
612 if (info->populated_ranks[channel][slot][0]) {
613 unsigned timebase;
614 timebase =
615 1000 *
616 info->
617 spd[channel][slot][TIMEBASE_DIVIDEND] /
618 info->spd[channel][slot][TIMEBASE_DIVISOR];
619 cycletime =
620 max(cycletime,
621 timebase *
622 info->spd[channel][slot][CYCLETIME]);
623 cas_latency_time =
624 max(cas_latency_time,
625 timebase *
626 info->
627 spd[channel][slot][CAS_LATENCY_TIME]);
628 }
629 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
630 if (cycletime == min_cycletime[clock_speed_index])
631 break;
632 if (cycletime > min_cycletime[clock_speed_index]) {
633 clock_speed_index--;
634 cycletime = min_cycletime[clock_speed_index];
635 break;
636 }
637 }
Edward O'Callaghan7116ac82014-07-08 01:53:24 +1000638 min_cas_latency = CEIL_DIV(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100639 cas_latency = 0;
640 while (supported_cas_latencies) {
641 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
642 if (cas_latency <= min_cas_latency)
643 break;
644 supported_cas_latencies &=
645 ~(1 << find_highest_bit_set(supported_cas_latencies));
646 }
647
648 if (cas_latency != min_cas_latency && clock_speed_index)
649 clock_speed_index--;
650
651 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
652 die("Couldn't configure DRAM");
653 info->clock_speed_index = clock_speed_index;
654 info->cas_latency = cas_latency;
655}
656
657static void program_base_timings(struct raminfo *info)
658{
659 unsigned channel;
660 unsigned slot, rank, lane;
661 unsigned extended_silicon_revision;
662 int i;
663
664 extended_silicon_revision = info->silicon_revision;
665 if (info->silicon_revision == 0)
666 for (channel = 0; channel < NUM_CHANNELS; channel++)
667 for (slot = 0; slot < NUM_SLOTS; slot++)
668 if ((info->
669 spd[channel][slot][MODULE_TYPE] & 0xF) ==
670 3)
671 extended_silicon_revision = 4;
672
673 for (channel = 0; channel < NUM_CHANNELS; channel++) {
674 for (slot = 0; slot < NUM_SLOTS; slot++)
675 for (rank = 0; rank < NUM_SLOTS; rank++) {
676 int card_timing_2;
677 if (!info->populated_ranks[channel][slot][rank])
678 continue;
679
680 for (lane = 0; lane < 9; lane++) {
681 int tm_reg;
682 int card_timing;
683
684 card_timing = 0;
685 if ((info->
686 spd[channel][slot][MODULE_TYPE] &
687 0xF) == 3) {
688 int reference_card;
689 reference_card =
690 info->
691 spd[channel][slot]
692 [REFERENCE_RAW_CARD_USED] &
693 0x1f;
694 if (reference_card == 3)
695 card_timing =
696 u16_ffd1188[0][lane]
697 [info->
698 clock_speed_index];
699 if (reference_card == 5)
700 card_timing =
701 u16_ffd1188[1][lane]
702 [info->
703 clock_speed_index];
704 }
705
706 info->training.
707 lane_timings[0][channel][slot][rank]
708 [lane] =
709 u8_FFFD1218[info->
710 clock_speed_index];
711 info->training.
712 lane_timings[1][channel][slot][rank]
713 [lane] = 256;
714
715 for (tm_reg = 2; tm_reg < 4; tm_reg++)
716 info->training.
717 lane_timings[tm_reg]
718 [channel][slot][rank][lane]
719 =
720 u8_FFFD1240[channel]
721 [extended_silicon_revision]
722 [lane][2 * slot +
723 rank][info->
724 clock_speed_index]
725 + info->max4048[channel]
726 +
727 u8_FFFD0C78[channel]
728 [extended_silicon_revision]
729 [info->
730 mode4030[channel]][slot]
731 [rank][info->
732 clock_speed_index]
733 + card_timing;
734 for (tm_reg = 0; tm_reg < 4; tm_reg++)
735 write_500(info, channel,
736 info->training.
737 lane_timings[tm_reg]
738 [channel][slot][rank]
739 [lane],
740 get_timing_register_addr
741 (lane, tm_reg, slot,
742 rank), 9, 0);
743 }
744
745 card_timing_2 = 0;
746 if (!(extended_silicon_revision != 4
747 || (info->
748 populated_ranks_mask[channel] & 5) ==
749 5)) {
750 if ((info->
751 spd[channel][slot]
752 [REFERENCE_RAW_CARD_USED] & 0x1F)
753 == 3)
754 card_timing_2 =
755 u16_FFFE0EB8[0][info->
756 clock_speed_index];
757 if ((info->
758 spd[channel][slot]
759 [REFERENCE_RAW_CARD_USED] & 0x1F)
760 == 5)
761 card_timing_2 =
762 u16_FFFE0EB8[1][info->
763 clock_speed_index];
764 }
765
766 for (i = 0; i < 3; i++)
767 write_500(info, channel,
768 (card_timing_2 +
769 info->max4048[channel]
770 +
771 u8_FFFD0EF8[channel]
772 [extended_silicon_revision]
773 [info->
774 mode4030[channel]][info->
775 clock_speed_index]),
776 u16_fffd0c50[i][slot][rank],
777 8, 1);
778 write_500(info, channel,
779 (info->max4048[channel] +
780 u8_FFFD0C78[channel]
781 [extended_silicon_revision][info->
782 mode4030
783 [channel]]
784 [slot][rank][info->
785 clock_speed_index]),
786 u16_fffd0c70[slot][rank], 7, 1);
787 }
788 if (!info->populated_ranks_mask[channel])
789 continue;
790 for (i = 0; i < 3; i++)
791 write_500(info, channel,
792 (info->max4048[channel] +
793 info->avg4044[channel]
794 +
795 u8_FFFD17E0[channel]
796 [extended_silicon_revision][info->
797 mode4030
798 [channel]][info->
799 clock_speed_index]),
800 u16_fffd0c68[i], 8, 1);
801 }
802}
803
804static unsigned int fsbcycle_ps(struct raminfo *info)
805{
806 return 900000 / info->fsb_frequency;
807}
808
809/* The time of DDR transfer in ps. */
810static unsigned int halfcycle_ps(struct raminfo *info)
811{
812 return 3750 / (info->clock_speed_index + 3);
813}
814
815/* The time of clock cycle in ps. */
816static unsigned int cycle_ps(struct raminfo *info)
817{
818 return 2 * halfcycle_ps(info);
819}
820
821/* Frequency in 1.(1)=10/9 MHz units. */
822static unsigned frequency_11(struct raminfo *info)
823{
824 return (info->clock_speed_index + 3) * 120;
825}
826
827/* Frequency in 0.1 MHz units. */
828static unsigned frequency_01(struct raminfo *info)
829{
830 return 100 * frequency_11(info) / 9;
831}
832
833static unsigned ps_to_halfcycles(struct raminfo *info, unsigned int ps)
834{
835 return (frequency_11(info) * 2) * ps / 900000;
836}
837
838static unsigned ns_to_cycles(struct raminfo *info, unsigned int ns)
839{
840 return (frequency_11(info)) * ns / 900;
841}
842
843static void compute_derived_timings(struct raminfo *info)
844{
845 unsigned channel, slot, rank;
846 int extended_silicon_revision;
847 int some_delay_1_ps;
848 int some_delay_2_ps;
849 int some_delay_2_halfcycles_ceil;
850 int some_delay_2_halfcycles_floor;
851 int some_delay_3_ps;
852 int some_delay_3_halfcycles;
853 int some_delay_3_ps_rounded;
854 int some_delay_1_cycle_ceil;
855 int some_delay_1_cycle_floor;
856
857 some_delay_3_halfcycles = 0;
858 some_delay_3_ps_rounded = 0;
859 extended_silicon_revision = info->silicon_revision;
860 if (!info->silicon_revision)
861 for (channel = 0; channel < NUM_CHANNELS; channel++)
862 for (slot = 0; slot < NUM_SLOTS; slot++)
863 if ((info->
864 spd[channel][slot][MODULE_TYPE] & 0xF) ==
865 3)
866 extended_silicon_revision = 4;
867 if (info->board_lane_delay[7] < 5)
868 info->board_lane_delay[7] = 5;
869 info->revision_flag_1 = 2;
870 if (info->silicon_revision == 2 || info->silicon_revision == 3)
871 info->revision_flag_1 = 0;
872 if (info->revision < 16)
873 info->revision_flag_1 = 0;
874
875 if (info->revision < 8)
876 info->revision_flag_1 = 0;
877 if (info->revision >= 8 && (info->silicon_revision == 0
878 || info->silicon_revision == 1))
879 some_delay_2_ps = 735;
880 else
881 some_delay_2_ps = 750;
882
883 if (info->revision >= 0x10 && (info->silicon_revision == 0
884 || info->silicon_revision == 1))
885 some_delay_1_ps = 3929;
886 else
887 some_delay_1_ps = 3490;
888
889 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
890 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
891 if (some_delay_1_ps % cycle_ps(info))
892 some_delay_1_cycle_ceil++;
893 else
894 some_delay_1_cycle_floor--;
895 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
896 if (info->revision_flag_1)
897 some_delay_2_ps = halfcycle_ps(info) >> 6;
898 some_delay_2_ps +=
899 max(some_delay_1_ps - 30,
900 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
901 375;
902 some_delay_3_ps =
903 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
904 if (info->revision_flag_1) {
905 if (some_delay_3_ps < 150)
906 some_delay_3_halfcycles = 0;
907 else
908 some_delay_3_halfcycles =
909 (some_delay_3_ps << 6) / halfcycle_ps(info);
910 some_delay_3_ps_rounded =
911 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
912 }
913 some_delay_2_halfcycles_ceil =
914 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
915 2 * (some_delay_1_cycle_ceil - 1);
916 if (info->revision_flag_1 && some_delay_3_ps < 150)
917 some_delay_2_halfcycles_ceil++;
918 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
919 if (info->revision < 0x10)
920 some_delay_2_halfcycles_floor =
921 some_delay_2_halfcycles_ceil - 1;
922 if (!info->revision_flag_1)
923 some_delay_2_halfcycles_floor++;
924 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
925 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
926 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
927 || (info->populated_ranks[1][0][0]
928 && info->populated_ranks[1][1][0]))
929 info->max_slots_used_in_channel = 2;
930 else
931 info->max_slots_used_in_channel = 1;
932 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200933 MCHBAR32(0x244 + (channel << 10)) =
934 ((info->revision < 8) ? 1 : 0x200) |
935 ((2 - info->max_slots_used_in_channel) << 17) |
936 (channel << 21) |
937 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100938 if (info->max_slots_used_in_channel == 1) {
939 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
940 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
941 } else {
942 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 */
943 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
944 || (count_ranks_in_channel(info, 1) ==
945 2)) ? 2 : 3;
946 }
947 for (channel = 0; channel < NUM_CHANNELS; channel++) {
948 int max_of_unk;
949 int min_of_unk_2;
950
951 int i, count;
952 int sum;
953
954 if (!info->populated_ranks_mask[channel])
955 continue;
956
957 max_of_unk = 0;
958 min_of_unk_2 = 32767;
959
960 sum = 0;
961 count = 0;
962 for (i = 0; i < 3; i++) {
963 int unk1;
964 if (info->revision < 8)
965 unk1 =
966 u8_FFFD1891[0][channel][info->
967 clock_speed_index]
968 [i];
969 else if (!
970 (info->revision >= 0x10
971 || info->revision_flag_1))
972 unk1 =
973 u8_FFFD1891[1][channel][info->
974 clock_speed_index]
975 [i];
976 else
977 unk1 = 0;
978 for (slot = 0; slot < NUM_SLOTS; slot++)
979 for (rank = 0; rank < NUM_RANKS; rank++) {
980 int a = 0;
981 int b = 0;
982
983 if (!info->
984 populated_ranks[channel][slot]
985 [rank])
986 continue;
987 if (extended_silicon_revision == 4
988 && (info->
989 populated_ranks_mask[channel] &
990 5) != 5) {
991 if ((info->
992 spd[channel][slot]
993 [REFERENCE_RAW_CARD_USED] &
994 0x1F) == 3) {
995 a = u16_ffd1178[0]
996 [info->
997 clock_speed_index];
998 b = u16_fe0eb8[0][info->
999 clock_speed_index];
1000 } else
1001 if ((info->
1002 spd[channel][slot]
1003 [REFERENCE_RAW_CARD_USED]
1004 & 0x1F) == 5) {
1005 a = u16_ffd1178[1]
1006 [info->
1007 clock_speed_index];
1008 b = u16_fe0eb8[1][info->
1009 clock_speed_index];
1010 }
1011 }
1012 min_of_unk_2 = min(min_of_unk_2, a);
1013 min_of_unk_2 = min(min_of_unk_2, b);
1014 if (rank == 0) {
1015 sum += a;
1016 count++;
1017 }
1018 {
1019 int t;
1020 t = b +
1021 u8_FFFD0EF8[channel]
1022 [extended_silicon_revision]
1023 [info->
1024 mode4030[channel]][info->
1025 clock_speed_index];
1026 if (unk1 >= t)
1027 max_of_unk =
1028 max(max_of_unk,
1029 unk1 - t);
1030 }
1031 }
1032 {
1033 int t =
1034 u8_FFFD17E0[channel]
1035 [extended_silicon_revision][info->
1036 mode4030
1037 [channel]]
1038 [info->clock_speed_index] + min_of_unk_2;
1039 if (unk1 >= t)
1040 max_of_unk = max(max_of_unk, unk1 - t);
1041 }
1042 }
1043
1044 info->avg4044[channel] = sum / count;
1045 info->max4048[channel] = max_of_unk;
1046 }
1047}
1048
1049static void jedec_read(struct raminfo *info,
1050 int channel, int slot, int rank,
1051 int total_rank, u8 addr3, unsigned int value)
1052{
1053 /* Handle mirrored mapping. */
1054 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001055 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1056 ((addr3 >> 1) & 0x10);
1057 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1058 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001059
1060 /* Handle mirrored mapping. */
1061 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1062 value =
1063 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1064 << 1);
1065
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001066 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001067
Felix Held04be2dd2018-07-29 04:53:22 +02001068 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1069 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001070
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001071 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001072}
1073
1074enum {
1075 MR1_RZQ12 = 512,
1076 MR1_RZQ2 = 64,
1077 MR1_RZQ4 = 4,
1078 MR1_ODS34OHM = 2
1079};
1080
1081enum {
1082 MR0_BT_INTERLEAVED = 8,
1083 MR0_DLL_RESET_ON = 256
1084};
1085
1086enum {
1087 MR2_RTT_WR_DISABLED = 0,
1088 MR2_RZQ2 = 1 << 10
1089};
1090
1091static void jedec_init(struct raminfo *info)
1092{
1093 int write_recovery;
1094 int channel, slot, rank;
1095 int total_rank;
1096 int dll_on;
1097 int self_refresh_temperature;
1098 int auto_self_refresh;
1099
1100 auto_self_refresh = 1;
1101 self_refresh_temperature = 1;
1102 if (info->board_lane_delay[3] <= 10) {
1103 if (info->board_lane_delay[3] <= 8)
1104 write_recovery = info->board_lane_delay[3] - 4;
1105 else
1106 write_recovery = 5;
1107 } else {
1108 write_recovery = 6;
1109 }
1110 FOR_POPULATED_RANKS {
1111 auto_self_refresh &=
1112 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1113 self_refresh_temperature &=
1114 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1115 }
1116 if (auto_self_refresh == 1)
1117 self_refresh_temperature = 0;
1118
1119 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1120 || (info->populated_ranks[0][0][0]
1121 && info->populated_ranks[0][1][0])
1122 || (info->populated_ranks[1][0][0]
1123 && info->populated_ranks[1][1][0]));
1124
1125 total_rank = 0;
1126
1127 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1128 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1129 int rzq_reg58e;
1130
1131 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1132 rzq_reg58e = 64;
1133 rtt = MR1_RZQ2;
1134 if (info->clock_speed_index != 0) {
1135 rzq_reg58e = 4;
1136 if (info->populated_ranks_mask[channel] == 3)
1137 rtt = MR1_RZQ4;
1138 }
1139 } else {
1140 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1141 rtt = MR1_RZQ12;
1142 rzq_reg58e = 64;
1143 rtt_wr = MR2_RZQ2;
1144 } else {
1145 rzq_reg58e = 4;
1146 rtt = MR1_RZQ4;
1147 }
1148 }
1149
Felix Held04be2dd2018-07-29 04:53:22 +02001150 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1151 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1152 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1153 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1154 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001155
1156 for (slot = 0; slot < NUM_SLOTS; slot++)
1157 for (rank = 0; rank < NUM_RANKS; rank++)
1158 if (info->populated_ranks[channel][slot][rank]) {
1159 jedec_read(info, channel, slot, rank,
1160 total_rank, 0x28,
1161 rtt_wr | (info->
1162 clock_speed_index
1163 << 3)
1164 | (auto_self_refresh << 6) |
1165 (self_refresh_temperature <<
1166 7));
1167 jedec_read(info, channel, slot, rank,
1168 total_rank, 0x38, 0);
1169 jedec_read(info, channel, slot, rank,
1170 total_rank, 0x18,
1171 rtt | MR1_ODS34OHM);
1172 jedec_read(info, channel, slot, rank,
1173 total_rank, 6,
1174 (dll_on << 12) |
1175 (write_recovery << 9)
1176 | ((info->cas_latency - 4) <<
1177 4) | MR0_BT_INTERLEAVED |
1178 MR0_DLL_RESET_ON);
1179 total_rank++;
1180 }
1181 }
1182}
1183
1184static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1185{
1186 unsigned channel, slot, rank;
1187 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1188 unsigned int channel_0_non_interleaved;
1189
1190 FOR_ALL_RANKS {
1191 if (info->populated_ranks[channel][slot][rank]) {
1192 total_mb[channel] +=
1193 pre_jedec ? 256 : (256 << info->
1194 density[channel][slot] >> info->
1195 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001196 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1197 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1198 (info->is_x16_module[channel][slot] |
1199 ((info->density[channel][slot] + 1) << 1))) |
1200 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001201 }
Felix Held04be2dd2018-07-29 04:53:22 +02001202 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1203 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001204 }
1205
1206 info->total_memory_mb = total_mb[0] + total_mb[1];
1207
1208 info->interleaved_part_mb =
1209 pre_jedec ? 0 : 2 * min(total_mb[0], total_mb[1]);
1210 info->non_interleaved_part_mb =
1211 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1212 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001213 MCHBAR32(0x100) = channel_0_non_interleaved |
1214 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001215 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001216 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001217}
1218
1219static void program_board_delay(struct raminfo *info)
1220{
1221 int cas_latency_shift;
1222 int some_delay_ns;
1223 int some_delay_3_half_cycles;
1224
1225 unsigned channel, i;
1226 int high_multiplier;
1227 int lane_3_delay;
1228 int cas_latency_derived;
1229
1230 high_multiplier = 0;
1231 some_delay_ns = 200;
1232 some_delay_3_half_cycles = 4;
1233 cas_latency_shift = info->silicon_revision == 0
1234 || info->silicon_revision == 1 ? 1 : 0;
1235 if (info->revision < 8) {
1236 some_delay_ns = 600;
1237 cas_latency_shift = 0;
1238 }
1239 {
1240 int speed_bit;
1241 speed_bit =
1242 ((info->clock_speed_index > 1
1243 || (info->silicon_revision != 2
1244 && info->silicon_revision != 3))) ^ (info->revision >=
1245 0x10);
1246 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1247 3, 1);
1248 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1249 3, 1);
1250 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1251 && (info->silicon_revision == 2
1252 || info->silicon_revision == 3))
1253 rmw_1d0(0x116, 5, 2, 4, 1);
1254 }
Felix Held04be2dd2018-07-29 04:53:22 +02001255 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1256 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001257
Felix Held04be2dd2018-07-29 04:53:22 +02001258 MCHBAR8(0x124) = info->board_lane_delay[4] +
1259 ((frequency_01(info) + 999) / 1000);
1260 MCHBAR16(0x125) = 0x1360;
1261 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001262 if (info->fsb_frequency < frequency_11(info) / 2) {
1263 unsigned some_delay_2_half_cycles;
1264 high_multiplier = 1;
1265 some_delay_2_half_cycles = ps_to_halfcycles(info,
1266 ((3 *
1267 fsbcycle_ps(info))
1268 >> 1) +
1269 (halfcycle_ps(info)
1270 *
1271 reg178_min[info->
1272 clock_speed_index]
1273 >> 6)
1274 +
1275 4 *
1276 halfcycle_ps(info)
1277 + 2230);
1278 some_delay_3_half_cycles =
1279 min((some_delay_2_half_cycles +
1280 (frequency_11(info) * 2) * (28 -
1281 some_delay_2_half_cycles) /
1282 (frequency_11(info) * 2 -
1283 4 * (info->fsb_frequency))) >> 3, 7);
1284 }
1285 if (read_mchbar8(0x2ca9) & 1)
1286 some_delay_3_half_cycles = 3;
1287 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001288 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1289 MCHBAR32(0x224 + (channel << 10)) =
1290 (info->max_slots_used_in_channel - 1) |
1291 ((info->cas_latency - 5 - info->clock_speed_index)
1292 << 21) | ((info->max_slots_used_in_channel +
1293 info->cas_latency - cas_latency_shift - 4) << 16) |
1294 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1295 ((info->cas_latency - info->clock_speed_index +
1296 info->max_slots_used_in_channel - 6) << 8);
1297 MCHBAR32(0x228 + (channel << 10)) =
1298 info->max_slots_used_in_channel;
1299 MCHBAR8(0x239 + (channel << 10)) = 32;
1300 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1301 (some_delay_3_half_cycles << 25) | 0x840000;
1302 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1303 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1304 MCHBAR32(0x24c + (channel << 10)) =
1305 ((!!info->clock_speed_index) << 17) |
1306 (((2 + info->clock_speed_index -
1307 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001308
Felix Held04be2dd2018-07-29 04:53:22 +02001309 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1310 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1311 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001312
1313 write_500(info, channel,
1314 ((!info->populated_ranks[channel][1][1])
1315 | (!info->populated_ranks[channel][1][0] << 1)
1316 | (!info->populated_ranks[channel][0][1] << 2)
1317 | (!info->populated_ranks[channel][0][0] << 3)),
1318 0x4c9, 4, 1);
1319 }
1320
1321 write_mchbar8(0x2c4, ((1 + (info->clock_speed_index != 0)) << 6) | 0xC);
1322 {
1323 u8 freq_divisor = 2;
1324 if (info->fsb_frequency == frequency_11(info))
1325 freq_divisor = 3;
1326 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1327 freq_divisor = 1;
1328 else
1329 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001330 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001331 }
1332
1333 if (info->board_lane_delay[3] <= 10) {
1334 if (info->board_lane_delay[3] <= 8)
1335 lane_3_delay = info->board_lane_delay[3];
1336 else
1337 lane_3_delay = 10;
1338 } else {
1339 lane_3_delay = 12;
1340 }
1341 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1342 if (info->clock_speed_index > 1)
1343 cas_latency_derived++;
1344 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001345 MCHBAR32(0x240 + (channel << 10)) =
1346 ((info->clock_speed_index == 0) * 0x11000) |
1347 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1348 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001349 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1350 0x609, 6, 1);
1351 write_500(info, channel,
1352 info->clock_speed_index + 2 * info->cas_latency - 7,
1353 0x601, 6, 1);
1354
Felix Held04be2dd2018-07-29 04:53:22 +02001355 MCHBAR32(0x250 + (channel << 10)) =
1356 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1357 (info->board_lane_delay[7] << 2) |
1358 (info->board_lane_delay[4] << 16) |
1359 (info->board_lane_delay[1] << 25) |
1360 (info->board_lane_delay[1] << 29) | 1;
1361 MCHBAR32(0x254 + (channel << 10)) =
1362 (info->board_lane_delay[1] >> 3) |
1363 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1364 0x80 | (info->board_lane_delay[6] << 1) |
1365 (info->board_lane_delay[2] << 28) |
1366 (cas_latency_derived << 16) | 0x4700000;
1367 MCHBAR32(0x258 + (channel << 10)) =
1368 ((info->board_lane_delay[5] + info->clock_speed_index +
1369 9) << 12) | ((info->clock_speed_index -
1370 info->cas_latency + 12) << 8) |
1371 (info->board_lane_delay[2] << 17) |
1372 (info->board_lane_delay[4] << 24) | 0x47;
1373 MCHBAR32(0x25c + (channel << 10)) =
1374 (info->board_lane_delay[1] << 1) |
1375 (info->board_lane_delay[0] << 8) | 0x1da50000;
1376 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1377 MCHBAR8(0x5f8 + (channel << 10)) =
1378 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001379 }
1380
1381 program_modules_memory_map(info, 1);
1382
Felix Held04be2dd2018-07-29 04:53:22 +02001383 MCHBAR16(0x610) = (min(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
1384 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1385 MCHBAR16_OR(0x612, 0x100);
1386 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001387 for (i = 0; i < 8; i++) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001388 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0x80 + 4 * i,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001389 (info->total_memory_mb - 64) | !i | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001390 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0xc0 + 4 * i, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001391 }
1392}
1393
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001394#define DEFAULT_PCI_MMIO_SIZE 2048
1395#define HOST_BRIDGE PCI_DEVFN(0, 0)
1396
1397static unsigned int get_mmio_size(void)
1398{
1399 const struct device *dev;
1400 const struct northbridge_intel_nehalem_config *cfg = NULL;
1401
1402 dev = dev_find_slot(0, HOST_BRIDGE);
1403 if (dev)
1404 cfg = dev->chip_info;
1405
1406 /* If this is zero, it just means devicetree.cb didn't set it */
1407 if (!cfg || cfg->pci_mmio_size == 0)
1408 return DEFAULT_PCI_MMIO_SIZE;
1409 else
1410 return cfg->pci_mmio_size;
1411}
1412
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001413#define BETTER_MEMORY_MAP 0
1414
1415static void program_total_memory_map(struct raminfo *info)
1416{
1417 unsigned int TOM, TOLUD, TOUUD;
1418 unsigned int quickpath_reserved;
1419 unsigned int REMAPbase;
1420 unsigned int uma_base_igd;
1421 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001422 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001423 int memory_remap;
1424 unsigned int memory_map[8];
1425 int i;
1426 unsigned int current_limit;
1427 unsigned int tseg_base;
1428 int uma_size_igd = 0, uma_size_gtt = 0;
1429
1430 memset(memory_map, 0, sizeof(memory_map));
1431
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001432 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001433 u16 t = pci_read_config16(NORTHBRIDGE, D0F0_GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001434 gav(t);
1435 const int uma_sizes_gtt[16] =
1436 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1437 /* Igd memory */
1438 const int uma_sizes_igd[16] = {
1439 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1440 256, 512
1441 };
1442
1443 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1444 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1445 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001446
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001447 mmio_size = get_mmio_size();
1448
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001449 TOM = info->total_memory_mb;
1450 if (TOM == 4096)
1451 TOM = 4032;
1452 TOUUD = ALIGN_DOWN(TOM - info->memory_reserved_for_heci_mb, 64);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001453 TOLUD = ALIGN_DOWN(min(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001454 , TOUUD), 64);
1455 memory_remap = 0;
1456 if (TOUUD - TOLUD > 64) {
1457 memory_remap = 1;
1458 REMAPbase = max(4096, TOUUD);
1459 TOUUD = TOUUD - TOLUD + 4096;
1460 }
1461 if (TOUUD > 4096)
1462 memory_map[2] = TOUUD | 1;
1463 quickpath_reserved = 0;
1464
1465 {
1466 u32 t;
1467
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001468 gav(t = pci_read_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 0x68));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001469 if (t & 0x800)
1470 quickpath_reserved =
1471 (1 << find_lowest_bit_set32(t >> 20));
1472 }
1473 if (memory_remap)
1474 TOUUD -= quickpath_reserved;
1475
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001476 uma_base_igd = TOLUD - uma_size_igd;
1477 uma_base_gtt = uma_base_igd - uma_size_gtt;
1478 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1479 if (!memory_remap)
1480 tseg_base -= quickpath_reserved;
1481 tseg_base = ALIGN_DOWN(tseg_base, 8);
1482
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001483 pci_write_config16(NORTHBRIDGE, D0F0_TOLUD, TOLUD << 4);
1484 pci_write_config16(NORTHBRIDGE, D0F0_TOM, TOM >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001485 if (memory_remap) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001486 pci_write_config16(NORTHBRIDGE, D0F0_REMAPBASE, REMAPbase >> 6);
1487 pci_write_config16(NORTHBRIDGE, D0F0_REMAPLIMIT, (TOUUD - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001488 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001489 pci_write_config16(NORTHBRIDGE, D0F0_TOUUD, TOUUD);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001490
1491 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001492 pci_write_config32(NORTHBRIDGE, D0F0_IGD_BASE, uma_base_igd << 20);
1493 pci_write_config32(NORTHBRIDGE, D0F0_GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001494 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001495 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001496
1497 current_limit = 0;
1498 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1499 memory_map[1] = 4096;
1500 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
1501 current_limit = max(current_limit, memory_map[i] & ~1);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001502 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0x80,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001503 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1504 1, 64) | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001505 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0xc0, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001506 }
1507}
1508
1509static void collect_system_info(struct raminfo *info)
1510{
1511 u32 capid0[3];
1512 int i;
1513 unsigned channel;
1514
1515 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001516 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1517 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001518
1519 if (!info->heci_bar)
1520 gav(info->heci_bar =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001521 pci_read_config32(HECIDEV, HECIBAR) & 0xFFFFFFF8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001522 if (!info->memory_reserved_for_heci_mb) {
1523 /* Wait for ME to be ready */
1524 intel_early_me_init();
1525 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1526 }
1527
1528 for (i = 0; i < 3; i++)
1529 gav(capid0[i] =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001530 pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 | (i << 2)));
1531 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001532 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1533
1534 if ((capid0[1] >> 11) & 1)
1535 info->uma_enabled = 0;
1536 else
1537 gav(info->uma_enabled =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001538 pci_read_config8(NORTHBRIDGE, D0F0_DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001539 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1540 info->silicon_revision = 0;
1541
1542 if (capid0[2] & 2) {
1543 info->silicon_revision = 0;
1544 info->max_supported_clock_speed_index = 2;
1545 for (channel = 0; channel < NUM_CHANNELS; channel++)
1546 if (info->populated_ranks[channel][0][0]
1547 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1548 3) {
1549 info->silicon_revision = 2;
1550 info->max_supported_clock_speed_index = 1;
1551 }
1552 } else {
1553 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1554 case 1:
1555 case 2:
1556 info->silicon_revision = 3;
1557 break;
1558 case 3:
1559 info->silicon_revision = 0;
1560 break;
1561 case 0:
1562 info->silicon_revision = 2;
1563 break;
1564 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001565 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001566 case 0x40:
1567 info->silicon_revision = 0;
1568 break;
1569 case 0x48:
1570 info->silicon_revision = 1;
1571 break;
1572 }
1573 }
1574}
1575
1576static void write_training_data(struct raminfo *info)
1577{
1578 int tm, channel, slot, rank, lane;
1579 if (info->revision < 8)
1580 return;
1581
1582 for (tm = 0; tm < 4; tm++)
1583 for (channel = 0; channel < NUM_CHANNELS; channel++)
1584 for (slot = 0; slot < NUM_SLOTS; slot++)
1585 for (rank = 0; rank < NUM_RANKS; rank++)
1586 for (lane = 0; lane < 9; lane++)
1587 write_500(info, channel,
1588 info->
1589 cached_training->
1590 lane_timings[tm]
1591 [channel][slot][rank]
1592 [lane],
1593 get_timing_register_addr
1594 (lane, tm, slot,
1595 rank), 9, 0);
1596 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1597 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1598}
1599
1600static void dump_timings(struct raminfo *info)
1601{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001602 int channel, slot, rank, lane, i;
1603 printk(BIOS_DEBUG, "Timings:\n");
1604 FOR_POPULATED_RANKS {
1605 printk(BIOS_DEBUG, "channel %d, slot %d, rank %d\n", channel,
1606 slot, rank);
1607 for (lane = 0; lane < 9; lane++) {
1608 printk(BIOS_DEBUG, "lane %d: ", lane);
1609 for (i = 0; i < 4; i++) {
1610 printk(BIOS_DEBUG, "%x (%x) ",
1611 read_500(info, channel,
1612 get_timing_register_addr
1613 (lane, i, slot, rank),
1614 9),
1615 info->training.
1616 lane_timings[i][channel][slot][rank]
1617 [lane]);
1618 }
1619 printk(BIOS_DEBUG, "\n");
1620 }
1621 }
1622 printk(BIOS_DEBUG, "[178] = %x (%x)\n", read_1d0(0x178, 7),
1623 info->training.reg_178);
1624 printk(BIOS_DEBUG, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
1625 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001626}
1627
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001628/* Read timings and other registers that need to be restored verbatim and
1629 put them to CBMEM.
1630 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001631static void save_timings(struct raminfo *info)
1632{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001633 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001634 int channel, slot, rank, lane, i;
1635
1636 train = info->training;
1637 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1638 for (i = 0; i < 4; i++)
1639 train.lane_timings[i][channel][slot][rank][lane] =
1640 read_500(info, channel,
1641 get_timing_register_addr(lane, i, slot,
1642 rank), 9);
1643 train.reg_178 = read_1d0(0x178, 7);
1644 train.reg_10b = read_1d0(0x10b, 6);
1645
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001646 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1647 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001648 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001649 train.reg274265[channel][0] = reg32 >> 16;
1650 train.reg274265[channel][1] = reg32 & 0xffff;
1651 train.reg274265[channel][2] = read_mchbar16 ((channel << 10) + 0x265) >> 8;
1652 }
Felix Held04be2dd2018-07-29 04:53:22 +02001653 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1654 train.reg_6dc = MCHBAR32(0x6dc);
1655 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001656
1657 printk (BIOS_SPEW, "[6dc] = %x\n", train.reg_6dc);
1658 printk (BIOS_SPEW, "[6e8] = %x\n", train.reg_6e8);
1659
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001660 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001661 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1662 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001663}
1664
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001665static const struct ram_training *get_cached_training(void)
1666{
Arthur Heymansdc71e252018-01-29 10:14:48 +01001667 struct region_device rdev;
1668 if (mrc_cache_get_current(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1669 &rdev))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001670 return 0;
Arthur Heymansdc71e252018-01-29 10:14:48 +01001671 return (void *)rdev_mmap_full(&rdev);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001672}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001673
1674/* FIXME: add timeout. */
1675static void wait_heci_ready(void)
1676{
Felix Held04be2dd2018-07-29 04:53:22 +02001677 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1678 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001679 write32((DEFAULT_HECIBAR + 0x4),
1680 (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001681}
1682
1683/* FIXME: add timeout. */
1684static void wait_heci_cb_avail(int len)
1685{
1686 union {
1687 struct mei_csr csr;
1688 u32 raw;
1689 } csr;
1690
Elyes HAOUAS7db506c2016-10-02 11:56:39 +02001691 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001692
1693 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001694 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001695 while (len >
1696 csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
1697 csr.csr.buffer_read_ptr));
1698}
1699
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001700static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001701{
1702 int len = (head->length + 3) / 4;
1703 int i;
1704
1705 wait_heci_cb_avail(len + 1);
1706
1707 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001708 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001709 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001710 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001711
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001712 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1713 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001714}
1715
1716static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001717send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001718{
1719 struct mei_header head;
1720 int maxlen;
1721
1722 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001723 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001724
1725 while (len) {
1726 int cur = len;
1727 if (cur > maxlen) {
1728 cur = maxlen;
1729 head.is_complete = 0;
1730 } else
1731 head.is_complete = 1;
1732 head.length = cur;
1733 head.reserved = 0;
1734 head.client_address = clientaddress;
1735 head.host_address = hostaddress;
1736 send_heci_packet(&head, (u32 *) msg);
1737 len -= cur;
1738 msg += cur;
1739 }
1740}
1741
1742/* FIXME: Add timeout. */
1743static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001744recv_heci_packet(struct raminfo *info, struct mei_header *head, u32 *packet,
1745 u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001746{
1747 union {
1748 struct mei_csr csr;
1749 u32 raw;
1750 } csr;
1751 int i = 0;
1752
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001753 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001754 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001755 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001756 }
Felix Held04be2dd2018-07-29 04:53:22 +02001757 while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr)
1758 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001759 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001760 if (!head->length) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001761 write32(DEFAULT_HECIBAR + 0x4,
1762 read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001763 *packet_size = 0;
1764 return 0;
1765 }
1766 if (head->length + 4 > 4 * csr.csr.buffer_depth
1767 || head->length > *packet_size) {
1768 *packet_size = 0;
1769 return -1;
1770 }
1771
1772 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001773 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001774 while ((head->length + 3) >> 2 >
1775 csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr);
1776
1777 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001778 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001779 *packet_size = head->length;
1780 if (!csr.csr.ready)
1781 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001782 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001783 return 0;
1784}
1785
1786/* FIXME: Add timeout. */
1787static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001788recv_heci_message(struct raminfo *info, u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001789{
1790 struct mei_header head;
1791 int current_position;
1792
1793 current_position = 0;
1794 while (1) {
1795 u32 current_size;
1796 current_size = *message_size - current_position;
1797 if (recv_heci_packet
1798 (info, &head, message + (current_position >> 2),
1799 &current_size) == -1)
1800 break;
1801 if (!current_size)
1802 break;
1803 current_position += current_size;
1804 if (head.is_complete) {
1805 *message_size = current_position;
1806 return 0;
1807 }
1808
1809 if (current_position >= *message_size)
1810 break;
1811 }
1812 *message_size = 0;
1813 return -1;
1814}
1815
1816static void send_heci_uma_message(struct raminfo *info)
1817{
1818 struct uma_reply {
1819 u8 group_id;
1820 u8 command;
1821 u8 reserved;
1822 u8 result;
1823 u8 field2;
1824 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001825 } __packed reply;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001826 struct uma_message {
1827 u8 group_id;
1828 u8 cmd;
1829 u8 reserved;
1830 u8 result;
1831 u32 c2;
1832 u64 heci_uma_addr;
1833 u32 memory_reserved_for_heci_mb;
1834 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001835 } __packed msg = {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001836 0, MKHI_SET_UMA, 0, 0,
1837 0x82,
1838 info->heci_uma_addr, info->memory_reserved_for_heci_mb, 0};
1839 u32 reply_size;
1840
1841 send_heci_message((u8 *) & msg, sizeof(msg), 0, 7);
1842
1843 reply_size = sizeof(reply);
1844 if (recv_heci_message(info, (u32 *) & reply, &reply_size) == -1)
1845 return;
1846
1847 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1848 die("HECI init failed\n");
1849}
1850
1851static void setup_heci_uma(struct raminfo *info)
1852{
1853 u32 reg44;
1854
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001855 reg44 = pci_read_config32(HECIDEV, 0x44); // = 0x80010020
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001856 info->memory_reserved_for_heci_mb = 0;
1857 info->heci_uma_addr = 0;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001858 if (!((reg44 & 0x10000) && !(pci_read_config32(HECIDEV, 0x40) & 0x20)))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001859 return;
1860
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001861 info->heci_bar = pci_read_config32(HECIDEV, 0x10) & 0xFFFFFFF0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001862 info->memory_reserved_for_heci_mb = reg44 & 0x3f;
1863 info->heci_uma_addr =
1864 ((u64)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001865 ((((u64) pci_read_config16(NORTHBRIDGE, D0F0_TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001866 info->memory_reserved_for_heci_mb)) << 20;
1867
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001868 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001869 if (info->memory_reserved_for_heci_mb) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001870 write32(DEFAULT_DMIBAR + 0x14,
1871 read32(DEFAULT_DMIBAR + 0x14) & ~0x80);
1872 write32(DEFAULT_RCBA + 0x14,
1873 read32(DEFAULT_RCBA + 0x14) & ~0x80);
1874 write32(DEFAULT_DMIBAR + 0x20,
1875 read32(DEFAULT_DMIBAR + 0x20) & ~0x80);
1876 write32(DEFAULT_RCBA + 0x20,
1877 read32(DEFAULT_RCBA + 0x20) & ~0x80);
1878 write32(DEFAULT_DMIBAR + 0x2c,
1879 read32(DEFAULT_DMIBAR + 0x2c) & ~0x80);
1880 write32(DEFAULT_RCBA + 0x30,
1881 read32(DEFAULT_RCBA + 0x30) & ~0x80);
1882 write32(DEFAULT_DMIBAR + 0x38,
1883 read32(DEFAULT_DMIBAR + 0x38) & ~0x80);
1884 write32(DEFAULT_RCBA + 0x40,
1885 read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001886
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001887 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
1888 write32(DEFAULT_DMIBAR + 0x38, 0x87000080); // OK
Felix Held04be2dd2018-07-29 04:53:22 +02001889 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
1890 read16(DEFAULT_DMIBAR + 0x3e) & 2)
1891 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001892 }
1893
Felix Held04be2dd2018-07-29 04:53:22 +02001894 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001895
1896 send_heci_uma_message(info);
1897
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001898 pci_write_config32(HECIDEV, 0x10, 0x0);
1899 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001900
1901}
1902
1903static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1904{
1905 int ranks_in_channel;
1906 ranks_in_channel = info->populated_ranks[channel][0][0]
1907 + info->populated_ranks[channel][0][1]
1908 + info->populated_ranks[channel][1][0]
1909 + info->populated_ranks[channel][1][1];
1910
1911 /* empty channel */
1912 if (ranks_in_channel == 0)
1913 return 1;
1914
1915 if (ranks_in_channel != ranks)
1916 return 0;
1917 /* single slot */
1918 if (info->populated_ranks[channel][0][0] !=
1919 info->populated_ranks[channel][1][0])
1920 return 1;
1921 if (info->populated_ranks[channel][0][1] !=
1922 info->populated_ranks[channel][1][1])
1923 return 1;
1924 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1925 return 0;
1926 if (info->density[channel][0] != info->density[channel][1])
1927 return 0;
1928 return 1;
1929}
1930
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001931static void read_4090(struct raminfo *info)
1932{
1933 int i, channel, slot, rank, lane;
1934 for (i = 0; i < 2; i++)
1935 for (slot = 0; slot < NUM_SLOTS; slot++)
1936 for (rank = 0; rank < NUM_RANKS; rank++)
1937 for (lane = 0; lane < 9; lane++)
1938 info->training.
1939 lane_timings[0][i][slot][rank][lane]
1940 = 32;
1941
1942 for (i = 1; i < 4; i++)
1943 for (channel = 0; channel < NUM_CHANNELS; channel++)
1944 for (slot = 0; slot < NUM_SLOTS; slot++)
1945 for (rank = 0; rank < NUM_RANKS; rank++)
1946 for (lane = 0; lane < 9; lane++) {
1947 info->training.
1948 lane_timings[i][channel]
1949 [slot][rank][lane] =
1950 read_500(info, channel,
1951 get_timing_register_addr
1952 (lane, i, slot,
1953 rank), 9)
1954 + (i == 1) * 11; // !!!!
1955 }
1956
1957}
1958
1959static u32 get_etalon2(int flip, u32 addr)
1960{
1961 const u16 invmask[] = {
1962 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1963 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1964 };
1965 u32 ret;
1966 u32 comp4 = addr / 480;
1967 addr %= 480;
1968 u32 comp1 = addr & 0xf;
1969 u32 comp2 = (addr >> 4) & 1;
1970 u32 comp3 = addr >> 5;
1971
1972 if (comp4)
1973 ret = 0x1010101 << (comp4 - 1);
1974 else
1975 ret = 0;
1976 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1977 ret = ~ret;
1978
1979 return ret;
1980}
1981
1982static void disable_cache(void)
1983{
1984 msr_t msr = {.lo = 0, .hi = 0 };
1985
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001986 wrmsr(MTRR_PHYS_BASE(3), msr);
1987 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001988}
1989
1990static void enable_cache(unsigned int base, unsigned int size)
1991{
1992 msr_t msr;
1993 msr.lo = base | MTRR_TYPE_WRPROT;
1994 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001995 wrmsr(MTRR_PHYS_BASE(3), msr);
1996 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001997 & 0xffffffff);
1998 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001999 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002000}
2001
2002static void flush_cache(u32 start, u32 size)
2003{
2004 u32 end;
2005 u32 addr;
2006
2007 end = start + (ALIGN_DOWN(size + 4096, 4096));
2008 for (addr = start; addr < end; addr += 64)
2009 clflush(addr);
2010}
2011
2012static void clear_errors(void)
2013{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002014 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002015}
2016
2017static void write_testing(struct raminfo *info, int totalrank, int flip)
2018{
2019 int nwrites = 0;
2020 /* in 8-byte units. */
2021 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002022 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002023
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002024 base = (u8 *)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002025 for (offset = 0; offset < 9 * 480; offset += 2) {
2026 write32(base + offset * 8, get_etalon2(flip, offset));
2027 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
2028 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
2029 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
2030 nwrites += 4;
2031 if (nwrites >= 320) {
2032 clear_errors();
2033 nwrites = 0;
2034 }
2035 }
2036}
2037
2038static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
2039{
2040 u8 failmask = 0;
2041 int i;
2042 int comp1, comp2, comp3;
2043 u32 failxor[2] = { 0, 0 };
2044
2045 enable_cache((total_rank << 28), 1728 * 5 * 4);
2046
2047 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
2048 for (comp1 = 0; comp1 < 4; comp1++)
2049 for (comp2 = 0; comp2 < 60; comp2++) {
2050 u32 re[4];
2051 u32 curroffset =
2052 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
2053 read128((total_rank << 28) | (curroffset << 3),
2054 (u64 *) re);
2055 failxor[0] |=
2056 get_etalon2(flip, curroffset) ^ re[0];
2057 failxor[1] |=
2058 get_etalon2(flip, curroffset) ^ re[1];
2059 failxor[0] |=
2060 get_etalon2(flip, curroffset | 1) ^ re[2];
2061 failxor[1] |=
2062 get_etalon2(flip, curroffset | 1) ^ re[3];
2063 }
2064 for (i = 0; i < 8; i++)
2065 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2066 failmask |= 1 << i;
2067 }
2068 disable_cache();
2069 flush_cache((total_rank << 28), 1728 * 5 * 4);
2070 return failmask;
2071}
2072
2073const u32 seed1[0x18] = {
2074 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2075 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2076 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2077 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2078 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2079 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2080};
2081
2082static u32 get_seed2(int a, int b)
2083{
2084 const u32 seed2[5] = {
2085 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2086 0x5b6db6db,
2087 };
2088 u32 r;
2089 r = seed2[(a + (a >= 10)) / 5];
2090 return b ? ~r : r;
2091}
2092
2093static int make_shift(int comp2, int comp5, int x)
2094{
2095 const u8 seed3[32] = {
2096 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2097 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2098 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2099 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2100 };
2101
2102 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2103}
2104
2105static u32 get_etalon(int flip, u32 addr)
2106{
2107 u32 mask_byte = 0;
2108 int comp1 = (addr >> 1) & 1;
2109 int comp2 = (addr >> 3) & 0x1f;
2110 int comp3 = (addr >> 8) & 0xf;
2111 int comp4 = (addr >> 12) & 0xf;
2112 int comp5 = (addr >> 16) & 0x1f;
2113 u32 mask_bit = ~(0x10001 << comp3);
2114 u32 part1;
2115 u32 part2;
2116 int byte;
2117
2118 part2 =
2119 ((seed1[comp5] >>
2120 make_shift(comp2, comp5,
2121 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2122 part1 =
2123 ((seed1[comp5] >>
2124 make_shift(comp2, comp5,
2125 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2126
2127 for (byte = 0; byte < 4; byte++)
2128 if ((get_seed2(comp5, comp4) >>
2129 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2130 mask_byte |= 0xff << (8 * byte);
2131
2132 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2133 (comp3 + 16));
2134}
2135
2136static void
2137write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2138 char flip)
2139{
2140 int i;
2141 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002142 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2143 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002144}
2145
2146static u8
2147check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2148 char flip)
2149{
2150 u8 failmask = 0;
2151 u32 failxor[2];
2152 int i;
2153 int comp1, comp2, comp3;
2154
2155 failxor[0] = 0;
2156 failxor[1] = 0;
2157
2158 enable_cache(totalrank << 28, 134217728);
2159 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2160 for (comp1 = 0; comp1 < 16; comp1++)
2161 for (comp2 = 0; comp2 < 64; comp2++) {
2162 u32 addr =
2163 (totalrank << 28) | (region << 25) | (block
2164 << 16)
2165 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2166 2);
2167 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002168 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002169 }
2170 for (i = 0; i < 8; i++)
2171 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2172 failmask |= 1 << i;
2173 }
2174 disable_cache();
2175 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2176 return failmask;
2177}
2178
2179static int check_bounded(unsigned short *vals, u16 bound)
2180{
2181 int i;
2182
2183 for (i = 0; i < 8; i++)
2184 if (vals[i] < bound)
2185 return 0;
2186 return 1;
2187}
2188
2189enum state {
2190 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2191};
2192
2193static int validate_state(enum state *in)
2194{
2195 int i;
2196 for (i = 0; i < 8; i++)
2197 if (in[i] != COMPLETE)
2198 return 0;
2199 return 1;
2200}
2201
2202static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002203do_fsm(enum state *state, u16 *counter,
2204 u8 fail_mask, int margin, int uplimit,
2205 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002206{
2207 int lane;
2208
2209 for (lane = 0; lane < 8; lane++) {
2210 int is_fail = (fail_mask >> lane) & 1;
2211 switch (state[lane]) {
2212 case BEFORE_USABLE:
2213 if (!is_fail) {
2214 counter[lane] = 1;
2215 state[lane] = AT_USABLE;
2216 break;
2217 }
2218 counter[lane] = 0;
2219 state[lane] = BEFORE_USABLE;
2220 break;
2221 case AT_USABLE:
2222 if (!is_fail) {
2223 ++counter[lane];
2224 if (counter[lane] >= margin) {
2225 state[lane] = AT_MARGIN;
2226 res_low[lane] = val - margin + 1;
2227 break;
2228 }
2229 state[lane] = 1;
2230 break;
2231 }
2232 counter[lane] = 0;
2233 state[lane] = BEFORE_USABLE;
2234 break;
2235 case AT_MARGIN:
2236 if (is_fail) {
2237 state[lane] = COMPLETE;
2238 res_high[lane] = val - 1;
2239 } else {
2240 counter[lane]++;
2241 state[lane] = AT_MARGIN;
2242 if (val == uplimit) {
2243 state[lane] = COMPLETE;
2244 res_high[lane] = uplimit;
2245 }
2246 }
2247 break;
2248 case COMPLETE:
2249 break;
2250 }
2251 }
2252}
2253
2254static void
2255train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2256 u8 total_rank, u8 reg_178, int first_run, int niter,
2257 timing_bounds_t * timings)
2258{
2259 int lane;
2260 enum state state[8];
2261 u16 count[8];
2262 u8 lower_usable[8];
2263 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002264 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002265 u8 secondary_total_rank;
2266 u8 reg1b3;
2267
2268 if (info->populated_ranks_mask[1]) {
2269 if (channel == 1)
2270 secondary_total_rank =
2271 info->populated_ranks[1][0][0] +
2272 info->populated_ranks[1][0][1]
2273 + info->populated_ranks[1][1][0] +
2274 info->populated_ranks[1][1][1];
2275 else
2276 secondary_total_rank = 0;
2277 } else
2278 secondary_total_rank = total_rank;
2279
2280 {
2281 int i;
2282 for (i = 0; i < 8; i++)
2283 state[i] = BEFORE_USABLE;
2284 }
2285
2286 if (!first_run) {
2287 int is_all_ok = 1;
2288 for (lane = 0; lane < 8; lane++)
2289 if (timings[reg_178][channel][slot][rank][lane].
2290 smallest ==
2291 timings[reg_178][channel][slot][rank][lane].
2292 largest) {
2293 timings[reg_178][channel][slot][rank][lane].
2294 smallest = 0;
2295 timings[reg_178][channel][slot][rank][lane].
2296 largest = 0;
2297 is_all_ok = 0;
2298 }
2299 if (is_all_ok) {
2300 int i;
2301 for (i = 0; i < 8; i++)
2302 state[i] = COMPLETE;
2303 }
2304 }
2305
2306 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2307 u8 failmask = 0;
2308 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2309 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2310 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002311 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002312 do_fsm(state, count, failmask, 5, 47, lower_usable,
2313 upper_usable, reg1b3);
2314 }
2315
2316 if (reg1b3) {
2317 write_1d0(0, 0x1b3, 6, 1);
2318 write_1d0(0, 0x1a3, 6, 1);
2319 for (lane = 0; lane < 8; lane++) {
2320 if (state[lane] == COMPLETE) {
2321 timings[reg_178][channel][slot][rank][lane].
2322 smallest =
2323 lower_usable[lane] +
2324 (info->training.
2325 lane_timings[0][channel][slot][rank][lane]
2326 & 0x3F) - 32;
2327 timings[reg_178][channel][slot][rank][lane].
2328 largest =
2329 upper_usable[lane] +
2330 (info->training.
2331 lane_timings[0][channel][slot][rank][lane]
2332 & 0x3F) - 32;
2333 }
2334 }
2335 }
2336
2337 if (!first_run) {
2338 for (lane = 0; lane < 8; lane++)
2339 if (state[lane] == COMPLETE) {
2340 write_500(info, channel,
2341 timings[reg_178][channel][slot][rank]
2342 [lane].smallest,
2343 get_timing_register_addr(lane, 0,
2344 slot, rank),
2345 9, 1);
2346 write_500(info, channel,
2347 timings[reg_178][channel][slot][rank]
2348 [lane].smallest +
2349 info->training.
2350 lane_timings[1][channel][slot][rank]
2351 [lane]
2352 -
2353 info->training.
2354 lane_timings[0][channel][slot][rank]
2355 [lane], get_timing_register_addr(lane,
2356 1,
2357 slot,
2358 rank),
2359 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002360 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002361 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002362 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002363
2364 do {
2365 u8 failmask = 0;
2366 int i;
2367 for (i = 0; i < niter; i++) {
2368 if (failmask == 0xFF)
2369 break;
2370 failmask |=
2371 check_testing_type2(info, total_rank, 2, i,
2372 0);
2373 failmask |=
2374 check_testing_type2(info, total_rank, 3, i,
2375 1);
2376 }
Felix Held04be2dd2018-07-29 04:53:22 +02002377 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002378 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002379 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002380 if ((1 << lane) & failmask) {
2381 if (timings[reg_178][channel]
2382 [slot][rank][lane].
2383 largest <=
2384 timings[reg_178][channel]
2385 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002386 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002387 [lane] = -1;
2388 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002389 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002390 [lane] = 0;
2391 timings[reg_178]
2392 [channel][slot]
2393 [rank][lane].
2394 smallest++;
2395 write_500(info, channel,
2396 timings
2397 [reg_178]
2398 [channel]
2399 [slot][rank]
2400 [lane].
2401 smallest,
2402 get_timing_register_addr
2403 (lane, 0,
2404 slot, rank),
2405 9, 1);
2406 write_500(info, channel,
2407 timings
2408 [reg_178]
2409 [channel]
2410 [slot][rank]
2411 [lane].
2412 smallest +
2413 info->
2414 training.
2415 lane_timings
2416 [1][channel]
2417 [slot][rank]
2418 [lane]
2419 -
2420 info->
2421 training.
2422 lane_timings
2423 [0][channel]
2424 [slot][rank]
2425 [lane],
2426 get_timing_register_addr
2427 (lane, 1,
2428 slot, rank),
2429 9, 1);
2430 }
2431 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002432 num_successfully_checked[lane]
2433 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002434 }
2435 }
Felix Held04be2dd2018-07-29 04:53:22 +02002436 while (!check_bounded(num_successfully_checked, 2))
2437 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002438
2439 for (lane = 0; lane < 8; lane++)
2440 if (state[lane] == COMPLETE) {
2441 write_500(info, channel,
2442 timings[reg_178][channel][slot][rank]
2443 [lane].largest,
2444 get_timing_register_addr(lane, 0,
2445 slot, rank),
2446 9, 1);
2447 write_500(info, channel,
2448 timings[reg_178][channel][slot][rank]
2449 [lane].largest +
2450 info->training.
2451 lane_timings[1][channel][slot][rank]
2452 [lane]
2453 -
2454 info->training.
2455 lane_timings[0][channel][slot][rank]
2456 [lane], get_timing_register_addr(lane,
2457 1,
2458 slot,
2459 rank),
2460 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002461 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002462 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002463 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002464
2465 do {
2466 int failmask = 0;
2467 int i;
2468 for (i = 0; i < niter; i++) {
2469 if (failmask == 0xFF)
2470 break;
2471 failmask |=
2472 check_testing_type2(info, total_rank, 2, i,
2473 0);
2474 failmask |=
2475 check_testing_type2(info, total_rank, 3, i,
2476 1);
2477 }
2478
Felix Held04be2dd2018-07-29 04:53:22 +02002479 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002480 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002481 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002482 if ((1 << lane) & failmask) {
2483 if (timings[reg_178][channel]
2484 [slot][rank][lane].
2485 largest <=
2486 timings[reg_178][channel]
2487 [slot][rank][lane].
2488 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002489 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002490 [lane] = -1;
2491 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002492 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002493 [lane] = 0;
2494 timings[reg_178]
2495 [channel][slot]
2496 [rank][lane].
2497 largest--;
2498 write_500(info, channel,
2499 timings
2500 [reg_178]
2501 [channel]
2502 [slot][rank]
2503 [lane].
2504 largest,
2505 get_timing_register_addr
2506 (lane, 0,
2507 slot, rank),
2508 9, 1);
2509 write_500(info, channel,
2510 timings
2511 [reg_178]
2512 [channel]
2513 [slot][rank]
2514 [lane].
2515 largest +
2516 info->
2517 training.
2518 lane_timings
2519 [1][channel]
2520 [slot][rank]
2521 [lane]
2522 -
2523 info->
2524 training.
2525 lane_timings
2526 [0][channel]
2527 [slot][rank]
2528 [lane],
2529 get_timing_register_addr
2530 (lane, 1,
2531 slot, rank),
2532 9, 1);
2533 }
2534 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002535 num_successfully_checked[lane]
2536 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002537 }
2538 }
2539 }
Felix Held04be2dd2018-07-29 04:53:22 +02002540 while (!check_bounded(num_successfully_checked, 3))
2541 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002542
2543 for (lane = 0; lane < 8; lane++) {
2544 write_500(info, channel,
2545 info->training.
2546 lane_timings[0][channel][slot][rank][lane],
2547 get_timing_register_addr(lane, 0, slot, rank),
2548 9, 1);
2549 write_500(info, channel,
2550 info->training.
2551 lane_timings[1][channel][slot][rank][lane],
2552 get_timing_register_addr(lane, 1, slot, rank),
2553 9, 1);
2554 if (timings[reg_178][channel][slot][rank][lane].
2555 largest <=
2556 timings[reg_178][channel][slot][rank][lane].
2557 smallest) {
2558 timings[reg_178][channel][slot][rank][lane].
2559 largest = 0;
2560 timings[reg_178][channel][slot][rank][lane].
2561 smallest = 0;
2562 }
2563 }
2564 }
2565}
2566
2567static void set_10b(struct raminfo *info, u8 val)
2568{
2569 int channel;
2570 int slot, rank;
2571 int lane;
2572
2573 if (read_1d0(0x10b, 6) == val)
2574 return;
2575
2576 write_1d0(val, 0x10b, 6, 1);
2577
2578 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2579 u16 reg_500;
2580 reg_500 = read_500(info, channel,
2581 get_timing_register_addr(lane, 0, slot,
2582 rank), 9);
2583 if (val == 1) {
2584 if (lut16[info->clock_speed_index] <= reg_500)
2585 reg_500 -= lut16[info->clock_speed_index];
2586 else
2587 reg_500 = 0;
2588 } else {
2589 reg_500 += lut16[info->clock_speed_index];
2590 }
2591 write_500(info, channel, reg_500,
2592 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2593 }
2594}
2595
2596static void set_ecc(int onoff)
2597{
2598 int channel;
2599 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2600 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002601 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002602 if (onoff)
2603 t |= 1;
2604 else
2605 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002606 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002607 }
2608}
2609
2610static void set_178(u8 val)
2611{
2612 if (val >= 31)
2613 val = val - 31;
2614 else
2615 val = 63 - val;
2616
2617 write_1d0(2 * val, 0x178, 7, 1);
2618}
2619
2620static void
2621write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2622 int type)
2623{
2624 int lane;
2625
2626 for (lane = 0; lane < 8; lane++)
2627 write_500(info, channel,
2628 info->training.
2629 lane_timings[type][channel][slot][rank][lane],
2630 get_timing_register_addr(lane, type, slot, rank), 9,
2631 0);
2632}
2633
2634static void
2635try_timing_offsets(struct raminfo *info, int channel,
2636 int slot, int rank, int totalrank)
2637{
2638 u16 count[8];
2639 enum state state[8];
2640 u8 lower_usable[8], upper_usable[8];
2641 int lane;
2642 int i;
2643 int flip = 1;
2644 int timing_offset;
2645
2646 for (i = 0; i < 8; i++)
2647 state[i] = BEFORE_USABLE;
2648
2649 memset(count, 0, sizeof(count));
2650
2651 for (lane = 0; lane < 8; lane++)
2652 write_500(info, channel,
2653 info->training.
2654 lane_timings[2][channel][slot][rank][lane] + 32,
2655 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2656
2657 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2658 timing_offset++) {
2659 u8 failmask;
2660 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2661 failmask = 0;
2662 for (i = 0; i < 2 && failmask != 0xff; i++) {
2663 flip = !flip;
2664 write_testing(info, totalrank, flip);
2665 failmask |= check_testing(info, totalrank, flip);
2666 }
2667 do_fsm(state, count, failmask, 10, 63, lower_usable,
2668 upper_usable, timing_offset);
2669 }
2670 write_1d0(0, 0x1bb, 6, 1);
2671 dump_timings(info);
2672 if (!validate_state(state))
2673 die("Couldn't discover DRAM timings (1)\n");
2674
2675 for (lane = 0; lane < 8; lane++) {
2676 u8 bias = 0;
2677
2678 if (info->silicon_revision) {
2679 int usable_length;
2680
2681 usable_length = upper_usable[lane] - lower_usable[lane];
2682 if (usable_length >= 20) {
2683 bias = usable_length / 2 - 10;
2684 if (bias >= 2)
2685 bias = 2;
2686 }
2687 }
2688 write_500(info, channel,
2689 info->training.
2690 lane_timings[2][channel][slot][rank][lane] +
2691 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2692 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2693 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2694 info->training.lane_timings[2][channel][slot][rank][lane] +
2695 lower_usable[lane];
2696 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2697 info->training.lane_timings[2][channel][slot][rank][lane] +
2698 upper_usable[lane];
2699 info->training.timing2_offset[channel][slot][rank][lane] =
2700 info->training.lane_timings[2][channel][slot][rank][lane];
2701 }
2702}
2703
2704static u8
2705choose_training(struct raminfo *info, int channel, int slot, int rank,
2706 int lane, timing_bounds_t * timings, u8 center_178)
2707{
2708 u16 central_weight;
2709 u16 side_weight;
2710 unsigned int sum = 0, count = 0;
2711 u8 span;
2712 u8 lower_margin, upper_margin;
2713 u8 reg_178;
2714 u8 result;
2715
2716 span = 12;
2717 central_weight = 20;
2718 side_weight = 20;
2719 if (info->silicon_revision == 1 && channel == 1) {
2720 central_weight = 5;
2721 side_weight = 20;
2722 if ((info->
2723 populated_ranks_mask[1] ^ (info->
2724 populated_ranks_mask[1] >> 2)) &
2725 1)
2726 span = 18;
2727 }
2728 if ((info->populated_ranks_mask[0] & 5) == 5) {
2729 central_weight = 20;
2730 side_weight = 20;
2731 }
2732 if (info->clock_speed_index >= 2
2733 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2734 if (info->silicon_revision == 1) {
2735 switch (channel) {
2736 case 0:
2737 if (lane == 1) {
2738 central_weight = 10;
2739 side_weight = 20;
2740 }
2741 break;
2742 case 1:
2743 if (lane == 6) {
2744 side_weight = 5;
2745 central_weight = 20;
2746 }
2747 break;
2748 }
2749 }
2750 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2751 side_weight = 5;
2752 central_weight = 20;
2753 }
2754 }
2755 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2756 reg_178 += span) {
2757 u8 smallest;
2758 u8 largest;
2759 largest = timings[reg_178][channel][slot][rank][lane].largest;
2760 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2761 if (largest - smallest + 1 >= 5) {
2762 unsigned int weight;
2763 if (reg_178 == center_178)
2764 weight = central_weight;
2765 else
2766 weight = side_weight;
2767 sum += weight * (largest + smallest);
2768 count += weight;
2769 }
2770 }
2771 dump_timings(info);
2772 if (count == 0)
2773 die("Couldn't discover DRAM timings (2)\n");
2774 result = sum / (2 * count);
2775 lower_margin =
2776 result - timings[center_178][channel][slot][rank][lane].smallest;
2777 upper_margin =
2778 timings[center_178][channel][slot][rank][lane].largest - result;
2779 if (upper_margin < 10 && lower_margin > 10)
2780 result -= min(lower_margin - 10, 10 - upper_margin);
2781 if (upper_margin > 10 && lower_margin < 10)
2782 result += min(upper_margin - 10, 10 - lower_margin);
2783 return result;
2784}
2785
2786#define STANDARD_MIN_MARGIN 5
2787
2788static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2789{
2790 u16 margin[64];
2791 int lane, rank, slot, channel;
2792 u8 reg178;
2793 int count = 0, sum = 0;
2794
2795 for (reg178 = reg178_min[info->clock_speed_index];
2796 reg178 < reg178_max[info->clock_speed_index];
2797 reg178 += reg178_step[info->clock_speed_index]) {
2798 margin[reg178] = -1;
2799 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2800 int curmargin =
2801 timings[reg178][channel][slot][rank][lane].largest -
2802 timings[reg178][channel][slot][rank][lane].
2803 smallest + 1;
2804 if (curmargin < margin[reg178])
2805 margin[reg178] = curmargin;
2806 }
2807 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2808 u16 weight;
2809 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2810 sum += weight * reg178;
2811 count += weight;
2812 }
2813 }
2814 dump_timings(info);
2815 if (count == 0)
2816 die("Couldn't discover DRAM timings (3)\n");
2817
2818 u8 threshold;
2819
2820 for (threshold = 30; threshold >= 5; threshold--) {
2821 int usable_length = 0;
2822 int smallest_fount = 0;
2823 for (reg178 = reg178_min[info->clock_speed_index];
2824 reg178 < reg178_max[info->clock_speed_index];
2825 reg178 += reg178_step[info->clock_speed_index])
2826 if (margin[reg178] >= threshold) {
2827 usable_length +=
2828 reg178_step[info->clock_speed_index];
2829 info->training.reg178_largest =
2830 reg178 -
2831 2 * reg178_step[info->clock_speed_index];
2832
2833 if (!smallest_fount) {
2834 smallest_fount = 1;
2835 info->training.reg178_smallest =
2836 reg178 +
2837 reg178_step[info->
2838 clock_speed_index];
2839 }
2840 }
2841 if (usable_length >= 0x21)
2842 break;
2843 }
2844
2845 return sum / count;
2846}
2847
2848static int check_cached_sanity(struct raminfo *info)
2849{
2850 int lane;
2851 int slot, rank;
2852 int channel;
2853
2854 if (!info->cached_training)
2855 return 0;
2856
2857 for (channel = 0; channel < NUM_CHANNELS; channel++)
2858 for (slot = 0; slot < NUM_SLOTS; slot++)
2859 for (rank = 0; rank < NUM_RANKS; rank++)
2860 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2861 u16 cached_value, estimation_value;
2862 cached_value =
2863 info->cached_training->
2864 lane_timings[1][channel][slot][rank]
2865 [lane];
2866 if (cached_value >= 0x18
2867 && cached_value <= 0x1E7) {
2868 estimation_value =
2869 info->training.
2870 lane_timings[1][channel]
2871 [slot][rank][lane];
2872 if (estimation_value <
2873 cached_value - 24)
2874 return 0;
2875 if (estimation_value >
2876 cached_value + 24)
2877 return 0;
2878 }
2879 }
2880 return 1;
2881}
2882
2883static int try_cached_training(struct raminfo *info)
2884{
2885 u8 saved_243[2];
2886 u8 tm;
2887
2888 int channel, slot, rank, lane;
2889 int flip = 1;
2890 int i, j;
2891
2892 if (!check_cached_sanity(info))
2893 return 0;
2894
2895 info->training.reg178_center = info->cached_training->reg178_center;
2896 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2897 info->training.reg178_largest = info->cached_training->reg178_largest;
2898 memcpy(&info->training.timing_bounds,
2899 &info->cached_training->timing_bounds,
2900 sizeof(info->training.timing_bounds));
2901 memcpy(&info->training.timing_offset,
2902 &info->cached_training->timing_offset,
2903 sizeof(info->training.timing_offset));
2904
2905 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002906 saved_243[0] = MCHBAR8(0x243);
2907 saved_243[1] = MCHBAR8(0x643);
2908 MCHBAR8(0x243) = saved_243[0] | 2;
2909 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002910 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002911 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002912 if (read_1d0(0x10b, 6) & 1)
2913 set_10b(info, 0);
2914 for (tm = 0; tm < 2; tm++) {
2915 int totalrank;
2916
2917 set_178(tm ? info->cached_training->reg178_largest : info->
2918 cached_training->reg178_smallest);
2919
2920 totalrank = 0;
2921 /* Check timing ranges. With i == 0 we check smallest one and with
2922 i == 1 the largest bound. With j == 0 we check that on the bound
2923 it still works whereas with j == 1 we check that just outside of
2924 bound we fail.
2925 */
2926 FOR_POPULATED_RANKS_BACKWARDS {
2927 for (i = 0; i < 2; i++) {
2928 for (lane = 0; lane < 8; lane++) {
2929 write_500(info, channel,
2930 info->cached_training->
2931 timing2_bounds[channel][slot]
2932 [rank][lane][i],
2933 get_timing_register_addr(lane,
2934 3,
2935 slot,
2936 rank),
2937 9, 1);
2938
2939 if (!i)
2940 write_500(info, channel,
2941 info->
2942 cached_training->
2943 timing2_offset
2944 [channel][slot][rank]
2945 [lane],
2946 get_timing_register_addr
2947 (lane, 2, slot, rank),
2948 9, 1);
2949 write_500(info, channel,
2950 i ? info->cached_training->
2951 timing_bounds[tm][channel]
2952 [slot][rank][lane].
2953 largest : info->
2954 cached_training->
2955 timing_bounds[tm][channel]
2956 [slot][rank][lane].smallest,
2957 get_timing_register_addr(lane,
2958 0,
2959 slot,
2960 rank),
2961 9, 1);
2962 write_500(info, channel,
2963 info->cached_training->
2964 timing_offset[channel][slot]
2965 [rank][lane] +
2966 (i ? info->cached_training->
2967 timing_bounds[tm][channel]
2968 [slot][rank][lane].
2969 largest : info->
2970 cached_training->
2971 timing_bounds[tm][channel]
2972 [slot][rank][lane].
2973 smallest) - 64,
2974 get_timing_register_addr(lane,
2975 1,
2976 slot,
2977 rank),
2978 9, 1);
2979 }
2980 for (j = 0; j < 2; j++) {
2981 u8 failmask;
2982 u8 expected_failmask;
2983 char reg1b3;
2984
2985 reg1b3 = (j == 1) + 4;
2986 reg1b3 =
2987 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2988 write_1d0(reg1b3, 0x1bb, 6, 1);
2989 write_1d0(reg1b3, 0x1b3, 6, 1);
2990 write_1d0(reg1b3, 0x1a3, 6, 1);
2991
2992 flip = !flip;
2993 write_testing(info, totalrank, flip);
2994 failmask =
2995 check_testing(info, totalrank,
2996 flip);
2997 expected_failmask =
2998 j == 0 ? 0x00 : 0xff;
2999 if (failmask != expected_failmask)
3000 goto fail;
3001 }
3002 }
3003 totalrank++;
3004 }
3005 }
3006
3007 set_178(info->cached_training->reg178_center);
3008 if (info->use_ecc)
3009 set_ecc(1);
3010 write_training_data(info);
3011 write_1d0(0, 322, 3, 1);
3012 info->training = *info->cached_training;
3013
3014 write_1d0(0, 0x1bb, 6, 1);
3015 write_1d0(0, 0x1b3, 6, 1);
3016 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003017 MCHBAR8(0x243) = saved_243[0];
3018 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003019
3020 return 1;
3021
3022fail:
3023 FOR_POPULATED_RANKS {
3024 write_500_timings_type(info, channel, slot, rank, 1);
3025 write_500_timings_type(info, channel, slot, rank, 2);
3026 write_500_timings_type(info, channel, slot, rank, 3);
3027 }
3028
3029 write_1d0(0, 0x1bb, 6, 1);
3030 write_1d0(0, 0x1b3, 6, 1);
3031 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003032 MCHBAR8(0x243) = saved_243[0];
3033 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003034
3035 return 0;
3036}
3037
3038static void do_ram_training(struct raminfo *info)
3039{
3040 u8 saved_243[2];
3041 int totalrank = 0;
3042 u8 reg_178;
3043 int niter;
3044
Matthias Gazzaridfa51252018-05-19 00:44:20 +02003045 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003046 int lane, rank, slot, channel;
3047 u8 reg178_center;
3048
3049 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003050 saved_243[0] = MCHBAR8(0x243);
3051 saved_243[1] = MCHBAR8(0x643);
3052 MCHBAR8(0x243) = saved_243[0] | 2;
3053 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003054 switch (info->clock_speed_index) {
3055 case 0:
3056 niter = 5;
3057 break;
3058 case 1:
3059 niter = 10;
3060 break;
3061 default:
3062 niter = 19;
3063 break;
3064 }
3065 set_ecc(0);
3066
3067 FOR_POPULATED_RANKS_BACKWARDS {
3068 int i;
3069
3070 write_500_timings_type(info, channel, slot, rank, 0);
3071
3072 write_testing(info, totalrank, 0);
3073 for (i = 0; i < niter; i++) {
3074 write_testing_type2(info, totalrank, 2, i, 0);
3075 write_testing_type2(info, totalrank, 3, i, 1);
3076 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003077 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003078 totalrank++;
3079 }
3080
3081 if (reg178_min[info->clock_speed_index] <
3082 reg178_max[info->clock_speed_index])
3083 memset(timings[reg178_min[info->clock_speed_index]], 0,
3084 sizeof(timings[0]) *
3085 (reg178_max[info->clock_speed_index] -
3086 reg178_min[info->clock_speed_index]));
3087 for (reg_178 = reg178_min[info->clock_speed_index];
3088 reg_178 < reg178_max[info->clock_speed_index];
3089 reg_178 += reg178_step[info->clock_speed_index]) {
3090 totalrank = 0;
3091 set_178(reg_178);
3092 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3093 for (slot = 0; slot < NUM_SLOTS; slot++)
3094 for (rank = 0; rank < NUM_RANKS; rank++) {
3095 memset(&timings[reg_178][channel][slot]
3096 [rank][0].smallest, 0, 16);
3097 if (info->
3098 populated_ranks[channel][slot]
3099 [rank]) {
3100 train_ram_at_178(info, channel,
3101 slot, rank,
3102 totalrank,
3103 reg_178, 1,
3104 niter,
3105 timings);
3106 totalrank++;
3107 }
3108 }
3109 }
3110
3111 reg178_center = choose_reg178(info, timings);
3112
3113 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3114 info->training.timing_bounds[0][channel][slot][rank][lane].
3115 smallest =
3116 timings[info->training.
3117 reg178_smallest][channel][slot][rank][lane].
3118 smallest;
3119 info->training.timing_bounds[0][channel][slot][rank][lane].
3120 largest =
3121 timings[info->training.
3122 reg178_smallest][channel][slot][rank][lane].largest;
3123 info->training.timing_bounds[1][channel][slot][rank][lane].
3124 smallest =
3125 timings[info->training.
3126 reg178_largest][channel][slot][rank][lane].smallest;
3127 info->training.timing_bounds[1][channel][slot][rank][lane].
3128 largest =
3129 timings[info->training.
3130 reg178_largest][channel][slot][rank][lane].largest;
3131 info->training.timing_offset[channel][slot][rank][lane] =
3132 info->training.lane_timings[1][channel][slot][rank][lane]
3133 -
3134 info->training.lane_timings[0][channel][slot][rank][lane] +
3135 64;
3136 }
3137
3138 if (info->silicon_revision == 1
3139 && (info->
3140 populated_ranks_mask[1] ^ (info->
3141 populated_ranks_mask[1] >> 2)) & 1) {
3142 int ranks_after_channel1;
3143
3144 totalrank = 0;
3145 for (reg_178 = reg178_center - 18;
3146 reg_178 <= reg178_center + 18; reg_178 += 18) {
3147 totalrank = 0;
3148 set_178(reg_178);
3149 for (slot = 0; slot < NUM_SLOTS; slot++)
3150 for (rank = 0; rank < NUM_RANKS; rank++) {
3151 if (info->
3152 populated_ranks[1][slot][rank]) {
3153 train_ram_at_178(info, 1, slot,
3154 rank,
3155 totalrank,
3156 reg_178, 0,
3157 niter,
3158 timings);
3159 totalrank++;
3160 }
3161 }
3162 }
3163 ranks_after_channel1 = totalrank;
3164
3165 for (reg_178 = reg178_center - 12;
3166 reg_178 <= reg178_center + 12; reg_178 += 12) {
3167 totalrank = ranks_after_channel1;
3168 set_178(reg_178);
3169 for (slot = 0; slot < NUM_SLOTS; slot++)
3170 for (rank = 0; rank < NUM_RANKS; rank++)
3171 if (info->
3172 populated_ranks[0][slot][rank]) {
3173 train_ram_at_178(info, 0, slot,
3174 rank,
3175 totalrank,
3176 reg_178, 0,
3177 niter,
3178 timings);
3179 totalrank++;
3180 }
3181
3182 }
3183 } else {
3184 for (reg_178 = reg178_center - 12;
3185 reg_178 <= reg178_center + 12; reg_178 += 12) {
3186 totalrank = 0;
3187 set_178(reg_178);
3188 FOR_POPULATED_RANKS_BACKWARDS {
3189 train_ram_at_178(info, channel, slot, rank,
3190 totalrank, reg_178, 0, niter,
3191 timings);
3192 totalrank++;
3193 }
3194 }
3195 }
3196
3197 set_178(reg178_center);
3198 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3199 u16 tm0;
3200
3201 tm0 =
3202 choose_training(info, channel, slot, rank, lane, timings,
3203 reg178_center);
3204 write_500(info, channel, tm0,
3205 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3206 write_500(info, channel,
3207 tm0 +
3208 info->training.
3209 lane_timings[1][channel][slot][rank][lane] -
3210 info->training.
3211 lane_timings[0][channel][slot][rank][lane],
3212 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3213 }
3214
3215 totalrank = 0;
3216 FOR_POPULATED_RANKS_BACKWARDS {
3217 try_timing_offsets(info, channel, slot, rank, totalrank);
3218 totalrank++;
3219 }
Felix Held04be2dd2018-07-29 04:53:22 +02003220 MCHBAR8(0x243) = saved_243[0];
3221 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003222 write_1d0(0, 0x142, 3, 1);
3223 info->training.reg178_center = reg178_center;
3224}
3225
3226static void ram_training(struct raminfo *info)
3227{
3228 u16 saved_fc4;
3229
Felix Held04be2dd2018-07-29 04:53:22 +02003230 saved_fc4 = MCHBAR16(0xfc4);
3231 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003232
3233 if (info->revision >= 8)
3234 read_4090(info);
3235
3236 if (!try_cached_training(info))
3237 do_ram_training(info);
3238 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3239 && info->clock_speed_index < 2)
3240 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003241 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003242}
3243
3244static unsigned gcd(unsigned a, unsigned b)
3245{
3246 unsigned t;
3247 if (a > b) {
3248 t = a;
3249 a = b;
3250 b = t;
3251 }
3252 /* invariant a < b. */
3253 while (a) {
3254 t = b % a;
3255 b = a;
3256 a = t;
3257 }
3258 return b;
3259}
3260
3261static inline int div_roundup(int a, int b)
3262{
Edward O'Callaghan7116ac82014-07-08 01:53:24 +10003263 return CEIL_DIV(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003264}
3265
3266static unsigned lcm(unsigned a, unsigned b)
3267{
3268 return (a * b) / gcd(a, b);
3269}
3270
3271struct stru1 {
3272 u8 freqs_reversed;
3273 u8 freq_diff_reduced;
3274 u8 freq_min_reduced;
3275 u8 divisor_f4_to_fmax;
3276 u8 divisor_f3_to_fmax;
3277 u8 freq4_to_max_remainder;
3278 u8 freq3_to_2_remainder;
3279 u8 freq3_to_2_remaindera;
3280 u8 freq4_to_2_remainder;
3281 int divisor_f3_to_f1, divisor_f4_to_f2;
3282 int common_time_unit_ps;
3283 int freq_max_reduced;
3284};
3285
3286static void
3287compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3288 int num_cycles_2, int num_cycles_1, int round_it,
3289 int add_freqs, struct stru1 *result)
3290{
3291 int g;
3292 int common_time_unit_ps;
3293 int freq1_reduced, freq2_reduced;
3294 int freq_min_reduced;
3295 int freq_max_reduced;
3296 int freq3, freq4;
3297
3298 g = gcd(freq1, freq2);
3299 freq1_reduced = freq1 / g;
3300 freq2_reduced = freq2 / g;
3301 freq_min_reduced = min(freq1_reduced, freq2_reduced);
3302 freq_max_reduced = max(freq1_reduced, freq2_reduced);
3303
3304 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3305 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3306 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3307 if (add_freqs) {
3308 freq3 += freq2_reduced;
3309 freq4 += freq1_reduced;
3310 }
3311
3312 if (round_it) {
3313 result->freq3_to_2_remainder = 0;
3314 result->freq3_to_2_remaindera = 0;
3315 result->freq4_to_max_remainder = 0;
3316 result->divisor_f4_to_f2 = 0;
3317 result->divisor_f3_to_f1 = 0;
3318 } else {
3319 if (freq2_reduced < freq1_reduced) {
3320 result->freq3_to_2_remainder =
3321 result->freq3_to_2_remaindera =
3322 freq3 % freq1_reduced - freq1_reduced + 1;
3323 result->freq4_to_max_remainder =
3324 -(freq4 % freq1_reduced);
3325 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3326 result->divisor_f4_to_f2 =
3327 (freq4 -
3328 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3329 result->freq4_to_2_remainder =
3330 -(char)((freq1_reduced - freq2_reduced) +
3331 ((u8) freq4 -
3332 (freq1_reduced -
3333 freq2_reduced)) % (u8) freq2_reduced);
3334 } else {
3335 if (freq2_reduced > freq1_reduced) {
3336 result->freq4_to_max_remainder =
3337 (freq4 % freq2_reduced) - freq2_reduced + 1;
3338 result->freq4_to_2_remainder =
3339 freq4 % freq_max_reduced -
3340 freq_max_reduced + 1;
3341 } else {
3342 result->freq4_to_max_remainder =
3343 -(freq4 % freq2_reduced);
3344 result->freq4_to_2_remainder =
3345 -(char)(freq4 % freq_max_reduced);
3346 }
3347 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3348 result->divisor_f3_to_f1 =
3349 (freq3 -
3350 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3351 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3352 result->freq3_to_2_remaindera =
3353 -(char)((freq_max_reduced - freq_min_reduced) +
3354 (freq3 -
3355 (freq_max_reduced -
3356 freq_min_reduced)) % freq1_reduced);
3357 }
3358 }
3359 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3360 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3361 if (round_it) {
3362 if (freq2_reduced > freq1_reduced) {
3363 if (freq3 % freq_max_reduced)
3364 result->divisor_f3_to_fmax++;
3365 }
3366 if (freq2_reduced < freq1_reduced) {
3367 if (freq4 % freq_max_reduced)
3368 result->divisor_f4_to_fmax++;
3369 }
3370 }
3371 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3372 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3373 result->freq_min_reduced = freq_min_reduced;
3374 result->common_time_unit_ps = common_time_unit_ps;
3375 result->freq_max_reduced = freq_max_reduced;
3376}
3377
3378static void
3379set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3380 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3381 int num_cycles_4, int reverse)
3382{
3383 struct stru1 vv;
3384 char multiplier;
3385
3386 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3387 0, 1, &vv);
3388
3389 multiplier =
3390 div_roundup(max
3391 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3392 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3393 div_roundup(num_cycles_1,
3394 vv.common_time_unit_ps) +
3395 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3396 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3397
3398 u32 y =
3399 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3400 vv.freq_max_reduced * multiplier)
3401 | (vv.
3402 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3403 multiplier) << 16) | ((u8) (vv.
3404 freq_min_reduced
3405 *
3406 multiplier)
3407 << 24);
3408 u32 x =
3409 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3410 divisor_f3_to_f1
3411 << 16)
3412 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3413 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003414 MCHBAR32(reg) = y;
3415 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003416 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003417 MCHBAR32(reg + 4) = y;
3418 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003419 }
3420}
3421
3422static void
3423set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3424 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3425 int num_cycles_4)
3426{
3427 struct stru1 ratios1;
3428 struct stru1 ratios2;
3429
3430 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3431 0, 1, &ratios2);
3432 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3433 0, 1, &ratios1);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003434 printk (BIOS_SPEW, "[%x] <= %x\n", reg,
3435 ratios1.freq4_to_max_remainder | (ratios2.
3436 freq4_to_max_remainder
3437 << 8)
3438 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3439 divisor_f4_to_fmax
3440 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003441 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3442 (ratios2.freq4_to_max_remainder << 8) |
3443 (ratios1.divisor_f4_to_fmax << 16) |
3444 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003445}
3446
3447static void
3448set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3449 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3450{
3451 struct stru1 ratios;
3452
3453 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3454 round_it, add_freqs, &ratios);
3455 switch (mode) {
3456 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003457 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3458 (ratios.freqs_reversed << 8);
3459 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3460 (ratios.freq4_to_max_remainder << 8) |
3461 (ratios.divisor_f3_to_fmax << 16) |
3462 (ratios.divisor_f4_to_fmax << 20) |
3463 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003464 break;
3465
3466 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003467 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3468 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003469 break;
3470
3471 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003472 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3473 (ratios.freq4_to_max_remainder << 8) |
3474 (ratios.divisor_f3_to_fmax << 16) |
3475 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003476 break;
3477
3478 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003479 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3480 (ratios.divisor_f4_to_fmax << 8) |
3481 (ratios.freqs_reversed << 12) |
3482 (ratios.freq_min_reduced << 16) |
3483 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003484 break;
3485 }
3486}
3487
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003488static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003489{
3490 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3491 0, 1);
3492 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3493 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3494 1);
3495 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3496 frequency_11(info), 1231, 1524, 0, 1);
3497 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3498 frequency_11(info) / 2, 1278, 2008, 0, 1);
3499 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3500 1167, 1539, 0, 1);
3501 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3502 frequency_11(info) / 2, 1403, 1318, 0, 1);
3503 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3504 1);
3505 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3506 1);
3507 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3508 1, 1);
3509 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3510 1);
3511 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3512 frequency_11(info) / 2, 4000, 0, 0, 0);
3513 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3514 frequency_11(info) / 2, 4000, 4000, 0, 0);
3515
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003516 if (s3resume) {
3517 printk (BIOS_SPEW, "[6dc] <= %x\n", info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003518 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003519 } else
3520 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3521 info->delay46_ps[0], 0,
3522 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003523 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3524 frequency_11(info), 2500, 0, 0, 0);
3525 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3526 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003527 if (s3resume) {
3528 printk (BIOS_SPEW, "[6e8] <= %x\n", info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003529 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003530 } else
3531 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3532 info->delay46_ps[1], 0,
3533 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003534 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3535 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3536 470, 0);
3537 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3538 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3539 454, 459, 0);
3540 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3541 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3542 2588, 0);
3543 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3544 2405, 0);
3545 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3546 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3547 480, 0);
3548 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003549 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3550 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003551}
3552
3553static u16 get_max_timing(struct raminfo *info, int channel)
3554{
3555 int slot, rank, lane;
3556 u16 ret = 0;
3557
Felix Held04be2dd2018-07-29 04:53:22 +02003558 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003559 return 384;
3560
3561 if (info->revision < 8)
3562 return 256;
3563
3564 for (slot = 0; slot < NUM_SLOTS; slot++)
3565 for (rank = 0; rank < NUM_RANKS; rank++)
3566 if (info->populated_ranks[channel][slot][rank])
3567 for (lane = 0; lane < 8 + info->use_ecc; lane++)
3568 ret = max(ret, read_500(info, channel,
3569 get_timing_register_addr
3570 (lane, 0, slot,
3571 rank), 9));
3572 return ret;
3573}
3574
3575static void set_274265(struct raminfo *info)
3576{
3577 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3578 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3579 int delay_e_over_cycle_ps;
3580 int cycletime_ps;
3581 int channel;
3582
3583 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003584 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003585 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3586 cycletime_ps =
3587 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3588 delay_d_ps =
3589 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3590 - info->some_delay_3_ps_rounded + 200;
3591 if (!
3592 ((info->silicon_revision == 0
3593 || info->silicon_revision == 1)
3594 && (info->revision >= 8)))
3595 delay_d_ps += halfcycle_ps(info) * 2;
3596 delay_d_ps +=
3597 halfcycle_ps(info) * (!info->revision_flag_1 +
3598 info->some_delay_2_halfcycles_ceil +
3599 2 * info->some_delay_1_cycle_floor +
3600 info->clock_speed_index +
3601 2 * info->cas_latency - 7 + 11);
3602 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3603
Felix Held04be2dd2018-07-29 04:53:22 +02003604 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3605 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3606 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003607 delay_d_ps += 650;
3608 delay_c_ps = delay_d_ps + 1800;
3609 if (delay_c_ps <= delay_a_ps)
3610 delay_e_ps = 0;
3611 else
3612 delay_e_ps =
3613 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3614 cycletime_ps);
3615
3616 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3617 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3618 delay_f_cycles =
3619 div_roundup(2500 - delay_e_over_cycle_ps,
3620 2 * halfcycle_ps(info));
3621 if (delay_f_cycles > delay_e_cycles) {
3622 info->delay46_ps[channel] = delay_e_ps;
3623 delay_e_cycles = 0;
3624 } else {
3625 info->delay46_ps[channel] =
3626 delay_e_over_cycle_ps +
3627 2 * halfcycle_ps(info) * delay_f_cycles;
3628 delay_e_cycles -= delay_f_cycles;
3629 }
3630
3631 if (info->delay46_ps[channel] < 2500) {
3632 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003633 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003634 }
3635 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3636 if (delay_b_ps <= delay_a_ps)
3637 delay_b_ps = 0;
3638 else
3639 delay_b_ps -= delay_a_ps;
3640 info->delay54_ps[channel] =
3641 cycletime_ps * div_roundup(delay_b_ps,
3642 cycletime_ps) -
3643 2 * halfcycle_ps(info) * delay_e_cycles;
3644 if (info->delay54_ps[channel] < 2500)
3645 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003646 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003647 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3648 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003649 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003650 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003651 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003652 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3653 4 * halfcycle_ps(info)) - 6;
3654 MCHBAR32((channel << 10) + 0x274) =
3655 info->training.reg274265[channel][1] |
3656 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003657 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003658 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3659 4 * halfcycle_ps(info)) + 1;
3660 MCHBAR16((channel << 10) + 0x265) =
3661 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003662 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003663 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003664 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003665 else
Felix Held04be2dd2018-07-29 04:53:22 +02003666 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003667}
3668
3669static void restore_274265(struct raminfo *info)
3670{
3671 int channel;
3672
3673 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3674 write_mchbar32((channel << 10) + 0x274,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003675 (info->cached_training->reg274265[channel][0] << 16)
3676 | info->cached_training->reg274265[channel][1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003677 write_mchbar16((channel << 10) + 0x265,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003678 info->cached_training->reg274265[channel][2] << 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003679 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003680 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003681 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003682 else
Felix Held04be2dd2018-07-29 04:53:22 +02003683 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003684}
3685
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003686static void dmi_setup(void)
3687{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003688 gav(read8(DEFAULT_DMIBAR + 0x254));
3689 write8(DEFAULT_DMIBAR + 0x254, 0x1);
3690 write16(DEFAULT_DMIBAR + 0x1b8, 0x18f2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003691 read_mchbar16(0x48);
Felix Held04be2dd2018-07-29 04:53:22 +02003692 MCHBAR16(0x48) = 0x2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003693
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003694 write32(DEFAULT_DMIBAR + 0xd68, read32(DEFAULT_DMIBAR + 0xd68) | 0x08000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003695
3696 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3697 DEFAULT_GPIOBASE | 0x38);
3698 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3699}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003700
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003701void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003702{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003703 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003704 u16 ggc;
3705 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003706
Felix Held04be2dd2018-07-29 04:53:22 +02003707 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003708 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3709 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003710 MCHBAR8(0x2ca8) = 0;
Vladimir Serbinenkoe1eef692014-02-19 22:08:51 +01003711 outb(0x6, 0xcf9);
Patrick Georgi546953c2014-11-29 10:38:17 +01003712 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003713 }
Felix Held29a9c072018-07-29 01:34:45 +02003714#if 0
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003715 if (!s3resume) {
3716 pre_raminit_3(x2ca8);
3717 }
Vladimir Serbinenkof62669c2014-01-09 10:59:38 +01003718 pre_raminit_4a(x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003719#endif
3720
3721 dmi_setup();
3722
Felix Held04be2dd2018-07-29 04:53:22 +02003723 MCHBAR16(0x1170) = 0xa880;
3724 MCHBAR8(0x11c1) = 0x1;
3725 MCHBAR16(0x1170) = 0xb880;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003726 read_mchbar8(0x1210);
Felix Held04be2dd2018-07-29 04:53:22 +02003727 MCHBAR8(0x1210) = 0x84;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003728
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003729 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3730 /* 0 for 32MB */
3731 gfxsize = 0;
3732 }
3733
3734 ggc = 0xb00 | ((gfxsize + 5) << 4);
3735
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003736 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003737
3738 u16 deven;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003739 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003740
3741 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003742 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003743 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003744 MCHBAR16_OR(0x2c30, 0x200);
3745 MCHBAR16(0x2c32) = 0x434;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003746 read_mchbar32(0x2c44);
Felix Held04be2dd2018-07-29 04:53:22 +02003747 MCHBAR32(0x2c44) = 0x1053687;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003748 pci_read_config8(GMA, 0x62); // = 0x2
3749 pci_write_config8(GMA, 0x62, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003750 read8(DEFAULT_RCBA + 0x2318);
3751 write8(DEFAULT_RCBA + 0x2318, 0x47);
3752 read8(DEFAULT_RCBA + 0x2320);
3753 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003754 }
3755
3756 read_mchbar32(0x30);
Felix Held04be2dd2018-07-29 04:53:22 +02003757 MCHBAR32(0x30) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003758
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003759 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003760 gav(read32(DEFAULT_RCBA + 0x3428));
3761 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003762}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003763
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003764void raminit(const int s3resume, const u8 *spd_addrmap)
3765{
3766 unsigned channel, slot, lane, rank;
3767 int i;
3768 struct raminfo info;
3769 u8 x2ca8;
3770 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003771 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003772
Felix Held04be2dd2018-07-29 04:53:22 +02003773 x2ca8 = MCHBAR8(0x2ca8);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003774 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003775
3776 memset(&info, 0x5a, sizeof(info));
3777
3778 info.last_500_command[0] = 0;
3779 info.last_500_command[1] = 0;
3780
3781 info.fsb_frequency = 135 * 2;
3782 info.board_lane_delay[0] = 0x14;
3783 info.board_lane_delay[1] = 0x07;
3784 info.board_lane_delay[2] = 0x07;
3785 info.board_lane_delay[3] = 0x08;
3786 info.board_lane_delay[4] = 0x56;
3787 info.board_lane_delay[5] = 0x04;
3788 info.board_lane_delay[6] = 0x04;
3789 info.board_lane_delay[7] = 0x05;
3790 info.board_lane_delay[8] = 0x10;
3791
3792 info.training.reg_178 = 0;
3793 info.training.reg_10b = 0;
3794
3795 info.heci_bar = 0;
3796 info.memory_reserved_for_heci_mb = 0;
3797
3798 /* before SPD */
3799 timestamp_add_now(101);
3800
Felix Held29a9c072018-07-29 01:34:45 +02003801 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003802 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003803
3804 collect_system_info(&info);
3805
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003806 /* Enable SMBUS. */
3807 enable_smbus();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003808
3809 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3810
3811 info.use_ecc = 1;
3812 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003813 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003814 int v;
3815 int try;
3816 int addr;
3817 const u8 useful_addresses[] = {
3818 DEVICE_TYPE,
3819 MODULE_TYPE,
3820 DENSITY,
3821 RANKS_AND_DQ,
3822 MEMORY_BUS_WIDTH,
3823 TIMEBASE_DIVIDEND,
3824 TIMEBASE_DIVISOR,
3825 CYCLETIME,
3826 CAS_LATENCIES_LSB,
3827 CAS_LATENCIES_MSB,
3828 CAS_LATENCY_TIME,
3829 0x11, 0x12, 0x13, 0x14, 0x15,
3830 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3831 0x1c, 0x1d,
3832 THERMAL_AND_REFRESH,
3833 0x20,
3834 REFERENCE_RAW_CARD_USED,
3835 RANK1_ADDRESS_MAPPING,
3836 0x75, 0x76, 0x77, 0x78,
3837 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3838 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3839 0x85, 0x86, 0x87, 0x88,
3840 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3841 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3842 0x95
3843 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003844 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003845 continue;
3846 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003847 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003848 DEVICE_TYPE);
3849 if (v >= 0)
3850 break;
3851 }
3852 if (v < 0)
3853 continue;
3854 for (addr = 0;
3855 addr <
3856 sizeof(useful_addresses) /
3857 sizeof(useful_addresses[0]); addr++)
3858 gav(info.
3859 spd[channel][0][useful_addresses
3860 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003861 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003862 useful_addresses
3863 [addr]));
3864 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3865 die("Only DDR3 is supported");
3866
3867 v = info.spd[channel][0][RANKS_AND_DQ];
3868 info.populated_ranks[channel][0][0] = 1;
3869 info.populated_ranks[channel][0][1] =
3870 ((v >> 3) & 7);
3871 if (((v >> 3) & 7) > 1)
3872 die("At most 2 ranks are supported");
3873 if ((v & 7) == 0 || (v & 7) > 2)
3874 die("Only x8 and x16 modules are supported");
3875 if ((info.
3876 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3877 && (info.
3878 spd[channel][slot][MODULE_TYPE] & 0xF)
3879 != 3)
3880 die("Registered memory is not supported");
3881 info.is_x16_module[channel][0] = (v & 7) - 1;
3882 info.density[channel][slot] =
3883 info.spd[channel][slot][DENSITY] & 0xF;
3884 if (!
3885 (info.
3886 spd[channel][slot][MEMORY_BUS_WIDTH] &
3887 0x18))
3888 info.use_ecc = 0;
3889 }
3890
3891 gav(0x55);
3892
3893 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3894 int v = 0;
3895 for (slot = 0; slot < NUM_SLOTS; slot++)
3896 for (rank = 0; rank < NUM_RANKS; rank++)
3897 v |= info.
3898 populated_ranks[channel][slot][rank]
3899 << (2 * slot + rank);
3900 info.populated_ranks_mask[channel] = v;
3901 }
3902
3903 gav(0x55);
3904
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003905 gav(pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003906 }
3907
3908 /* after SPD */
3909 timestamp_add_now(102);
3910
Felix Held04be2dd2018-07-29 04:53:22 +02003911 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003912
3913 collect_system_info(&info);
3914 calculate_timings(&info);
3915
Felix Held29a9c072018-07-29 01:34:45 +02003916#if 0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003917 pci_write_config8(NORTHBRIDGE, 0xdf, 0x82);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003918#endif
3919
3920 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003921 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003922 if (x2ca8 == 0 && (reg8 & 0x80)) {
3923 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3924 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3925 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3926 */
3927
3928 /* Clear bit7. */
3929
3930 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3931 (reg8 & ~(1 << 7)));
3932
3933 printk(BIOS_INFO,
3934 "Interrupted RAM init, reset required.\n");
3935 outb(0x6, 0xcf9);
Patrick Georgi546953c2014-11-29 10:38:17 +01003936 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003937 }
3938 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003939
3940 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003941 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3942 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003943
3944 compute_derived_timings(&info);
3945
3946 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003947 gav(MCHBAR8(0x164));
3948 MCHBAR8(0x164) = 0x26;
3949 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003950 }
3951
Felix Held04be2dd2018-07-29 04:53:22 +02003952 MCHBAR32_OR(0x18b4, 0x210000);
3953 MCHBAR32_OR(0x1890, 0x2000000);
3954 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003955
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003956 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x50)); // !!!!
3957 pci_write_config8(PCI_DEV(0xff, 2, 1), 0x54, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003958
Felix Held04be2dd2018-07-29 04:53:22 +02003959 gav(MCHBAR16(0x2c10));
3960 MCHBAR16(0x2c10) = 0x412;
3961 gav(MCHBAR16(0x2c10));
3962 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003963
Felix Held04be2dd2018-07-29 04:53:22 +02003964 gav(MCHBAR8(0x2ca8)); // !!!!
3965 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003966
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003967 pci_read_config32(PCI_DEV(0xff, 2, 1), 0x6c); // !!!!
3968 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x6c, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003969 gav(MCHBAR32(0x1c04)); // !!!!
3970 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003971
3972 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003973 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003974 }
3975
Felix Held04be2dd2018-07-29 04:53:22 +02003976 MCHBAR32(0x18d8) = 0x120000;
3977 MCHBAR32(0x18dc) = 0x30a484a;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003978 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x0);
3979 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003980 MCHBAR32(0x18d8) = 0x40000;
3981 MCHBAR32(0x18dc) = 0xb000000;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003982 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x60000);
3983 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003984 MCHBAR32(0x18d8) = 0x180000;
3985 MCHBAR32(0x18dc) = 0xc0000142;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003986 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x20000);
3987 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003988 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003989
Felix Held04be2dd2018-07-29 04:53:22 +02003990 gav(MCHBAR32(0x18dc)); // !!!!
3991 MCHBAR32(0x18dc) = 0x3;
3992 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003993
3994 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003995 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003996 }
3997
Felix Held04be2dd2018-07-29 04:53:22 +02003998 MCHBAR32(0x188c) = 0x20bc09;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003999 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xd0, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02004000 MCHBAR32(0x1a10) = 0x4200010e;
4001 MCHBAR32_OR(0x18b8, 0x200);
4002 gav(MCHBAR32(0x1918)); // !!!!
4003 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004004
Felix Held04be2dd2018-07-29 04:53:22 +02004005 gav(MCHBAR32(0x18b8)); // !!!!
4006 MCHBAR32(0x18b8) = 0xe00;
4007 gav(MCHBAR32(0x182c)); // !!!!
4008 MCHBAR32(0x182c) = 0x10202;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004009 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x94)); // !!!!
4010 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x94, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02004011 MCHBAR32_AND(0x1a1c, 0x8fffffff);
4012 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004013
Felix Held04be2dd2018-07-29 04:53:22 +02004014 MCHBAR32_AND(0x18b4, 0xffff7fff);
4015 gav(MCHBAR32(0x1a68)); // !!!!
4016 MCHBAR32(0x1a68) = 0x343800;
4017 gav(MCHBAR32(0x1e68)); // !!!!
4018 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004019
4020 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004021 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004022 }
4023
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004024 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x048); // !!!!
4025 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x048, 0x140000);
4026 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
4027 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x058, 0x64555);
4028 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
4029 pci_read_config32(PCI_DEV (0xff, 0, 0), 0xd0); // !!!!
4030 pci_write_config32(PCI_DEV (0xff, 0, 0), 0xd0, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02004031 gav(MCHBAR32(0x1af0)); // !!!!
4032 gav(MCHBAR32(0x1af0)); // !!!!
4033 MCHBAR32(0x1af0) = 0x1f020003;
4034 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004035
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10004036 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004037 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004038 }
4039
Felix Held04be2dd2018-07-29 04:53:22 +02004040 gav(MCHBAR32(0x1890)); // !!!!
4041 MCHBAR32(0x1890) = 0x80102;
4042 gav(MCHBAR32(0x18b4)); // !!!!
4043 MCHBAR32(0x18b4) = 0x216000;
4044 MCHBAR32(0x18a4) = 0x22222222;
4045 MCHBAR32(0x18a8) = 0x22222222;
4046 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004047
4048 udelay(1000);
4049
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004050 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004051
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004052 if (x2ca8 == 0) {
4053 int j;
4054 if (s3resume && info.cached_training) {
4055 restore_274265(&info);
4056 printk(BIOS_DEBUG, "reg2ca9_bit0 = %x\n",
4057 info.cached_training->reg2ca9_bit0);
4058 for (i = 0; i < 2; i++)
4059 for (j = 0; j < 3; j++)
4060 printk(BIOS_DEBUG, "reg274265[%d][%d] = %x\n",
4061 i, j, info.cached_training->reg274265[i][j]);
4062 } else {
4063 set_274265(&info);
4064 printk(BIOS_DEBUG, "reg2ca9_bit0 = %x\n",
4065 info.training.reg2ca9_bit0);
4066 for (i = 0; i < 2; i++)
4067 for (j = 0; j < 3; j++)
4068 printk(BIOS_DEBUG, "reg274265[%d][%d] = %x\n",
4069 i, j, info.training.reg274265[i][j]);
4070 }
4071
4072 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004073
4074 if (!(deven & 8)) {
4075 read_mchbar32(0x2cb0);
Felix Held04be2dd2018-07-29 04:53:22 +02004076 MCHBAR32(0x2cb0) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004077 }
4078
4079 udelay(1000);
4080
4081 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02004082 MCHBAR32_OR(0xff8, 0x1800);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004083 read_mchbar32(0x2cb0);
Felix Held04be2dd2018-07-29 04:53:22 +02004084 MCHBAR32(0x2cb0) = 0x00;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004085 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4086 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4087 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004088
4089 read_mchbar8(0x1150);
4090 read_mchbar8(0x1151);
4091 read_mchbar8(0x1022);
4092 read_mchbar8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004093 MCHBAR32(0x1300) = 0x60606060;
4094 MCHBAR32(0x1304) = 0x60606060;
4095 MCHBAR32(0x1308) = 0x78797a7b;
4096 MCHBAR32(0x130c) = 0x7c7d7e7f;
4097 MCHBAR32(0x1310) = 0x60606060;
4098 MCHBAR32(0x1314) = 0x60606060;
4099 MCHBAR32(0x1318) = 0x60606060;
4100 MCHBAR32(0x131c) = 0x60606060;
4101 MCHBAR32(0x1320) = 0x50515253;
4102 MCHBAR32(0x1324) = 0x54555657;
4103 MCHBAR32(0x1328) = 0x58595a5b;
4104 MCHBAR32(0x132c) = 0x5c5d5e5f;
4105 MCHBAR32(0x1330) = 0x40414243;
4106 MCHBAR32(0x1334) = 0x44454647;
4107 MCHBAR32(0x1338) = 0x48494a4b;
4108 MCHBAR32(0x133c) = 0x4c4d4e4f;
4109 MCHBAR32(0x1340) = 0x30313233;
4110 MCHBAR32(0x1344) = 0x34353637;
4111 MCHBAR32(0x1348) = 0x38393a3b;
4112 MCHBAR32(0x134c) = 0x3c3d3e3f;
4113 MCHBAR32(0x1350) = 0x20212223;
4114 MCHBAR32(0x1354) = 0x24252627;
4115 MCHBAR32(0x1358) = 0x28292a2b;
4116 MCHBAR32(0x135c) = 0x2c2d2e2f;
4117 MCHBAR32(0x1360) = 0x10111213;
4118 MCHBAR32(0x1364) = 0x14151617;
4119 MCHBAR32(0x1368) = 0x18191a1b;
4120 MCHBAR32(0x136c) = 0x1c1d1e1f;
4121 MCHBAR32(0x1370) = 0x10203;
4122 MCHBAR32(0x1374) = 0x4050607;
4123 MCHBAR32(0x1378) = 0x8090a0b;
4124 MCHBAR32(0x137c) = 0xc0d0e0f;
4125 MCHBAR8(0x11cc) = 0x4e;
4126 MCHBAR32(0x1110) = 0x73970404;
4127 MCHBAR32(0x1114) = 0x72960404;
4128 MCHBAR32(0x1118) = 0x6f950404;
4129 MCHBAR32(0x111c) = 0x6d940404;
4130 MCHBAR32(0x1120) = 0x6a930404;
4131 MCHBAR32(0x1124) = 0x68a41404;
4132 MCHBAR32(0x1128) = 0x66a21404;
4133 MCHBAR32(0x112c) = 0x63a01404;
4134 MCHBAR32(0x1130) = 0x609e1404;
4135 MCHBAR32(0x1134) = 0x5f9c1404;
4136 MCHBAR32(0x1138) = 0x5c961404;
4137 MCHBAR32(0x113c) = 0x58a02404;
4138 MCHBAR32(0x1140) = 0x54942404;
4139 MCHBAR32(0x1190) = 0x900080a;
4140 MCHBAR16(0x11c0) = 0xc40b;
4141 MCHBAR16(0x11c2) = 0x303;
4142 MCHBAR16(0x11c4) = 0x301;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004143 read_mchbar32(0x1190);
Felix Held04be2dd2018-07-29 04:53:22 +02004144 MCHBAR32(0x1190) = 0x8900080a;
4145 MCHBAR32(0x11b8) = 0x70c3000;
4146 MCHBAR8(0x11ec) = 0xa;
4147 MCHBAR16(0x1100) = 0x800;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004148 read_mchbar32(0x11bc);
Felix Held04be2dd2018-07-29 04:53:22 +02004149 MCHBAR32(0x11bc) = 0x1e84800;
4150 MCHBAR16(0x11ca) = 0xfa;
4151 MCHBAR32(0x11e4) = 0x4e20;
4152 MCHBAR8(0x11bc) = 0xf;
4153 MCHBAR16(0x11da) = 0x19;
4154 MCHBAR16(0x11ba) = 0x470c;
4155 MCHBAR32(0x1680) = 0xe6ffe4ff;
4156 MCHBAR32(0x1684) = 0xdeffdaff;
4157 MCHBAR32(0x1688) = 0xd4ffd0ff;
4158 MCHBAR32(0x168c) = 0xccffc6ff;
4159 MCHBAR32(0x1690) = 0xc0ffbeff;
4160 MCHBAR32(0x1694) = 0xb8ffb0ff;
4161 MCHBAR32(0x1698) = 0xa8ff0000;
4162 MCHBAR32(0x169c) = 0xc00;
4163 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004164 }
4165
Felix Held04be2dd2018-07-29 04:53:22 +02004166 MCHBAR32(0x124c) = 0x15040d00;
4167 MCHBAR32(0x1250) = 0x7f0000;
4168 MCHBAR32(0x1254) = 0x1e220004;
4169 MCHBAR32(0x1258) = 0x4000004;
4170 MCHBAR32(0x1278) = 0x0;
4171 MCHBAR32(0x125c) = 0x0;
4172 MCHBAR32(0x1260) = 0x0;
4173 MCHBAR32(0x1264) = 0x0;
4174 MCHBAR32(0x1268) = 0x0;
4175 MCHBAR32(0x126c) = 0x0;
4176 MCHBAR32(0x1270) = 0x0;
4177 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004178 }
4179
4180 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004181 MCHBAR16(0x1214) = 0x320;
4182 MCHBAR32(0x1600) = 0x40000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004183 read_mchbar32(0x11f4);
Felix Held04be2dd2018-07-29 04:53:22 +02004184 MCHBAR32(0x11f4) = 0x10000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004185 read_mchbar16(0x1230);
Felix Held04be2dd2018-07-29 04:53:22 +02004186 MCHBAR16(0x1230) = 0x8000;
4187 MCHBAR32(0x1400) = 0x13040020;
4188 MCHBAR32(0x1404) = 0xe090120;
4189 MCHBAR32(0x1408) = 0x5120220;
4190 MCHBAR32(0x140c) = 0x5120330;
4191 MCHBAR32(0x1410) = 0xe090220;
4192 MCHBAR32(0x1414) = 0x1010001;
4193 MCHBAR32(0x1418) = 0x1110000;
4194 MCHBAR32(0x141c) = 0x9020020;
4195 MCHBAR32(0x1420) = 0xd090220;
4196 MCHBAR32(0x1424) = 0x2090220;
4197 MCHBAR32(0x1428) = 0x2090330;
4198 MCHBAR32(0x142c) = 0xd090220;
4199 MCHBAR32(0x1430) = 0x1010001;
4200 MCHBAR32(0x1434) = 0x1110000;
4201 MCHBAR32(0x1438) = 0x11040020;
4202 MCHBAR32(0x143c) = 0x4030220;
4203 MCHBAR32(0x1440) = 0x1060220;
4204 MCHBAR32(0x1444) = 0x1060330;
4205 MCHBAR32(0x1448) = 0x4030220;
4206 MCHBAR32(0x144c) = 0x1010001;
4207 MCHBAR32(0x1450) = 0x1110000;
4208 MCHBAR32(0x1454) = 0x4010020;
4209 MCHBAR32(0x1458) = 0xb090220;
4210 MCHBAR32(0x145c) = 0x1090220;
4211 MCHBAR32(0x1460) = 0x1090330;
4212 MCHBAR32(0x1464) = 0xb090220;
4213 MCHBAR32(0x1468) = 0x1010001;
4214 MCHBAR32(0x146c) = 0x1110000;
4215 MCHBAR32(0x1470) = 0xf040020;
4216 MCHBAR32(0x1474) = 0xa090220;
4217 MCHBAR32(0x1478) = 0x1120220;
4218 MCHBAR32(0x147c) = 0x1120330;
4219 MCHBAR32(0x1480) = 0xa090220;
4220 MCHBAR32(0x1484) = 0x1010001;
4221 MCHBAR32(0x1488) = 0x1110000;
4222 MCHBAR32(0x148c) = 0x7020020;
4223 MCHBAR32(0x1490) = 0x1010220;
4224 MCHBAR32(0x1494) = 0x10210;
4225 MCHBAR32(0x1498) = 0x10320;
4226 MCHBAR32(0x149c) = 0x1010220;
4227 MCHBAR32(0x14a0) = 0x1010001;
4228 MCHBAR32(0x14a4) = 0x1110000;
4229 MCHBAR32(0x14a8) = 0xd040020;
4230 MCHBAR32(0x14ac) = 0x8090220;
4231 MCHBAR32(0x14b0) = 0x1111310;
4232 MCHBAR32(0x14b4) = 0x1111420;
4233 MCHBAR32(0x14b8) = 0x8090220;
4234 MCHBAR32(0x14bc) = 0x1010001;
4235 MCHBAR32(0x14c0) = 0x1110000;
4236 MCHBAR32(0x14c4) = 0x3010020;
4237 MCHBAR32(0x14c8) = 0x7090220;
4238 MCHBAR32(0x14cc) = 0x1081310;
4239 MCHBAR32(0x14d0) = 0x1081420;
4240 MCHBAR32(0x14d4) = 0x7090220;
4241 MCHBAR32(0x14d8) = 0x1010001;
4242 MCHBAR32(0x14dc) = 0x1110000;
4243 MCHBAR32(0x14e0) = 0xb040020;
4244 MCHBAR32(0x14e4) = 0x2030220;
4245 MCHBAR32(0x14e8) = 0x1051310;
4246 MCHBAR32(0x14ec) = 0x1051420;
4247 MCHBAR32(0x14f0) = 0x2030220;
4248 MCHBAR32(0x14f4) = 0x1010001;
4249 MCHBAR32(0x14f8) = 0x1110000;
4250 MCHBAR32(0x14fc) = 0x5020020;
4251 MCHBAR32(0x1500) = 0x5090220;
4252 MCHBAR32(0x1504) = 0x2071310;
4253 MCHBAR32(0x1508) = 0x2071420;
4254 MCHBAR32(0x150c) = 0x5090220;
4255 MCHBAR32(0x1510) = 0x1010001;
4256 MCHBAR32(0x1514) = 0x1110000;
4257 MCHBAR32(0x1518) = 0x7040120;
4258 MCHBAR32(0x151c) = 0x2090220;
4259 MCHBAR32(0x1520) = 0x70b1210;
4260 MCHBAR32(0x1524) = 0x70b1310;
4261 MCHBAR32(0x1528) = 0x2090220;
4262 MCHBAR32(0x152c) = 0x1010001;
4263 MCHBAR32(0x1530) = 0x1110000;
4264 MCHBAR32(0x1534) = 0x1010110;
4265 MCHBAR32(0x1538) = 0x1081310;
4266 MCHBAR32(0x153c) = 0x5041200;
4267 MCHBAR32(0x1540) = 0x5041310;
4268 MCHBAR32(0x1544) = 0x1081310;
4269 MCHBAR32(0x1548) = 0x1010001;
4270 MCHBAR32(0x154c) = 0x1110000;
4271 MCHBAR32(0x1550) = 0x1040120;
4272 MCHBAR32(0x1554) = 0x4051210;
4273 MCHBAR32(0x1558) = 0xd051200;
4274 MCHBAR32(0x155c) = 0xd051200;
4275 MCHBAR32(0x1560) = 0x4051210;
4276 MCHBAR32(0x1564) = 0x1010001;
4277 MCHBAR32(0x1568) = 0x1110000;
4278 MCHBAR16(0x1222) = 0x220a;
4279 MCHBAR16(0x123c) = 0x1fc0;
4280 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004281 }
4282
4283 read_mchbar32(0x2c80); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004284 MCHBAR32(0x2c80) = 0x1053688;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004285 read_mchbar32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004286 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004287
4288 read_mchbar8(0x2ca8);
4289
4290 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004291 MCHBAR8_AND(0x2ca8, ~3);
4292 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
4293 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004294 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004295 }
4296
Felix Held04be2dd2018-07-29 04:53:22 +02004297 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004298 read_mchbar32(0x2c80); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004299 MCHBAR32(0x2c80) = 0x53688;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004300 pci_write_config32(PCI_DEV (0xff, 0, 0), 0x60, 0x20220);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004301 read_mchbar16(0x2c20); // !!!!
4302 read_mchbar16(0x2c10); // !!!!
4303 read_mchbar16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004304 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004305 udelay(1000);
4306 write_1d0(0, 0x33d, 0, 0);
4307 write_500(&info, 0, 0, 0xb61, 0, 0);
4308 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004309 MCHBAR32(0x1a30) = 0x0;
4310 MCHBAR32(0x1a34) = 0x0;
4311 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4312 (info.populated_ranks[0][0][0] * 0xa0);
4313 MCHBAR16(0x616) = 0x26a;
4314 MCHBAR32(0x134) = 0x856000;
4315 MCHBAR32(0x160) = 0x5ffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004316 read_mchbar32(0x114); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004317 MCHBAR32(0x114) = 0xc2024440;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004318 read_mchbar32(0x118); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004319 MCHBAR32(0x118) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004320 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004321 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4322 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004323 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004324 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004325 write_mchbar16(0x360 + (channel << 10), 0x909);
4326 write_mchbar16(0x3a4 + (channel << 10), 0x101);
Felix Held04be2dd2018-07-29 04:53:22 +02004327 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4328 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4329 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4330 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4331 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4332 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4333 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4334 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4335 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4336 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004337 }
4338
4339 write_1d0(0x4, 0x151, 4, 1);
4340 write_1d0(0, 0x142, 3, 1);
4341 rdmsr(0x1ac); // !!!!
4342 write_500(&info, 1, 1, 0x6b3, 4, 1);
4343 write_500(&info, 1, 1, 0x6cf, 4, 1);
4344
4345 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4346
4347 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4348 populated_ranks[0]
4349 [0][0]) << 0),
4350 0x1d1, 3, 1);
4351 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004352 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4353 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004354 }
4355
4356 set_334(0);
4357
4358 program_base_timings(&info);
4359
Felix Held04be2dd2018-07-29 04:53:22 +02004360 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004361
4362 write_1d0(0x2, 0x1d5, 2, 1);
4363 write_1d0(0x20, 0x166, 7, 1);
4364 write_1d0(0x0, 0xeb, 3, 1);
4365 write_1d0(0x0, 0xf3, 6, 1);
4366
4367 for (channel = 0; channel < NUM_CHANNELS; channel++)
4368 for (lane = 0; lane < 9; lane++) {
4369 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4370 u8 a;
4371 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4372 write_500(&info, channel, a, addr, 6, 1);
4373 }
4374
4375 udelay(1000);
4376
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004377 if (s3resume) {
4378 if (info.cached_training == NULL) {
4379 u32 reg32;
4380 printk(BIOS_ERR,
4381 "Couldn't find training data. Rebooting\n");
4382 reg32 = inl(DEFAULT_PMBASE + 0x04);
4383 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4384 outb(0xe, 0xcf9);
Patrick Georgi546953c2014-11-29 10:38:17 +01004385 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004386 }
4387 int tm;
4388 info.training = *info.cached_training;
4389 for (tm = 0; tm < 4; tm++)
4390 for (channel = 0; channel < NUM_CHANNELS; channel++)
4391 for (slot = 0; slot < NUM_SLOTS; slot++)
4392 for (rank = 0; rank < NUM_RANKS; rank++)
4393 for (lane = 0; lane < 9; lane++)
4394 write_500(&info,
4395 channel,
4396 info.training.
4397 lane_timings
4398 [tm][channel]
4399 [slot][rank]
4400 [lane],
4401 get_timing_register_addr
4402 (lane, tm,
4403 slot, rank),
4404 9, 0);
4405 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4406 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4407 }
4408
4409 read_mchbar32(0x1f4); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004410 MCHBAR32(0x1f4) = 0x20000;
4411 MCHBAR32(0x1f0) = 0x1d000200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004412 read_mchbar8(0x1f0); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004413 MCHBAR8(0x1f0) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004414 read_mchbar8(0x1f0); // !!!!
4415
4416 program_board_delay(&info);
4417
Felix Held04be2dd2018-07-29 04:53:22 +02004418 MCHBAR8(0x5ff) = 0x0;
4419 MCHBAR8(0x5ff) = 0x80;
4420 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004421
Felix Held04be2dd2018-07-29 04:53:22 +02004422 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
4423 while (read_mchbar32(0x130) & 1)
4424 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004425 gav(read_1d0(0x14b, 7)); // = 0x81023100
4426 write_1d0(0x30, 0x14b, 7, 1);
4427 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4428 write_1d0(7, 0xd6, 6, 1);
4429 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4430 write_1d0(7, 0x328, 6, 1);
4431
4432 for (channel = 0; channel < NUM_CHANNELS; channel++)
4433 set_4cf(&info, channel,
4434 info.populated_ranks[channel][0][0] ? 8 : 0);
4435
4436 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4437 write_1d0(2, 0x116, 4, 1);
4438 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4439 write_1d0(0, 0xae, 6, 1);
4440 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4441 write_1d0(0, 0x300, 6, 1);
4442 read_mchbar16(0x356); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004443 MCHBAR16(0x356) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004444 read_mchbar16(0x756); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004445 MCHBAR16(0x756) = 0x1040;
4446 MCHBAR32_AND(0x140, ~0x07000000);
4447 MCHBAR32_AND(0x138, ~0x07000000);
4448 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004449 /* Wait until REG130b0 is 1. */
4450 while (read_mchbar32(0x130) & 1)
4451 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004452
4453 {
4454 u32 t;
4455 u8 val_a1;
4456 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4457 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4458 rmw_1d0(0x320, 0x07,
4459 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4460 rmw_1d0(0x14b, 0x78,
4461 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4462 4), 7,
4463 1);
4464 rmw_1d0(0xce, 0x38,
4465 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4466 4), 6,
4467 1);
4468 }
4469
4470 for (channel = 0; channel < NUM_CHANNELS; channel++)
4471 set_4cf(&info, channel,
4472 info.populated_ranks[channel][0][0] ? 9 : 1);
4473
4474 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
4475 read_mchbar32(0x144); // !!!!
4476 write_1d0(2, 0xae, 6, 1);
4477 write_1d0(2, 0x300, 6, 1);
4478 write_1d0(2, 0x121, 3, 1);
4479 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4480 write_1d0(4, 0xd6, 6, 1);
4481 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4482 write_1d0(4, 0x328, 6, 1);
4483
4484 for (channel = 0; channel < NUM_CHANNELS; channel++)
4485 set_4cf(&info, channel,
4486 info.populated_ranks[channel][0][0] ? 9 : 0);
4487
Felix Held04be2dd2018-07-29 04:53:22 +02004488 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4489 (info.populated_ranks[0][0][0] << 29);
4490 while (read_mchbar8(0x130) & 1) // !!!!
4491 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004492 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4493 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4494 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4495 write_1d0(0, 0x21c, 6, 1);
4496 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4497 write_1d0(0x35, 0x14b, 7, 1);
4498
4499 for (channel = 0; channel < NUM_CHANNELS; channel++)
4500 set_4cf(&info, channel,
4501 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4502
4503 set_334(1);
4504
Felix Held04be2dd2018-07-29 04:53:22 +02004505 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004506
4507 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4508 write_500(&info, channel,
4509 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4510 1);
4511 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4512 }
Felix Held04be2dd2018-07-29 04:53:22 +02004513 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4514 MCHBAR16(0x6c0) = 0x14a0;
4515 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4516 MCHBAR16(0x232) = 0x8;
4517 /* 0x40004 or 0 depending on ? */
4518 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4519 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4520 MCHBAR32(0x128) = 0x2150d05;
4521 MCHBAR8(0x12c) = 0x1f;
4522 MCHBAR8(0x12d) = 0x56;
4523 MCHBAR8(0x12e) = 0x31;
4524 MCHBAR8(0x12f) = 0x0;
4525 MCHBAR8(0x271) = 0x2;
4526 MCHBAR8(0x671) = 0x2;
4527 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004528 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004529 MCHBAR32(0x294 + (channel << 10)) =
4530 (info.populated_ranks_mask[channel] & 3) << 16;
4531 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4532 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004533 for (channel = 0; channel < NUM_CHANNELS; channel++)
4534 write_mchbar32(0x260 + (channel << 10),
4535 (read_mchbar32(0x260 + (channel << 10)) &
4536 ~0xf00000) | 0x8000000 | ((info.
4537 populated_ranks_mask
4538 [channel] & 3) <<
4539 20));
4540
4541 if (!s3resume)
4542 jedec_init(&info);
4543
4544 int totalrank = 0;
4545 for (channel = 0; channel < NUM_CHANNELS; channel++)
4546 for (slot = 0; slot < NUM_SLOTS; slot++)
4547 for (rank = 0; rank < NUM_RANKS; rank++)
4548 if (info.populated_ranks[channel][slot][rank]) {
4549 jedec_read(&info, channel, slot, rank,
4550 totalrank, 0xa, 0x400);
4551 totalrank++;
4552 }
4553
Felix Held04be2dd2018-07-29 04:53:22 +02004554 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004555
4556 read_mchbar8(0x271); // 2 // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004557 MCHBAR8(0x271) = 0xe;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004558 read_mchbar8(0x671); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004559 MCHBAR8(0x671) = 0xe;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004560
4561 if (!s3resume) {
4562 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004563 MCHBAR32(0x294 + (channel << 10)) =
4564 (info.populated_ranks_mask[channel] & 3) << 16;
4565 MCHBAR16(0x298 + (channel << 10)) =
4566 info.populated_ranks[channel][0][0] |
4567 (info.populated_ranks[channel][0][1] << 5);
4568 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004569 }
4570 read_mchbar32(0x2c0); /// !!!
Felix Held04be2dd2018-07-29 04:53:22 +02004571 MCHBAR32(0x2c0) = 0x6009cc00;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004572
4573 {
4574 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004575 a = MCHBAR8(0x243);
4576 b = MCHBAR8(0x643);
4577 MCHBAR8(0x243) = a | 2;
4578 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004579 }
4580
4581 write_1d0(7, 0x19b, 3, 1);
4582 write_1d0(7, 0x1c0, 3, 1);
4583 write_1d0(4, 0x1c6, 4, 1);
4584 write_1d0(4, 0x1cc, 4, 1);
4585 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4586 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004587 MCHBAR32(0x584) = 0xfffff;
4588 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004589
4590 for (channel = 0; channel < NUM_CHANNELS; channel++)
4591 for (slot = 0; slot < NUM_SLOTS; slot++)
4592 for (rank = 0; rank < NUM_RANKS; rank++)
4593 if (info.
4594 populated_ranks[channel][slot]
4595 [rank])
4596 config_rank(&info, s3resume,
4597 channel, slot,
4598 rank);
4599
Felix Held04be2dd2018-07-29 04:53:22 +02004600 MCHBAR8(0x243) = 0x1;
4601 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004602 }
4603
4604 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004605 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004606 write_26c(0, 0x820);
4607 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004608 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004609 /* end */
4610
4611 if (s3resume) {
4612 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004613 MCHBAR32(0x294 + (channel << 10)) =
4614 (info.populated_ranks_mask[channel] & 3) << 16;
4615 MCHBAR16(0x298 + (channel << 10)) =
4616 info.populated_ranks[channel][0][0] |
4617 (info.populated_ranks[channel][0][1] << 5);
4618 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004619 }
4620 read_mchbar32(0x2c0); /// !!!
Felix Held04be2dd2018-07-29 04:53:22 +02004621 MCHBAR32(0x2c0) = 0x6009cc00;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004622 }
4623
Felix Held04be2dd2018-07-29 04:53:22 +02004624 MCHBAR32_AND(0xfa4, ~0x01000002);
4625 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004626
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004627 /* Before training. */
4628 timestamp_add_now(103);
4629
4630 if (!s3resume)
4631 ram_training(&info);
4632
4633 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004634 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004635
4636 dump_timings(&info);
4637
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004638 program_modules_memory_map(&info, 0);
4639 program_total_memory_map(&info);
4640
4641 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004642 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004643 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004644 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004645 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004646 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004647 else
Felix Held04be2dd2018-07-29 04:53:22 +02004648 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004649
Felix Held04be2dd2018-07-29 04:53:22 +02004650 MCHBAR32_AND(0xfac, ~0x80000000);
4651 MCHBAR32(0xfb4) = 0x4800;
4652 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4653 MCHBAR32(0xe94) = 0x7ffff;
4654 MCHBAR32(0xfc0) = 0x80002040;
4655 MCHBAR32(0xfc4) = 0x701246;
4656 MCHBAR8_AND(0xfc8, ~0x70);
4657 MCHBAR32_OR(0xe5c, 0x1000000);
4658 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4659 MCHBAR32(0x50) = 0x700b0;
4660 MCHBAR32(0x3c) = 0x10;
4661 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4662 MCHBAR8_OR(0xff4, 0x2);
4663 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004664
Felix Held29a9c072018-07-29 01:34:45 +02004665#if 1
Felix Held04be2dd2018-07-29 04:53:22 +02004666 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4667 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4668 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004669
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004670 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4671 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4672 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004673
4674#else
4675 {
4676 u32 eax;
Felix Held04be2dd2018-07-29 04:53:22 +02004677 // = 0xe911714b
4678 eax = read32p(0xffc + (MCHBAR32(0xd00) & ~1)) | 0x08000000;
4679 write32p(0xffc + (MCHBAR32(0xd00) & ~1), eax);
4680 // = 0xe911714b
4681 eax = read32p(0xffc + (MCHBAR32(0xdc0) & ~1)) | 0x40000000;
4682 write32p(0xffc + (MCHBAR32(0xdc0) & ~1), eax);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004683 }
4684#endif
4685
4686 {
4687 u32 eax;
4688
4689 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004690 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4691 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4692 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004693 }
4694
4695 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004696 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004697 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004698 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004699 else
Felix Held04be2dd2018-07-29 04:53:22 +02004700 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004701
Felix Held04be2dd2018-07-29 04:53:22 +02004702 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004703
Felix Held04be2dd2018-07-29 04:53:22 +02004704 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004705 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004706 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004707 else
Felix Held04be2dd2018-07-29 04:53:22 +02004708 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004709 }
4710
Felix Held04be2dd2018-07-29 04:53:22 +02004711 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004712
4713 {
4714 u8 al;
4715 al = 0xd;
4716 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4717 al += 2;
4718 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004719 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004720 }
4721
4722 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004723 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4724 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4725 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4726 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004727 }
4728 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004729 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004730 reg1c = read32p(DEFAULT_EPBAR | 0x01c); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004731 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004732 write32p(DEFAULT_EPBAR | 0x01c, reg1c); // OK
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004733 read_mchbar8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004734 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004735 MCHBAR8_OR(0x1210, 2);
4736 MCHBAR32(0x1200) = 0x8800440;
4737 MCHBAR32(0x1204) = 0x53ff0453;
4738 MCHBAR32(0x1208) = 0x19002043;
4739 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004740
4741 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004742 MCHBAR16(0x1214) = 0x220;
4743 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004744 }
4745
Felix Held04be2dd2018-07-29 04:53:22 +02004746 MCHBAR8_OR(0x1214, 0x4);
4747 MCHBAR8(0x120c) = 0x1;
4748 MCHBAR8(0x1218) = 0x3;
4749 MCHBAR8(0x121a) = 0x3;
4750 MCHBAR8(0x121c) = 0x3;
4751 MCHBAR16(0xc14) = 0x0;
4752 MCHBAR16(0xc20) = 0x0;
4753 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004754
4755 /* revision dependent here. */
4756
Felix Held04be2dd2018-07-29 04:53:22 +02004757 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004758
4759 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004760 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004761
Felix Held04be2dd2018-07-29 04:53:22 +02004762 MCHBAR16_OR(0x1230, 0x8000);
4763 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004764
4765 u8 bl, ebpb;
4766 u16 reg_1020;
4767
Felix Held04be2dd2018-07-29 04:53:22 +02004768 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4769 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004770
Felix Held04be2dd2018-07-29 04:53:22 +02004771 MCHBAR32(0x1000) = 0x100;
4772 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004773
4774 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004775 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004776 bl = reg_1020 >> 8;
4777 ebpb = reg_1020 & 0xff;
4778 } else {
4779 ebpb = 0;
4780 bl = 8;
4781 }
4782
4783 rdmsr(0x1a2);
4784
Felix Held04be2dd2018-07-29 04:53:22 +02004785 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004786
Felix Held04be2dd2018-07-29 04:53:22 +02004787 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004788
Felix Held04be2dd2018-07-29 04:53:22 +02004789 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004790
Felix Held04be2dd2018-07-29 04:53:22 +02004791 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004792 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004793 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4794 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004795 }
4796
4797 setup_heci_uma(&info);
4798
4799 if (info.uma_enabled) {
4800 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004801 MCHBAR32_OR(0x11b0, 0x4000);
4802 MCHBAR32_OR(0x11b4, 0x4000);
4803 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004804
Felix Held04be2dd2018-07-29 04:53:22 +02004805 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4806 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4807 MCHBAR16_OR(0x1170, 0x1000);
4808
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004809 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004810
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004811 u16 ecx;
Felix Held04be2dd2018-07-29 04:53:22 +02004812 for (ecx = 0xffff; ecx && (read_mchbar16(0x1170) & 0x1000);
4813 ecx--) // OK
4814 ;
4815 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004816 }
4817
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004818 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4819 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004820 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004821 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004822
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004823 udelay(1000);
4824 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004825 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4826
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004827 if (!s3resume)
4828 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004829 if (s3resume && cbmem_wasnot_inited) {
4830 u32 reg32;
4831 printk(BIOS_ERR, "Failed S3 resume.\n");
4832 ram_check(0x100000, 0x200000);
4833
4834 /* Clear SLP_TYPE. */
4835 reg32 = inl(DEFAULT_PMBASE + 0x04);
4836 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4837
4838 /* Failed S3 resume, reset to come up cleanly */
4839 outb(0xe, 0xcf9);
Patrick Georgi546953c2014-11-29 10:38:17 +01004840 halt();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004841 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004842}