blob: 78bc6de70a52c0b4ae791e1b754d03ffec26b35d [file] [log] [blame]
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013 Vladimir Serbinenko.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010015 */
16
Kyösti Mälkki931c1dc2014-06-30 09:40:19 +030017#include <stdlib.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010018#include <console/console.h>
19#include <string.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010020#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020021#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020022#include <device/pci_ops.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010023#include <cpu/x86/msr.h>
24#include <cbmem.h>
25#include <arch/cbfs.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010026#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>
Patrick Georgi546953c2014-11-29 10:38:17 +010030#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010031#include <spd.h>
32#include "raminit.h"
Patrick Rudolph266a1f72016-06-09 18:13:34 +020033#include "chip.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010034#include <timestamp.h>
35#include <cpu/x86/mtrr.h>
36#include <cpu/intel/speedstep.h>
37#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010038#include <mrc_cache.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010039
40#include "nehalem.h"
41
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020042#include <southbridge/intel/ibexpeak/me.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010043#include <delay.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010044
45#define NORTHBRIDGE PCI_DEV(0, 0, 0)
46#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
47#define GMA PCI_DEV (0, 0x2, 0x0)
48#define HECIDEV PCI_DEV(0, 0x16, 0)
49#define HECIBAR 0x10
50
51#define FOR_ALL_RANKS \
52 for (channel = 0; channel < NUM_CHANNELS; channel++) \
53 for (slot = 0; slot < NUM_SLOTS; slot++) \
54 for (rank = 0; rank < NUM_RANKS; rank++)
55
56#define FOR_POPULATED_RANKS \
57 for (channel = 0; channel < NUM_CHANNELS; channel++) \
58 for (slot = 0; slot < NUM_SLOTS; slot++) \
59 for (rank = 0; rank < NUM_RANKS; rank++) \
60 if (info->populated_ranks[channel][slot][rank])
61
62#define FOR_POPULATED_RANKS_BACKWARDS \
63 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
64 for (slot = 0; slot < NUM_SLOTS; slot++) \
65 for (rank = 0; rank < NUM_RANKS; rank++) \
66 if (info->populated_ranks[channel][slot][rank])
67
68/* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */
69typedef struct {
70 u8 smallest;
71 u8 largest;
72} timing_bounds_t[2][2][2][9];
73
Arthur Heymansdc71e252018-01-29 10:14:48 +010074#define MRC_CACHE_VERSION 1
75
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010076struct ram_training {
77 /* [TM][CHANNEL][SLOT][RANK][LANE] */
78 u16 lane_timings[4][2][2][2][9];
79 u16 reg_178;
80 u16 reg_10b;
81
82 u8 reg178_center;
83 u8 reg178_smallest;
84 u8 reg178_largest;
85 timing_bounds_t timing_bounds[2];
86 u16 timing_offset[2][2][2][9];
87 u16 timing2_offset[2][2][2][9];
88 u16 timing2_bounds[2][2][2][9][2];
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +010089 u8 reg274265[2][3]; /* [CHANNEL][REGISTER] */
90 u8 reg2ca9_bit0;
91 u32 reg_6dc;
92 u32 reg_6e8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010093};
94
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010095#include <lib.h> /* Prototypes */
96
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010097
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010098static void clflush(u32 addr)
99{
100 asm volatile ("clflush (%0)"::"r" (addr));
101}
102
103typedef struct _u128 {
104 u64 lo;
105 u64 hi;
106} u128;
107
108static void read128(u32 addr, u64 * out)
109{
110 u128 ret;
111 u128 stor;
112 asm volatile ("movdqu %%xmm0, %0\n"
113 "movdqa (%2), %%xmm0\n"
114 "movdqu %%xmm0, %1\n"
115 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
116 out[0] = ret.lo;
117 out[1] = ret.hi;
118}
119
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100120/* OK */
121static void write_1d0(u32 val, u16 addr, int bits, int flag)
122{
Felix Held04be2dd2018-07-29 04:53:22 +0200123 MCHBAR32(0x1d0) = 0;
124 while (MCHBAR32(0x1d0) & 0x800000)
125 ;
126 MCHBAR32(0x1d4) =
127 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
128 MCHBAR32(0x1d0) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200129 while (MCHBAR32(0x1d0) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200130 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100131}
132
133/* OK */
134static u16 read_1d0(u16 addr, int split)
135{
136 u32 val;
Felix Held04be2dd2018-07-29 04:53:22 +0200137 MCHBAR32(0x1d0) = 0;
138 while (MCHBAR32(0x1d0) & 0x800000)
139 ;
140 MCHBAR32(0x1d0) =
141 0x80000000 | (((MCHBAR8(0x246) >> 2) & 3) + 0x361 - addr);
142 while (MCHBAR32(0x1d0) & 0x800000)
143 ;
144 val = MCHBAR32(0x1d8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100145 write_1d0(0, 0x33d, 0, 0);
146 write_1d0(0, 0x33d, 0, 0);
147 val &= ((1 << split) - 1);
148 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
149 return val;
150}
151
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800152static void write32p(uintptr_t addr, uint32_t val)
153{
154 write32((void *)addr, val);
155}
156
157static uint32_t read32p(uintptr_t addr)
158{
159 return read32((void *)addr);
160}
161
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100162static void sfence(void)
163{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100164 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100165}
166
167static inline u16 get_lane_offset(int slot, int rank, int lane)
168{
169 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
170 0x452 * (lane == 8);
171}
172
173static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
174{
175 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
176 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
177}
178
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100179static u32 gav_real(int line, u32 in)
180{
181 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
182 return in;
183}
184
185#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200186
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100187struct raminfo {
188 u16 clock_speed_index; /* clock_speed (REAL, not DDR) / 133.(3) - 3 */
189 u16 fsb_frequency; /* in 1.(1)/2 MHz. */
190 u8 is_x16_module[2][2]; /* [CHANNEL][SLOT] */
191 u8 density[2][2]; /* [CHANNEL][SLOT] */
192 u8 populated_ranks[2][2][2]; /* [CHANNEL][SLOT][RANK] */
193 int rank_start[2][2][2];
194 u8 cas_latency;
195 u8 board_lane_delay[9];
196 u8 use_ecc;
197 u8 revision;
198 u8 max_supported_clock_speed_index;
199 u8 uma_enabled;
200 u8 spd[2][2][151]; /* [CHANNEL][SLOT][BYTE] */
201 u8 silicon_revision;
202 u8 populated_ranks_mask[2];
203 u8 max_slots_used_in_channel;
204 u8 mode4030[2];
205 u16 avg4044[2];
206 u16 max4048[2];
207 unsigned total_memory_mb;
208 unsigned interleaved_part_mb;
209 unsigned non_interleaved_part_mb;
210
211 u32 heci_bar;
212 u64 heci_uma_addr;
213 unsigned memory_reserved_for_heci_mb;
214
215 struct ram_training training;
216 u32 last_500_command[2];
217
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100218 u32 delay46_ps[2];
219 u32 delay54_ps[2];
220 u8 revision_flag_1;
221 u8 some_delay_1_cycle_floor;
222 u8 some_delay_2_halfcycles_ceil;
223 u8 some_delay_3_ps_rounded;
224
225 const struct ram_training *cached_training;
226};
227
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200228/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100229timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200230
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100231static void
232write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
233 int flag);
234
235/* OK */
236static u16
237read_500(struct raminfo *info, int channel, u16 addr, int split)
238{
239 u32 val;
240 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200241 MCHBAR32(0x500 + (channel << 10)) = 0;
242 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
243 ;
244 MCHBAR32(0x500 + (channel << 10)) =
245 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
246 + 0xb88 - addr);
247 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
248 ;
249 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100250 return val & ((1 << split) - 1);
251}
252
253/* OK */
254static void
255write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
256 int flag)
257{
258 if (info->last_500_command[channel] == 0x80000000) {
259 info->last_500_command[channel] = 0x40000000;
260 write_500(info, channel, 0, 0xb61, 0, 0);
261 }
Felix Held04be2dd2018-07-29 04:53:22 +0200262 MCHBAR32(0x500 + (channel << 10)) = 0;
263 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
264 ;
265 MCHBAR32(0x504 + (channel << 10)) =
266 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
267 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200268 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200269 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100270}
271
272static int rw_test(int rank)
273{
274 const u32 mask = 0xf00fc33c;
275 int ok = 0xff;
276 int i;
277 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800278 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100279 sfence();
280 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800281 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100282 sfence();
283 for (i = 0; i < 32; i++) {
284 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800285 write32p((rank << 28) | (i << 3), pat);
286 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100287 }
288 sfence();
289 for (i = 0; i < 32; i++) {
290 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
291 int j;
292 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800293 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100294 for (j = 0; j < 4; j++)
295 if (((val >> (j * 8)) & 0xff) != pat)
296 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800297 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100298 for (j = 0; j < 4; j++)
299 if (((val >> (j * 8)) & 0xff) != pat)
300 ok &= ~(16 << j);
301 }
302 sfence();
303 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800304 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100305 sfence();
306 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800307 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100308
309 return ok;
310}
311
312static void
313program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
314{
315 int lane;
316 for (lane = 0; lane < 8; lane++) {
317 write_500(info, channel,
318 base +
319 info->training.
320 lane_timings[2][channel][slot][rank][lane],
321 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
322 write_500(info, channel,
323 base +
324 info->training.
325 lane_timings[3][channel][slot][rank][lane],
326 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
327 }
328}
329
330static void write_26c(int channel, u16 si)
331{
Felix Held04be2dd2018-07-29 04:53:22 +0200332 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
333 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
334 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100335}
336
337static u32 get_580(int channel, u8 addr)
338{
339 u32 ret;
340 gav(read_1d0(0x142, 3));
Felix Held04be2dd2018-07-29 04:53:22 +0200341 MCHBAR8(0x5ff) = 0x0;
342 MCHBAR8(0x5ff) = 0x80;
343 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
344 MCHBAR8_OR(0x580 + (channel << 10), 1);
345 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
346 ;
347 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100348 return ret;
349}
350
351const int cached_config = 0;
352
353#define NUM_CHANNELS 2
354#define NUM_SLOTS 2
355#define NUM_RANKS 2
356#define RANK_SHIFT 28
357#define CHANNEL_SHIFT 10
358
359#include "raminit_tables.c"
360
361static void seq9(struct raminfo *info, int channel, int slot, int rank)
362{
363 int i, lane;
364
365 for (i = 0; i < 2; i++)
366 for (lane = 0; lane < 8; lane++)
367 write_500(info, channel,
368 info->training.lane_timings[i +
369 1][channel][slot]
370 [rank][lane], get_timing_register_addr(lane,
371 i + 1,
372 slot,
373 rank),
374 9, 0);
375
376 write_1d0(1, 0x103, 6, 1);
377 for (lane = 0; lane < 8; lane++)
378 write_500(info, channel,
379 info->training.
380 lane_timings[0][channel][slot][rank][lane],
381 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
382
383 for (i = 0; i < 2; i++) {
384 for (lane = 0; lane < 8; lane++)
385 write_500(info, channel,
386 info->training.lane_timings[i +
387 1][channel][slot]
388 [rank][lane], get_timing_register_addr(lane,
389 i + 1,
390 slot,
391 rank),
392 9, 0);
393 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
394 }
395
396 gav(read_1d0(0x142, 3)); // = 0x10408118
Felix Held04be2dd2018-07-29 04:53:22 +0200397 MCHBAR8(0x5ff) = 0x0;
398 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100399 write_1d0(0x2, 0x142, 3, 1);
400 for (lane = 0; lane < 8; lane++) {
401 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
402 info->training.lane_timings[2][channel][slot][rank][lane] =
403 read_500(info, channel,
404 get_timing_register_addr(lane, 2, slot, rank), 9);
405 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
406 info->training.lane_timings[3][channel][slot][rank][lane] =
407 info->training.lane_timings[2][channel][slot][rank][lane] +
408 0x20;
409 }
410}
411
412static int count_ranks_in_channel(struct raminfo *info, int channel)
413{
414 int slot, rank;
415 int res = 0;
416 for (slot = 0; slot < NUM_SLOTS; slot++)
417 for (rank = 0; rank < NUM_SLOTS; rank++)
418 res += info->populated_ranks[channel][slot][rank];
419 return res;
420}
421
422static void
423config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
424{
425 int add;
426
427 write_1d0(0, 0x178, 7, 1);
428 seq9(info, channel, slot, rank);
429 program_timings(info, 0x80, channel, slot, rank);
430
431 if (channel == 0)
432 add = count_ranks_in_channel(info, 1);
433 else
434 add = 0;
435 if (!s3resume)
436 gav(rw_test(rank + add));
437 program_timings(info, 0x00, channel, slot, rank);
438 if (!s3resume)
439 gav(rw_test(rank + add));
440 if (!s3resume)
441 gav(rw_test(rank + add));
442 write_1d0(0, 0x142, 3, 1);
443 write_1d0(0, 0x103, 6, 1);
444
445 gav(get_580(channel, 0xc | (rank << 5)));
446 gav(read_1d0(0x142, 3));
447
Felix Held04be2dd2018-07-29 04:53:22 +0200448 MCHBAR8(0x5ff) = 0x0;
449 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100450}
451
452static void set_4cf(struct raminfo *info, int channel, u8 val)
453{
454 gav(read_500(info, channel, 0x4cf, 4)); // = 0xc2300cf9
455 write_500(info, channel, val, 0x4cf, 4, 1);
456 gav(read_500(info, channel, 0x659, 4)); // = 0x80300839
457 write_500(info, channel, val, 0x659, 4, 1);
458 gav(read_500(info, channel, 0x697, 4)); // = 0x80300839
459 write_500(info, channel, val, 0x697, 4, 1);
460}
461
462static void set_334(int zero)
463{
464 int j, k, channel;
465 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
466 u32 vd8[2][16];
467
468 for (channel = 0; channel < NUM_CHANNELS; channel++) {
469 for (j = 0; j < 4; j++) {
470 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
471 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
472 u16 c;
473 if ((j == 0 || j == 3) && zero)
474 c = 0;
475 else if (j == 3)
476 c = 0x5f;
477 else
478 c = 0x5f5f;
479
480 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200481 MCHBAR32(0x138 + 8 * k) =
482 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100483 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200484 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100485 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200486 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100487 }
488
Felix Held22ca8cb2018-07-29 05:09:44 +0200489 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
490 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200491 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
492 zero ? 0 : (0x18191819 & lmask);
493 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
494 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
495 zero ? 0 : (a & lmask);
496 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
497 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100498 }
499 }
500
Felix Held04be2dd2018-07-29 04:53:22 +0200501 MCHBAR32_OR(0x130, 1);
502 while (MCHBAR8(0x130) & 1)
503 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100504}
505
506static void rmw_1d0(u16 addr, u32 and, u32 or, int split, int flag)
507{
508 u32 v;
509 v = read_1d0(addr, split);
510 write_1d0((v & and) | or, addr, split, flag);
511}
512
513static int find_highest_bit_set(u16 val)
514{
515 int i;
516 for (i = 15; i >= 0; i--)
517 if (val & (1 << i))
518 return i;
519 return -1;
520}
521
522static int find_lowest_bit_set32(u32 val)
523{
524 int i;
525 for (i = 0; i < 32; i++)
526 if (val & (1 << i))
527 return i;
528 return -1;
529}
530
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100531enum {
532 DEVICE_TYPE = 2,
533 MODULE_TYPE = 3,
534 DENSITY = 4,
535 RANKS_AND_DQ = 7,
536 MEMORY_BUS_WIDTH = 8,
537 TIMEBASE_DIVIDEND = 10,
538 TIMEBASE_DIVISOR = 11,
539 CYCLETIME = 12,
540
541 CAS_LATENCIES_LSB = 14,
542 CAS_LATENCIES_MSB = 15,
543 CAS_LATENCY_TIME = 16,
544 THERMAL_AND_REFRESH = 31,
545 REFERENCE_RAW_CARD_USED = 62,
546 RANK1_ADDRESS_MAPPING = 63
547};
548
549static void calculate_timings(struct raminfo *info)
550{
551 unsigned cycletime;
552 unsigned cas_latency_time;
553 unsigned supported_cas_latencies;
554 unsigned channel, slot;
555 unsigned clock_speed_index;
556 unsigned min_cas_latency;
557 unsigned cas_latency;
558 unsigned max_clock_index;
559
560 /* Find common CAS latency */
561 supported_cas_latencies = 0x3fe;
562 for (channel = 0; channel < NUM_CHANNELS; channel++)
563 for (slot = 0; slot < NUM_SLOTS; slot++)
564 if (info->populated_ranks[channel][slot][0])
565 supported_cas_latencies &=
566 2 *
567 (info->
568 spd[channel][slot][CAS_LATENCIES_LSB] |
569 (info->
570 spd[channel][slot][CAS_LATENCIES_MSB] <<
571 8));
572
573 max_clock_index = min(3, info->max_supported_clock_speed_index);
574
575 cycletime = min_cycletime[max_clock_index];
576 cas_latency_time = min_cas_latency_time[max_clock_index];
577
578 for (channel = 0; channel < NUM_CHANNELS; channel++)
579 for (slot = 0; slot < NUM_SLOTS; slot++)
580 if (info->populated_ranks[channel][slot][0]) {
581 unsigned timebase;
582 timebase =
583 1000 *
584 info->
585 spd[channel][slot][TIMEBASE_DIVIDEND] /
586 info->spd[channel][slot][TIMEBASE_DIVISOR];
587 cycletime =
588 max(cycletime,
589 timebase *
590 info->spd[channel][slot][CYCLETIME]);
591 cas_latency_time =
592 max(cas_latency_time,
593 timebase *
594 info->
595 spd[channel][slot][CAS_LATENCY_TIME]);
596 }
597 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
598 if (cycletime == min_cycletime[clock_speed_index])
599 break;
600 if (cycletime > min_cycletime[clock_speed_index]) {
601 clock_speed_index--;
602 cycletime = min_cycletime[clock_speed_index];
603 break;
604 }
605 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100606 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100607 cas_latency = 0;
608 while (supported_cas_latencies) {
609 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
610 if (cas_latency <= min_cas_latency)
611 break;
612 supported_cas_latencies &=
613 ~(1 << find_highest_bit_set(supported_cas_latencies));
614 }
615
616 if (cas_latency != min_cas_latency && clock_speed_index)
617 clock_speed_index--;
618
619 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
620 die("Couldn't configure DRAM");
621 info->clock_speed_index = clock_speed_index;
622 info->cas_latency = cas_latency;
623}
624
625static void program_base_timings(struct raminfo *info)
626{
627 unsigned channel;
628 unsigned slot, rank, lane;
629 unsigned extended_silicon_revision;
630 int i;
631
632 extended_silicon_revision = info->silicon_revision;
633 if (info->silicon_revision == 0)
634 for (channel = 0; channel < NUM_CHANNELS; channel++)
635 for (slot = 0; slot < NUM_SLOTS; slot++)
636 if ((info->
637 spd[channel][slot][MODULE_TYPE] & 0xF) ==
638 3)
639 extended_silicon_revision = 4;
640
641 for (channel = 0; channel < NUM_CHANNELS; channel++) {
642 for (slot = 0; slot < NUM_SLOTS; slot++)
643 for (rank = 0; rank < NUM_SLOTS; rank++) {
644 int card_timing_2;
645 if (!info->populated_ranks[channel][slot][rank])
646 continue;
647
648 for (lane = 0; lane < 9; lane++) {
649 int tm_reg;
650 int card_timing;
651
652 card_timing = 0;
653 if ((info->
654 spd[channel][slot][MODULE_TYPE] &
655 0xF) == 3) {
656 int reference_card;
657 reference_card =
658 info->
659 spd[channel][slot]
660 [REFERENCE_RAW_CARD_USED] &
661 0x1f;
662 if (reference_card == 3)
663 card_timing =
664 u16_ffd1188[0][lane]
665 [info->
666 clock_speed_index];
667 if (reference_card == 5)
668 card_timing =
669 u16_ffd1188[1][lane]
670 [info->
671 clock_speed_index];
672 }
673
674 info->training.
675 lane_timings[0][channel][slot][rank]
676 [lane] =
677 u8_FFFD1218[info->
678 clock_speed_index];
679 info->training.
680 lane_timings[1][channel][slot][rank]
681 [lane] = 256;
682
683 for (tm_reg = 2; tm_reg < 4; tm_reg++)
684 info->training.
685 lane_timings[tm_reg]
686 [channel][slot][rank][lane]
687 =
688 u8_FFFD1240[channel]
689 [extended_silicon_revision]
690 [lane][2 * slot +
691 rank][info->
692 clock_speed_index]
693 + info->max4048[channel]
694 +
695 u8_FFFD0C78[channel]
696 [extended_silicon_revision]
697 [info->
698 mode4030[channel]][slot]
699 [rank][info->
700 clock_speed_index]
701 + card_timing;
702 for (tm_reg = 0; tm_reg < 4; tm_reg++)
703 write_500(info, channel,
704 info->training.
705 lane_timings[tm_reg]
706 [channel][slot][rank]
707 [lane],
708 get_timing_register_addr
709 (lane, tm_reg, slot,
710 rank), 9, 0);
711 }
712
713 card_timing_2 = 0;
714 if (!(extended_silicon_revision != 4
715 || (info->
716 populated_ranks_mask[channel] & 5) ==
717 5)) {
718 if ((info->
719 spd[channel][slot]
720 [REFERENCE_RAW_CARD_USED] & 0x1F)
721 == 3)
722 card_timing_2 =
723 u16_FFFE0EB8[0][info->
724 clock_speed_index];
725 if ((info->
726 spd[channel][slot]
727 [REFERENCE_RAW_CARD_USED] & 0x1F)
728 == 5)
729 card_timing_2 =
730 u16_FFFE0EB8[1][info->
731 clock_speed_index];
732 }
733
734 for (i = 0; i < 3; i++)
735 write_500(info, channel,
736 (card_timing_2 +
737 info->max4048[channel]
738 +
739 u8_FFFD0EF8[channel]
740 [extended_silicon_revision]
741 [info->
742 mode4030[channel]][info->
743 clock_speed_index]),
744 u16_fffd0c50[i][slot][rank],
745 8, 1);
746 write_500(info, channel,
747 (info->max4048[channel] +
748 u8_FFFD0C78[channel]
749 [extended_silicon_revision][info->
750 mode4030
751 [channel]]
752 [slot][rank][info->
753 clock_speed_index]),
754 u16_fffd0c70[slot][rank], 7, 1);
755 }
756 if (!info->populated_ranks_mask[channel])
757 continue;
758 for (i = 0; i < 3; i++)
759 write_500(info, channel,
760 (info->max4048[channel] +
761 info->avg4044[channel]
762 +
763 u8_FFFD17E0[channel]
764 [extended_silicon_revision][info->
765 mode4030
766 [channel]][info->
767 clock_speed_index]),
768 u16_fffd0c68[i], 8, 1);
769 }
770}
771
772static unsigned int fsbcycle_ps(struct raminfo *info)
773{
774 return 900000 / info->fsb_frequency;
775}
776
777/* The time of DDR transfer in ps. */
778static unsigned int halfcycle_ps(struct raminfo *info)
779{
780 return 3750 / (info->clock_speed_index + 3);
781}
782
783/* The time of clock cycle in ps. */
784static unsigned int cycle_ps(struct raminfo *info)
785{
786 return 2 * halfcycle_ps(info);
787}
788
789/* Frequency in 1.(1)=10/9 MHz units. */
790static unsigned frequency_11(struct raminfo *info)
791{
792 return (info->clock_speed_index + 3) * 120;
793}
794
795/* Frequency in 0.1 MHz units. */
796static unsigned frequency_01(struct raminfo *info)
797{
798 return 100 * frequency_11(info) / 9;
799}
800
801static unsigned ps_to_halfcycles(struct raminfo *info, unsigned int ps)
802{
803 return (frequency_11(info) * 2) * ps / 900000;
804}
805
806static unsigned ns_to_cycles(struct raminfo *info, unsigned int ns)
807{
808 return (frequency_11(info)) * ns / 900;
809}
810
811static void compute_derived_timings(struct raminfo *info)
812{
813 unsigned channel, slot, rank;
814 int extended_silicon_revision;
815 int some_delay_1_ps;
816 int some_delay_2_ps;
817 int some_delay_2_halfcycles_ceil;
818 int some_delay_2_halfcycles_floor;
819 int some_delay_3_ps;
820 int some_delay_3_halfcycles;
821 int some_delay_3_ps_rounded;
822 int some_delay_1_cycle_ceil;
823 int some_delay_1_cycle_floor;
824
825 some_delay_3_halfcycles = 0;
826 some_delay_3_ps_rounded = 0;
827 extended_silicon_revision = info->silicon_revision;
828 if (!info->silicon_revision)
829 for (channel = 0; channel < NUM_CHANNELS; channel++)
830 for (slot = 0; slot < NUM_SLOTS; slot++)
831 if ((info->
832 spd[channel][slot][MODULE_TYPE] & 0xF) ==
833 3)
834 extended_silicon_revision = 4;
835 if (info->board_lane_delay[7] < 5)
836 info->board_lane_delay[7] = 5;
837 info->revision_flag_1 = 2;
838 if (info->silicon_revision == 2 || info->silicon_revision == 3)
839 info->revision_flag_1 = 0;
840 if (info->revision < 16)
841 info->revision_flag_1 = 0;
842
843 if (info->revision < 8)
844 info->revision_flag_1 = 0;
845 if (info->revision >= 8 && (info->silicon_revision == 0
846 || info->silicon_revision == 1))
847 some_delay_2_ps = 735;
848 else
849 some_delay_2_ps = 750;
850
851 if (info->revision >= 0x10 && (info->silicon_revision == 0
852 || info->silicon_revision == 1))
853 some_delay_1_ps = 3929;
854 else
855 some_delay_1_ps = 3490;
856
857 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
858 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
859 if (some_delay_1_ps % cycle_ps(info))
860 some_delay_1_cycle_ceil++;
861 else
862 some_delay_1_cycle_floor--;
863 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
864 if (info->revision_flag_1)
865 some_delay_2_ps = halfcycle_ps(info) >> 6;
866 some_delay_2_ps +=
867 max(some_delay_1_ps - 30,
868 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
869 375;
870 some_delay_3_ps =
871 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
872 if (info->revision_flag_1) {
873 if (some_delay_3_ps < 150)
874 some_delay_3_halfcycles = 0;
875 else
876 some_delay_3_halfcycles =
877 (some_delay_3_ps << 6) / halfcycle_ps(info);
878 some_delay_3_ps_rounded =
879 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
880 }
881 some_delay_2_halfcycles_ceil =
882 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
883 2 * (some_delay_1_cycle_ceil - 1);
884 if (info->revision_flag_1 && some_delay_3_ps < 150)
885 some_delay_2_halfcycles_ceil++;
886 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
887 if (info->revision < 0x10)
888 some_delay_2_halfcycles_floor =
889 some_delay_2_halfcycles_ceil - 1;
890 if (!info->revision_flag_1)
891 some_delay_2_halfcycles_floor++;
892 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
893 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
894 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
895 || (info->populated_ranks[1][0][0]
896 && info->populated_ranks[1][1][0]))
897 info->max_slots_used_in_channel = 2;
898 else
899 info->max_slots_used_in_channel = 1;
900 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200901 MCHBAR32(0x244 + (channel << 10)) =
902 ((info->revision < 8) ? 1 : 0x200) |
903 ((2 - info->max_slots_used_in_channel) << 17) |
904 (channel << 21) |
905 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100906 if (info->max_slots_used_in_channel == 1) {
907 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
908 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
909 } else {
910 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 */
911 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
912 || (count_ranks_in_channel(info, 1) ==
913 2)) ? 2 : 3;
914 }
915 for (channel = 0; channel < NUM_CHANNELS; channel++) {
916 int max_of_unk;
917 int min_of_unk_2;
918
919 int i, count;
920 int sum;
921
922 if (!info->populated_ranks_mask[channel])
923 continue;
924
925 max_of_unk = 0;
926 min_of_unk_2 = 32767;
927
928 sum = 0;
929 count = 0;
930 for (i = 0; i < 3; i++) {
931 int unk1;
932 if (info->revision < 8)
933 unk1 =
934 u8_FFFD1891[0][channel][info->
935 clock_speed_index]
936 [i];
937 else if (!
938 (info->revision >= 0x10
939 || info->revision_flag_1))
940 unk1 =
941 u8_FFFD1891[1][channel][info->
942 clock_speed_index]
943 [i];
944 else
945 unk1 = 0;
946 for (slot = 0; slot < NUM_SLOTS; slot++)
947 for (rank = 0; rank < NUM_RANKS; rank++) {
948 int a = 0;
949 int b = 0;
950
951 if (!info->
952 populated_ranks[channel][slot]
953 [rank])
954 continue;
955 if (extended_silicon_revision == 4
956 && (info->
957 populated_ranks_mask[channel] &
958 5) != 5) {
959 if ((info->
960 spd[channel][slot]
961 [REFERENCE_RAW_CARD_USED] &
962 0x1F) == 3) {
963 a = u16_ffd1178[0]
964 [info->
965 clock_speed_index];
966 b = u16_fe0eb8[0][info->
967 clock_speed_index];
968 } else
969 if ((info->
970 spd[channel][slot]
971 [REFERENCE_RAW_CARD_USED]
972 & 0x1F) == 5) {
973 a = u16_ffd1178[1]
974 [info->
975 clock_speed_index];
976 b = u16_fe0eb8[1][info->
977 clock_speed_index];
978 }
979 }
980 min_of_unk_2 = min(min_of_unk_2, a);
981 min_of_unk_2 = min(min_of_unk_2, b);
982 if (rank == 0) {
983 sum += a;
984 count++;
985 }
986 {
987 int t;
988 t = b +
989 u8_FFFD0EF8[channel]
990 [extended_silicon_revision]
991 [info->
992 mode4030[channel]][info->
993 clock_speed_index];
994 if (unk1 >= t)
995 max_of_unk =
996 max(max_of_unk,
997 unk1 - t);
998 }
999 }
1000 {
1001 int t =
1002 u8_FFFD17E0[channel]
1003 [extended_silicon_revision][info->
1004 mode4030
1005 [channel]]
1006 [info->clock_speed_index] + min_of_unk_2;
1007 if (unk1 >= t)
1008 max_of_unk = max(max_of_unk, unk1 - t);
1009 }
1010 }
1011
1012 info->avg4044[channel] = sum / count;
1013 info->max4048[channel] = max_of_unk;
1014 }
1015}
1016
1017static void jedec_read(struct raminfo *info,
1018 int channel, int slot, int rank,
1019 int total_rank, u8 addr3, unsigned int value)
1020{
1021 /* Handle mirrored mapping. */
1022 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001023 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1024 ((addr3 >> 1) & 0x10);
1025 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1026 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001027
1028 /* Handle mirrored mapping. */
1029 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1030 value =
1031 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1032 << 1);
1033
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001034 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001035
Felix Held04be2dd2018-07-29 04:53:22 +02001036 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1037 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001038
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001039 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001040}
1041
1042enum {
1043 MR1_RZQ12 = 512,
1044 MR1_RZQ2 = 64,
1045 MR1_RZQ4 = 4,
1046 MR1_ODS34OHM = 2
1047};
1048
1049enum {
1050 MR0_BT_INTERLEAVED = 8,
1051 MR0_DLL_RESET_ON = 256
1052};
1053
1054enum {
1055 MR2_RTT_WR_DISABLED = 0,
1056 MR2_RZQ2 = 1 << 10
1057};
1058
1059static void jedec_init(struct raminfo *info)
1060{
1061 int write_recovery;
1062 int channel, slot, rank;
1063 int total_rank;
1064 int dll_on;
1065 int self_refresh_temperature;
1066 int auto_self_refresh;
1067
1068 auto_self_refresh = 1;
1069 self_refresh_temperature = 1;
1070 if (info->board_lane_delay[3] <= 10) {
1071 if (info->board_lane_delay[3] <= 8)
1072 write_recovery = info->board_lane_delay[3] - 4;
1073 else
1074 write_recovery = 5;
1075 } else {
1076 write_recovery = 6;
1077 }
1078 FOR_POPULATED_RANKS {
1079 auto_self_refresh &=
1080 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1081 self_refresh_temperature &=
1082 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1083 }
1084 if (auto_self_refresh == 1)
1085 self_refresh_temperature = 0;
1086
1087 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1088 || (info->populated_ranks[0][0][0]
1089 && info->populated_ranks[0][1][0])
1090 || (info->populated_ranks[1][0][0]
1091 && info->populated_ranks[1][1][0]));
1092
1093 total_rank = 0;
1094
1095 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1096 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1097 int rzq_reg58e;
1098
1099 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1100 rzq_reg58e = 64;
1101 rtt = MR1_RZQ2;
1102 if (info->clock_speed_index != 0) {
1103 rzq_reg58e = 4;
1104 if (info->populated_ranks_mask[channel] == 3)
1105 rtt = MR1_RZQ4;
1106 }
1107 } else {
1108 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1109 rtt = MR1_RZQ12;
1110 rzq_reg58e = 64;
1111 rtt_wr = MR2_RZQ2;
1112 } else {
1113 rzq_reg58e = 4;
1114 rtt = MR1_RZQ4;
1115 }
1116 }
1117
Felix Held04be2dd2018-07-29 04:53:22 +02001118 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1119 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1120 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1121 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1122 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001123
1124 for (slot = 0; slot < NUM_SLOTS; slot++)
1125 for (rank = 0; rank < NUM_RANKS; rank++)
1126 if (info->populated_ranks[channel][slot][rank]) {
1127 jedec_read(info, channel, slot, rank,
1128 total_rank, 0x28,
1129 rtt_wr | (info->
1130 clock_speed_index
1131 << 3)
1132 | (auto_self_refresh << 6) |
1133 (self_refresh_temperature <<
1134 7));
1135 jedec_read(info, channel, slot, rank,
1136 total_rank, 0x38, 0);
1137 jedec_read(info, channel, slot, rank,
1138 total_rank, 0x18,
1139 rtt | MR1_ODS34OHM);
1140 jedec_read(info, channel, slot, rank,
1141 total_rank, 6,
1142 (dll_on << 12) |
1143 (write_recovery << 9)
1144 | ((info->cas_latency - 4) <<
1145 4) | MR0_BT_INTERLEAVED |
1146 MR0_DLL_RESET_ON);
1147 total_rank++;
1148 }
1149 }
1150}
1151
1152static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1153{
1154 unsigned channel, slot, rank;
1155 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1156 unsigned int channel_0_non_interleaved;
1157
1158 FOR_ALL_RANKS {
1159 if (info->populated_ranks[channel][slot][rank]) {
1160 total_mb[channel] +=
1161 pre_jedec ? 256 : (256 << info->
1162 density[channel][slot] >> info->
1163 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001164 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1165 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1166 (info->is_x16_module[channel][slot] |
1167 ((info->density[channel][slot] + 1) << 1))) |
1168 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001169 }
Felix Held04be2dd2018-07-29 04:53:22 +02001170 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1171 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001172 }
1173
1174 info->total_memory_mb = total_mb[0] + total_mb[1];
1175
1176 info->interleaved_part_mb =
1177 pre_jedec ? 0 : 2 * min(total_mb[0], total_mb[1]);
1178 info->non_interleaved_part_mb =
1179 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1180 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001181 MCHBAR32(0x100) = channel_0_non_interleaved |
1182 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001183 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001184 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001185}
1186
1187static void program_board_delay(struct raminfo *info)
1188{
1189 int cas_latency_shift;
1190 int some_delay_ns;
1191 int some_delay_3_half_cycles;
1192
1193 unsigned channel, i;
1194 int high_multiplier;
1195 int lane_3_delay;
1196 int cas_latency_derived;
1197
1198 high_multiplier = 0;
1199 some_delay_ns = 200;
1200 some_delay_3_half_cycles = 4;
1201 cas_latency_shift = info->silicon_revision == 0
1202 || info->silicon_revision == 1 ? 1 : 0;
1203 if (info->revision < 8) {
1204 some_delay_ns = 600;
1205 cas_latency_shift = 0;
1206 }
1207 {
1208 int speed_bit;
1209 speed_bit =
1210 ((info->clock_speed_index > 1
1211 || (info->silicon_revision != 2
1212 && info->silicon_revision != 3))) ^ (info->revision >=
1213 0x10);
1214 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1215 3, 1);
1216 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1217 3, 1);
1218 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1219 && (info->silicon_revision == 2
1220 || info->silicon_revision == 3))
1221 rmw_1d0(0x116, 5, 2, 4, 1);
1222 }
Felix Held04be2dd2018-07-29 04:53:22 +02001223 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1224 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001225
Felix Held04be2dd2018-07-29 04:53:22 +02001226 MCHBAR8(0x124) = info->board_lane_delay[4] +
1227 ((frequency_01(info) + 999) / 1000);
1228 MCHBAR16(0x125) = 0x1360;
1229 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001230 if (info->fsb_frequency < frequency_11(info) / 2) {
1231 unsigned some_delay_2_half_cycles;
1232 high_multiplier = 1;
1233 some_delay_2_half_cycles = ps_to_halfcycles(info,
1234 ((3 *
1235 fsbcycle_ps(info))
1236 >> 1) +
1237 (halfcycle_ps(info)
1238 *
1239 reg178_min[info->
1240 clock_speed_index]
1241 >> 6)
1242 +
1243 4 *
1244 halfcycle_ps(info)
1245 + 2230);
1246 some_delay_3_half_cycles =
1247 min((some_delay_2_half_cycles +
1248 (frequency_11(info) * 2) * (28 -
1249 some_delay_2_half_cycles) /
1250 (frequency_11(info) * 2 -
1251 4 * (info->fsb_frequency))) >> 3, 7);
1252 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001253 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001254 some_delay_3_half_cycles = 3;
1255 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001256 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1257 MCHBAR32(0x224 + (channel << 10)) =
1258 (info->max_slots_used_in_channel - 1) |
1259 ((info->cas_latency - 5 - info->clock_speed_index)
1260 << 21) | ((info->max_slots_used_in_channel +
1261 info->cas_latency - cas_latency_shift - 4) << 16) |
1262 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1263 ((info->cas_latency - info->clock_speed_index +
1264 info->max_slots_used_in_channel - 6) << 8);
1265 MCHBAR32(0x228 + (channel << 10)) =
1266 info->max_slots_used_in_channel;
1267 MCHBAR8(0x239 + (channel << 10)) = 32;
1268 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1269 (some_delay_3_half_cycles << 25) | 0x840000;
1270 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1271 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1272 MCHBAR32(0x24c + (channel << 10)) =
1273 ((!!info->clock_speed_index) << 17) |
1274 (((2 + info->clock_speed_index -
1275 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001276
Felix Held04be2dd2018-07-29 04:53:22 +02001277 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1278 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1279 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001280
1281 write_500(info, channel,
1282 ((!info->populated_ranks[channel][1][1])
1283 | (!info->populated_ranks[channel][1][0] << 1)
1284 | (!info->populated_ranks[channel][0][1] << 2)
1285 | (!info->populated_ranks[channel][0][0] << 3)),
1286 0x4c9, 4, 1);
1287 }
1288
Felix Held22ca8cb2018-07-29 05:09:44 +02001289 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001290 {
1291 u8 freq_divisor = 2;
1292 if (info->fsb_frequency == frequency_11(info))
1293 freq_divisor = 3;
1294 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1295 freq_divisor = 1;
1296 else
1297 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001298 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001299 }
1300
1301 if (info->board_lane_delay[3] <= 10) {
1302 if (info->board_lane_delay[3] <= 8)
1303 lane_3_delay = info->board_lane_delay[3];
1304 else
1305 lane_3_delay = 10;
1306 } else {
1307 lane_3_delay = 12;
1308 }
1309 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1310 if (info->clock_speed_index > 1)
1311 cas_latency_derived++;
1312 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001313 MCHBAR32(0x240 + (channel << 10)) =
1314 ((info->clock_speed_index == 0) * 0x11000) |
1315 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1316 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001317 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1318 0x609, 6, 1);
1319 write_500(info, channel,
1320 info->clock_speed_index + 2 * info->cas_latency - 7,
1321 0x601, 6, 1);
1322
Felix Held04be2dd2018-07-29 04:53:22 +02001323 MCHBAR32(0x250 + (channel << 10)) =
1324 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1325 (info->board_lane_delay[7] << 2) |
1326 (info->board_lane_delay[4] << 16) |
1327 (info->board_lane_delay[1] << 25) |
1328 (info->board_lane_delay[1] << 29) | 1;
1329 MCHBAR32(0x254 + (channel << 10)) =
1330 (info->board_lane_delay[1] >> 3) |
1331 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1332 0x80 | (info->board_lane_delay[6] << 1) |
1333 (info->board_lane_delay[2] << 28) |
1334 (cas_latency_derived << 16) | 0x4700000;
1335 MCHBAR32(0x258 + (channel << 10)) =
1336 ((info->board_lane_delay[5] + info->clock_speed_index +
1337 9) << 12) | ((info->clock_speed_index -
1338 info->cas_latency + 12) << 8) |
1339 (info->board_lane_delay[2] << 17) |
1340 (info->board_lane_delay[4] << 24) | 0x47;
1341 MCHBAR32(0x25c + (channel << 10)) =
1342 (info->board_lane_delay[1] << 1) |
1343 (info->board_lane_delay[0] << 8) | 0x1da50000;
1344 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1345 MCHBAR8(0x5f8 + (channel << 10)) =
1346 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001347 }
1348
1349 program_modules_memory_map(info, 1);
1350
Felix Held04be2dd2018-07-29 04:53:22 +02001351 MCHBAR16(0x610) = (min(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
1352 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1353 MCHBAR16_OR(0x612, 0x100);
1354 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001355 for (i = 0; i < 8; i++) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001356 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0x80 + 4 * i,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001357 (info->total_memory_mb - 64) | !i | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001358 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0xc0 + 4 * i, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001359 }
1360}
1361
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001362#define DEFAULT_PCI_MMIO_SIZE 2048
1363#define HOST_BRIDGE PCI_DEVFN(0, 0)
1364
1365static unsigned int get_mmio_size(void)
1366{
1367 const struct device *dev;
1368 const struct northbridge_intel_nehalem_config *cfg = NULL;
1369
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001370 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001371 if (dev)
1372 cfg = dev->chip_info;
1373
1374 /* If this is zero, it just means devicetree.cb didn't set it */
1375 if (!cfg || cfg->pci_mmio_size == 0)
1376 return DEFAULT_PCI_MMIO_SIZE;
1377 else
1378 return cfg->pci_mmio_size;
1379}
1380
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001381#define BETTER_MEMORY_MAP 0
1382
1383static void program_total_memory_map(struct raminfo *info)
1384{
1385 unsigned int TOM, TOLUD, TOUUD;
1386 unsigned int quickpath_reserved;
1387 unsigned int REMAPbase;
1388 unsigned int uma_base_igd;
1389 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001390 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001391 int memory_remap;
1392 unsigned int memory_map[8];
1393 int i;
1394 unsigned int current_limit;
1395 unsigned int tseg_base;
1396 int uma_size_igd = 0, uma_size_gtt = 0;
1397
1398 memset(memory_map, 0, sizeof(memory_map));
1399
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001400 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001401 u16 t = pci_read_config16(NORTHBRIDGE, D0F0_GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001402 gav(t);
1403 const int uma_sizes_gtt[16] =
1404 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1405 /* Igd memory */
1406 const int uma_sizes_igd[16] = {
1407 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1408 256, 512
1409 };
1410
1411 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1412 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1413 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001414
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001415 mmio_size = get_mmio_size();
1416
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001417 TOM = info->total_memory_mb;
1418 if (TOM == 4096)
1419 TOM = 4032;
1420 TOUUD = ALIGN_DOWN(TOM - info->memory_reserved_for_heci_mb, 64);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001421 TOLUD = ALIGN_DOWN(min(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
Elyes HAOUASa342f392018-10-17 10:56:26 +02001422 , TOUUD), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001423 memory_remap = 0;
1424 if (TOUUD - TOLUD > 64) {
1425 memory_remap = 1;
1426 REMAPbase = max(4096, TOUUD);
1427 TOUUD = TOUUD - TOLUD + 4096;
1428 }
1429 if (TOUUD > 4096)
1430 memory_map[2] = TOUUD | 1;
1431 quickpath_reserved = 0;
1432
1433 {
1434 u32 t;
1435
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001436 gav(t = pci_read_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 0x68));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001437 if (t & 0x800)
1438 quickpath_reserved =
1439 (1 << find_lowest_bit_set32(t >> 20));
1440 }
1441 if (memory_remap)
1442 TOUUD -= quickpath_reserved;
1443
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001444 uma_base_igd = TOLUD - uma_size_igd;
1445 uma_base_gtt = uma_base_igd - uma_size_gtt;
1446 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1447 if (!memory_remap)
1448 tseg_base -= quickpath_reserved;
1449 tseg_base = ALIGN_DOWN(tseg_base, 8);
1450
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001451 pci_write_config16(NORTHBRIDGE, D0F0_TOLUD, TOLUD << 4);
1452 pci_write_config16(NORTHBRIDGE, D0F0_TOM, TOM >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001453 if (memory_remap) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001454 pci_write_config16(NORTHBRIDGE, D0F0_REMAPBASE, REMAPbase >> 6);
1455 pci_write_config16(NORTHBRIDGE, D0F0_REMAPLIMIT, (TOUUD - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001456 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001457 pci_write_config16(NORTHBRIDGE, D0F0_TOUUD, TOUUD);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001458
1459 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001460 pci_write_config32(NORTHBRIDGE, D0F0_IGD_BASE, uma_base_igd << 20);
1461 pci_write_config32(NORTHBRIDGE, D0F0_GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001462 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001463 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001464
1465 current_limit = 0;
1466 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1467 memory_map[1] = 4096;
1468 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
1469 current_limit = max(current_limit, memory_map[i] & ~1);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001470 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0x80,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001471 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1472 1, 64) | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001473 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0xc0, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001474 }
1475}
1476
1477static void collect_system_info(struct raminfo *info)
1478{
1479 u32 capid0[3];
1480 int i;
1481 unsigned channel;
1482
1483 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001484 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1485 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001486
1487 if (!info->heci_bar)
1488 gav(info->heci_bar =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001489 pci_read_config32(HECIDEV, HECIBAR) & 0xFFFFFFF8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001490 if (!info->memory_reserved_for_heci_mb) {
1491 /* Wait for ME to be ready */
1492 intel_early_me_init();
1493 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1494 }
1495
1496 for (i = 0; i < 3; i++)
1497 gav(capid0[i] =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001498 pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 | (i << 2)));
1499 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001500 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1501
1502 if ((capid0[1] >> 11) & 1)
1503 info->uma_enabled = 0;
1504 else
1505 gav(info->uma_enabled =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001506 pci_read_config8(NORTHBRIDGE, D0F0_DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001507 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1508 info->silicon_revision = 0;
1509
1510 if (capid0[2] & 2) {
1511 info->silicon_revision = 0;
1512 info->max_supported_clock_speed_index = 2;
1513 for (channel = 0; channel < NUM_CHANNELS; channel++)
1514 if (info->populated_ranks[channel][0][0]
1515 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1516 3) {
1517 info->silicon_revision = 2;
1518 info->max_supported_clock_speed_index = 1;
1519 }
1520 } else {
1521 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1522 case 1:
1523 case 2:
1524 info->silicon_revision = 3;
1525 break;
1526 case 3:
1527 info->silicon_revision = 0;
1528 break;
1529 case 0:
1530 info->silicon_revision = 2;
1531 break;
1532 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001533 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001534 case 0x40:
1535 info->silicon_revision = 0;
1536 break;
1537 case 0x48:
1538 info->silicon_revision = 1;
1539 break;
1540 }
1541 }
1542}
1543
1544static void write_training_data(struct raminfo *info)
1545{
1546 int tm, channel, slot, rank, lane;
1547 if (info->revision < 8)
1548 return;
1549
1550 for (tm = 0; tm < 4; tm++)
1551 for (channel = 0; channel < NUM_CHANNELS; channel++)
1552 for (slot = 0; slot < NUM_SLOTS; slot++)
1553 for (rank = 0; rank < NUM_RANKS; rank++)
1554 for (lane = 0; lane < 9; lane++)
1555 write_500(info, channel,
1556 info->
1557 cached_training->
1558 lane_timings[tm]
1559 [channel][slot][rank]
1560 [lane],
1561 get_timing_register_addr
1562 (lane, tm, slot,
1563 rank), 9, 0);
1564 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1565 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1566}
1567
1568static void dump_timings(struct raminfo *info)
1569{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001570 int channel, slot, rank, lane, i;
1571 printk(BIOS_DEBUG, "Timings:\n");
1572 FOR_POPULATED_RANKS {
1573 printk(BIOS_DEBUG, "channel %d, slot %d, rank %d\n", channel,
1574 slot, rank);
1575 for (lane = 0; lane < 9; lane++) {
1576 printk(BIOS_DEBUG, "lane %d: ", lane);
1577 for (i = 0; i < 4; i++) {
1578 printk(BIOS_DEBUG, "%x (%x) ",
1579 read_500(info, channel,
1580 get_timing_register_addr
1581 (lane, i, slot, rank),
1582 9),
1583 info->training.
1584 lane_timings[i][channel][slot][rank]
1585 [lane]);
1586 }
1587 printk(BIOS_DEBUG, "\n");
1588 }
1589 }
1590 printk(BIOS_DEBUG, "[178] = %x (%x)\n", read_1d0(0x178, 7),
1591 info->training.reg_178);
1592 printk(BIOS_DEBUG, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
1593 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001594}
1595
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001596/* Read timings and other registers that need to be restored verbatim and
1597 put them to CBMEM.
1598 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001599static void save_timings(struct raminfo *info)
1600{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001601 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001602 int channel, slot, rank, lane, i;
1603
1604 train = info->training;
1605 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1606 for (i = 0; i < 4; i++)
1607 train.lane_timings[i][channel][slot][rank][lane] =
1608 read_500(info, channel,
1609 get_timing_register_addr(lane, i, slot,
1610 rank), 9);
1611 train.reg_178 = read_1d0(0x178, 7);
1612 train.reg_10b = read_1d0(0x10b, 6);
1613
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001614 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1615 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001616 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001617 train.reg274265[channel][0] = reg32 >> 16;
1618 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001619 train.reg274265[channel][2] =
1620 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001621 }
Felix Held04be2dd2018-07-29 04:53:22 +02001622 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1623 train.reg_6dc = MCHBAR32(0x6dc);
1624 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001625
1626 printk (BIOS_SPEW, "[6dc] = %x\n", train.reg_6dc);
1627 printk (BIOS_SPEW, "[6e8] = %x\n", train.reg_6e8);
1628
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001629 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001630 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1631 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001632}
1633
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001634static const struct ram_training *get_cached_training(void)
1635{
Arthur Heymansdc71e252018-01-29 10:14:48 +01001636 struct region_device rdev;
1637 if (mrc_cache_get_current(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1638 &rdev))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001639 return 0;
Arthur Heymansdc71e252018-01-29 10:14:48 +01001640 return (void *)rdev_mmap_full(&rdev);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001641}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001642
1643/* FIXME: add timeout. */
1644static void wait_heci_ready(void)
1645{
Felix Held04be2dd2018-07-29 04:53:22 +02001646 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1647 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001648 write32((DEFAULT_HECIBAR + 0x4),
1649 (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001650}
1651
1652/* FIXME: add timeout. */
1653static void wait_heci_cb_avail(int len)
1654{
1655 union {
1656 struct mei_csr csr;
1657 u32 raw;
1658 } csr;
1659
Felix Held22ca8cb2018-07-29 05:09:44 +02001660 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1661 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001662
1663 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001664 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001665 while (len >
1666 csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
Felix Held22ca8cb2018-07-29 05:09:44 +02001667 csr.csr.buffer_read_ptr))
1668 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001669}
1670
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001671static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001672{
1673 int len = (head->length + 3) / 4;
1674 int i;
1675
1676 wait_heci_cb_avail(len + 1);
1677
1678 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001679 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001680 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001681 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001682
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001683 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1684 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001685}
1686
1687static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001688send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001689{
1690 struct mei_header head;
1691 int maxlen;
1692
1693 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001694 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001695
1696 while (len) {
1697 int cur = len;
1698 if (cur > maxlen) {
1699 cur = maxlen;
1700 head.is_complete = 0;
1701 } else
1702 head.is_complete = 1;
1703 head.length = cur;
1704 head.reserved = 0;
1705 head.client_address = clientaddress;
1706 head.host_address = hostaddress;
1707 send_heci_packet(&head, (u32 *) msg);
1708 len -= cur;
1709 msg += cur;
1710 }
1711}
1712
1713/* FIXME: Add timeout. */
1714static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001715recv_heci_packet(struct raminfo *info, struct mei_header *head, u32 *packet,
1716 u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001717{
1718 union {
1719 struct mei_csr csr;
1720 u32 raw;
1721 } csr;
1722 int i = 0;
1723
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001724 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001725 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001726 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001727 }
Felix Held04be2dd2018-07-29 04:53:22 +02001728 while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr)
1729 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001730 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001731 if (!head->length) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001732 write32(DEFAULT_HECIBAR + 0x4,
1733 read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001734 *packet_size = 0;
1735 return 0;
1736 }
1737 if (head->length + 4 > 4 * csr.csr.buffer_depth
1738 || head->length > *packet_size) {
1739 *packet_size = 0;
1740 return -1;
1741 }
1742
1743 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001744 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Felix Held22ca8cb2018-07-29 05:09:44 +02001745 while (((head->length + 3) >> 2) >
1746 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr))
1747 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001748
1749 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001750 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001751 *packet_size = head->length;
1752 if (!csr.csr.ready)
1753 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001754 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001755 return 0;
1756}
1757
1758/* FIXME: Add timeout. */
1759static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001760recv_heci_message(struct raminfo *info, u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001761{
1762 struct mei_header head;
1763 int current_position;
1764
1765 current_position = 0;
1766 while (1) {
1767 u32 current_size;
1768 current_size = *message_size - current_position;
1769 if (recv_heci_packet
1770 (info, &head, message + (current_position >> 2),
1771 &current_size) == -1)
1772 break;
1773 if (!current_size)
1774 break;
1775 current_position += current_size;
1776 if (head.is_complete) {
1777 *message_size = current_position;
1778 return 0;
1779 }
1780
1781 if (current_position >= *message_size)
1782 break;
1783 }
1784 *message_size = 0;
1785 return -1;
1786}
1787
1788static void send_heci_uma_message(struct raminfo *info)
1789{
1790 struct uma_reply {
1791 u8 group_id;
1792 u8 command;
1793 u8 reserved;
1794 u8 result;
1795 u8 field2;
1796 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001797 } __packed reply;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001798 struct uma_message {
1799 u8 group_id;
1800 u8 cmd;
1801 u8 reserved;
1802 u8 result;
1803 u32 c2;
1804 u64 heci_uma_addr;
1805 u32 memory_reserved_for_heci_mb;
1806 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001807 } __packed msg = {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001808 0, MKHI_SET_UMA, 0, 0,
1809 0x82,
1810 info->heci_uma_addr, info->memory_reserved_for_heci_mb, 0};
1811 u32 reply_size;
1812
1813 send_heci_message((u8 *) & msg, sizeof(msg), 0, 7);
1814
1815 reply_size = sizeof(reply);
1816 if (recv_heci_message(info, (u32 *) & reply, &reply_size) == -1)
1817 return;
1818
1819 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1820 die("HECI init failed\n");
1821}
1822
1823static void setup_heci_uma(struct raminfo *info)
1824{
1825 u32 reg44;
1826
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001827 reg44 = pci_read_config32(HECIDEV, 0x44); // = 0x80010020
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001828 info->memory_reserved_for_heci_mb = 0;
1829 info->heci_uma_addr = 0;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001830 if (!((reg44 & 0x10000) && !(pci_read_config32(HECIDEV, 0x40) & 0x20)))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001831 return;
1832
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001833 info->heci_bar = pci_read_config32(HECIDEV, 0x10) & 0xFFFFFFF0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001834 info->memory_reserved_for_heci_mb = reg44 & 0x3f;
1835 info->heci_uma_addr =
1836 ((u64)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001837 ((((u64) pci_read_config16(NORTHBRIDGE, D0F0_TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001838 info->memory_reserved_for_heci_mb)) << 20;
1839
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001840 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001841 if (info->memory_reserved_for_heci_mb) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001842 write32(DEFAULT_DMIBAR + 0x14,
1843 read32(DEFAULT_DMIBAR + 0x14) & ~0x80);
1844 write32(DEFAULT_RCBA + 0x14,
1845 read32(DEFAULT_RCBA + 0x14) & ~0x80);
1846 write32(DEFAULT_DMIBAR + 0x20,
1847 read32(DEFAULT_DMIBAR + 0x20) & ~0x80);
1848 write32(DEFAULT_RCBA + 0x20,
1849 read32(DEFAULT_RCBA + 0x20) & ~0x80);
1850 write32(DEFAULT_DMIBAR + 0x2c,
1851 read32(DEFAULT_DMIBAR + 0x2c) & ~0x80);
1852 write32(DEFAULT_RCBA + 0x30,
1853 read32(DEFAULT_RCBA + 0x30) & ~0x80);
1854 write32(DEFAULT_DMIBAR + 0x38,
1855 read32(DEFAULT_DMIBAR + 0x38) & ~0x80);
1856 write32(DEFAULT_RCBA + 0x40,
1857 read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001858
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001859 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
1860 write32(DEFAULT_DMIBAR + 0x38, 0x87000080); // OK
Felix Held04be2dd2018-07-29 04:53:22 +02001861 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
1862 read16(DEFAULT_DMIBAR + 0x3e) & 2)
1863 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001864 }
1865
Felix Held04be2dd2018-07-29 04:53:22 +02001866 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001867
1868 send_heci_uma_message(info);
1869
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001870 pci_write_config32(HECIDEV, 0x10, 0x0);
1871 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001872
1873}
1874
1875static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1876{
1877 int ranks_in_channel;
1878 ranks_in_channel = info->populated_ranks[channel][0][0]
1879 + info->populated_ranks[channel][0][1]
1880 + info->populated_ranks[channel][1][0]
1881 + info->populated_ranks[channel][1][1];
1882
1883 /* empty channel */
1884 if (ranks_in_channel == 0)
1885 return 1;
1886
1887 if (ranks_in_channel != ranks)
1888 return 0;
1889 /* single slot */
1890 if (info->populated_ranks[channel][0][0] !=
1891 info->populated_ranks[channel][1][0])
1892 return 1;
1893 if (info->populated_ranks[channel][0][1] !=
1894 info->populated_ranks[channel][1][1])
1895 return 1;
1896 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1897 return 0;
1898 if (info->density[channel][0] != info->density[channel][1])
1899 return 0;
1900 return 1;
1901}
1902
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001903static void read_4090(struct raminfo *info)
1904{
1905 int i, channel, slot, rank, lane;
1906 for (i = 0; i < 2; i++)
1907 for (slot = 0; slot < NUM_SLOTS; slot++)
1908 for (rank = 0; rank < NUM_RANKS; rank++)
1909 for (lane = 0; lane < 9; lane++)
1910 info->training.
1911 lane_timings[0][i][slot][rank][lane]
1912 = 32;
1913
1914 for (i = 1; i < 4; i++)
1915 for (channel = 0; channel < NUM_CHANNELS; channel++)
1916 for (slot = 0; slot < NUM_SLOTS; slot++)
1917 for (rank = 0; rank < NUM_RANKS; rank++)
1918 for (lane = 0; lane < 9; lane++) {
1919 info->training.
1920 lane_timings[i][channel]
1921 [slot][rank][lane] =
1922 read_500(info, channel,
1923 get_timing_register_addr
1924 (lane, i, slot,
1925 rank), 9)
1926 + (i == 1) * 11; // !!!!
1927 }
1928
1929}
1930
1931static u32 get_etalon2(int flip, u32 addr)
1932{
1933 const u16 invmask[] = {
1934 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1935 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1936 };
1937 u32 ret;
1938 u32 comp4 = addr / 480;
1939 addr %= 480;
1940 u32 comp1 = addr & 0xf;
1941 u32 comp2 = (addr >> 4) & 1;
1942 u32 comp3 = addr >> 5;
1943
1944 if (comp4)
1945 ret = 0x1010101 << (comp4 - 1);
1946 else
1947 ret = 0;
1948 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1949 ret = ~ret;
1950
1951 return ret;
1952}
1953
1954static void disable_cache(void)
1955{
1956 msr_t msr = {.lo = 0, .hi = 0 };
1957
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001958 wrmsr(MTRR_PHYS_BASE(3), msr);
1959 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001960}
1961
1962static void enable_cache(unsigned int base, unsigned int size)
1963{
1964 msr_t msr;
1965 msr.lo = base | MTRR_TYPE_WRPROT;
1966 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001967 wrmsr(MTRR_PHYS_BASE(3), msr);
1968 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001969 & 0xffffffff);
1970 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001971 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001972}
1973
1974static void flush_cache(u32 start, u32 size)
1975{
1976 u32 end;
1977 u32 addr;
1978
1979 end = start + (ALIGN_DOWN(size + 4096, 4096));
1980 for (addr = start; addr < end; addr += 64)
1981 clflush(addr);
1982}
1983
1984static void clear_errors(void)
1985{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001986 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001987}
1988
1989static void write_testing(struct raminfo *info, int totalrank, int flip)
1990{
1991 int nwrites = 0;
1992 /* in 8-byte units. */
1993 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001994 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001995
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001996 base = (u8 *)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001997 for (offset = 0; offset < 9 * 480; offset += 2) {
1998 write32(base + offset * 8, get_etalon2(flip, offset));
1999 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
2000 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
2001 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
2002 nwrites += 4;
2003 if (nwrites >= 320) {
2004 clear_errors();
2005 nwrites = 0;
2006 }
2007 }
2008}
2009
2010static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
2011{
2012 u8 failmask = 0;
2013 int i;
2014 int comp1, comp2, comp3;
2015 u32 failxor[2] = { 0, 0 };
2016
2017 enable_cache((total_rank << 28), 1728 * 5 * 4);
2018
2019 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
2020 for (comp1 = 0; comp1 < 4; comp1++)
2021 for (comp2 = 0; comp2 < 60; comp2++) {
2022 u32 re[4];
2023 u32 curroffset =
2024 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
2025 read128((total_rank << 28) | (curroffset << 3),
2026 (u64 *) re);
2027 failxor[0] |=
2028 get_etalon2(flip, curroffset) ^ re[0];
2029 failxor[1] |=
2030 get_etalon2(flip, curroffset) ^ re[1];
2031 failxor[0] |=
2032 get_etalon2(flip, curroffset | 1) ^ re[2];
2033 failxor[1] |=
2034 get_etalon2(flip, curroffset | 1) ^ re[3];
2035 }
2036 for (i = 0; i < 8; i++)
2037 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2038 failmask |= 1 << i;
2039 }
2040 disable_cache();
2041 flush_cache((total_rank << 28), 1728 * 5 * 4);
2042 return failmask;
2043}
2044
2045const u32 seed1[0x18] = {
2046 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2047 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2048 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2049 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2050 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2051 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2052};
2053
2054static u32 get_seed2(int a, int b)
2055{
2056 const u32 seed2[5] = {
2057 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2058 0x5b6db6db,
2059 };
2060 u32 r;
2061 r = seed2[(a + (a >= 10)) / 5];
2062 return b ? ~r : r;
2063}
2064
2065static int make_shift(int comp2, int comp5, int x)
2066{
2067 const u8 seed3[32] = {
2068 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2069 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2070 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2071 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2072 };
2073
2074 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2075}
2076
2077static u32 get_etalon(int flip, u32 addr)
2078{
2079 u32 mask_byte = 0;
2080 int comp1 = (addr >> 1) & 1;
2081 int comp2 = (addr >> 3) & 0x1f;
2082 int comp3 = (addr >> 8) & 0xf;
2083 int comp4 = (addr >> 12) & 0xf;
2084 int comp5 = (addr >> 16) & 0x1f;
2085 u32 mask_bit = ~(0x10001 << comp3);
2086 u32 part1;
2087 u32 part2;
2088 int byte;
2089
2090 part2 =
2091 ((seed1[comp5] >>
2092 make_shift(comp2, comp5,
2093 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2094 part1 =
2095 ((seed1[comp5] >>
2096 make_shift(comp2, comp5,
2097 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2098
2099 for (byte = 0; byte < 4; byte++)
2100 if ((get_seed2(comp5, comp4) >>
2101 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2102 mask_byte |= 0xff << (8 * byte);
2103
2104 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2105 (comp3 + 16));
2106}
2107
2108static void
2109write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2110 char flip)
2111{
2112 int i;
2113 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002114 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2115 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002116}
2117
2118static u8
2119check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2120 char flip)
2121{
2122 u8 failmask = 0;
2123 u32 failxor[2];
2124 int i;
2125 int comp1, comp2, comp3;
2126
2127 failxor[0] = 0;
2128 failxor[1] = 0;
2129
2130 enable_cache(totalrank << 28, 134217728);
2131 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2132 for (comp1 = 0; comp1 < 16; comp1++)
2133 for (comp2 = 0; comp2 < 64; comp2++) {
2134 u32 addr =
2135 (totalrank << 28) | (region << 25) | (block
2136 << 16)
2137 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2138 2);
2139 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002140 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002141 }
2142 for (i = 0; i < 8; i++)
2143 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2144 failmask |= 1 << i;
2145 }
2146 disable_cache();
2147 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2148 return failmask;
2149}
2150
2151static int check_bounded(unsigned short *vals, u16 bound)
2152{
2153 int i;
2154
2155 for (i = 0; i < 8; i++)
2156 if (vals[i] < bound)
2157 return 0;
2158 return 1;
2159}
2160
2161enum state {
2162 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2163};
2164
2165static int validate_state(enum state *in)
2166{
2167 int i;
2168 for (i = 0; i < 8; i++)
2169 if (in[i] != COMPLETE)
2170 return 0;
2171 return 1;
2172}
2173
2174static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002175do_fsm(enum state *state, u16 *counter,
2176 u8 fail_mask, int margin, int uplimit,
2177 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002178{
2179 int lane;
2180
2181 for (lane = 0; lane < 8; lane++) {
2182 int is_fail = (fail_mask >> lane) & 1;
2183 switch (state[lane]) {
2184 case BEFORE_USABLE:
2185 if (!is_fail) {
2186 counter[lane] = 1;
2187 state[lane] = AT_USABLE;
2188 break;
2189 }
2190 counter[lane] = 0;
2191 state[lane] = BEFORE_USABLE;
2192 break;
2193 case AT_USABLE:
2194 if (!is_fail) {
2195 ++counter[lane];
2196 if (counter[lane] >= margin) {
2197 state[lane] = AT_MARGIN;
2198 res_low[lane] = val - margin + 1;
2199 break;
2200 }
2201 state[lane] = 1;
2202 break;
2203 }
2204 counter[lane] = 0;
2205 state[lane] = BEFORE_USABLE;
2206 break;
2207 case AT_MARGIN:
2208 if (is_fail) {
2209 state[lane] = COMPLETE;
2210 res_high[lane] = val - 1;
2211 } else {
2212 counter[lane]++;
2213 state[lane] = AT_MARGIN;
2214 if (val == uplimit) {
2215 state[lane] = COMPLETE;
2216 res_high[lane] = uplimit;
2217 }
2218 }
2219 break;
2220 case COMPLETE:
2221 break;
2222 }
2223 }
2224}
2225
2226static void
2227train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2228 u8 total_rank, u8 reg_178, int first_run, int niter,
2229 timing_bounds_t * timings)
2230{
2231 int lane;
2232 enum state state[8];
2233 u16 count[8];
2234 u8 lower_usable[8];
2235 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002236 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002237 u8 secondary_total_rank;
2238 u8 reg1b3;
2239
2240 if (info->populated_ranks_mask[1]) {
2241 if (channel == 1)
2242 secondary_total_rank =
2243 info->populated_ranks[1][0][0] +
2244 info->populated_ranks[1][0][1]
2245 + info->populated_ranks[1][1][0] +
2246 info->populated_ranks[1][1][1];
2247 else
2248 secondary_total_rank = 0;
2249 } else
2250 secondary_total_rank = total_rank;
2251
2252 {
2253 int i;
2254 for (i = 0; i < 8; i++)
2255 state[i] = BEFORE_USABLE;
2256 }
2257
2258 if (!first_run) {
2259 int is_all_ok = 1;
2260 for (lane = 0; lane < 8; lane++)
2261 if (timings[reg_178][channel][slot][rank][lane].
2262 smallest ==
2263 timings[reg_178][channel][slot][rank][lane].
2264 largest) {
2265 timings[reg_178][channel][slot][rank][lane].
2266 smallest = 0;
2267 timings[reg_178][channel][slot][rank][lane].
2268 largest = 0;
2269 is_all_ok = 0;
2270 }
2271 if (is_all_ok) {
2272 int i;
2273 for (i = 0; i < 8; i++)
2274 state[i] = COMPLETE;
2275 }
2276 }
2277
2278 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2279 u8 failmask = 0;
2280 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2281 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2282 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002283 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002284 do_fsm(state, count, failmask, 5, 47, lower_usable,
2285 upper_usable, reg1b3);
2286 }
2287
2288 if (reg1b3) {
2289 write_1d0(0, 0x1b3, 6, 1);
2290 write_1d0(0, 0x1a3, 6, 1);
2291 for (lane = 0; lane < 8; lane++) {
2292 if (state[lane] == COMPLETE) {
2293 timings[reg_178][channel][slot][rank][lane].
2294 smallest =
2295 lower_usable[lane] +
2296 (info->training.
2297 lane_timings[0][channel][slot][rank][lane]
2298 & 0x3F) - 32;
2299 timings[reg_178][channel][slot][rank][lane].
2300 largest =
2301 upper_usable[lane] +
2302 (info->training.
2303 lane_timings[0][channel][slot][rank][lane]
2304 & 0x3F) - 32;
2305 }
2306 }
2307 }
2308
2309 if (!first_run) {
2310 for (lane = 0; lane < 8; lane++)
2311 if (state[lane] == COMPLETE) {
2312 write_500(info, channel,
2313 timings[reg_178][channel][slot][rank]
2314 [lane].smallest,
2315 get_timing_register_addr(lane, 0,
2316 slot, rank),
2317 9, 1);
2318 write_500(info, channel,
2319 timings[reg_178][channel][slot][rank]
2320 [lane].smallest +
2321 info->training.
2322 lane_timings[1][channel][slot][rank]
2323 [lane]
2324 -
2325 info->training.
2326 lane_timings[0][channel][slot][rank]
2327 [lane], get_timing_register_addr(lane,
2328 1,
2329 slot,
2330 rank),
2331 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002332 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002333 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002334 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002335
2336 do {
2337 u8 failmask = 0;
2338 int i;
2339 for (i = 0; i < niter; i++) {
2340 if (failmask == 0xFF)
2341 break;
2342 failmask |=
2343 check_testing_type2(info, total_rank, 2, i,
2344 0);
2345 failmask |=
2346 check_testing_type2(info, total_rank, 3, i,
2347 1);
2348 }
Felix Held04be2dd2018-07-29 04:53:22 +02002349 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002350 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002351 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002352 if ((1 << lane) & failmask) {
2353 if (timings[reg_178][channel]
2354 [slot][rank][lane].
2355 largest <=
2356 timings[reg_178][channel]
2357 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002358 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002359 [lane] = -1;
2360 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002361 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002362 [lane] = 0;
2363 timings[reg_178]
2364 [channel][slot]
2365 [rank][lane].
2366 smallest++;
2367 write_500(info, channel,
2368 timings
2369 [reg_178]
2370 [channel]
2371 [slot][rank]
2372 [lane].
2373 smallest,
2374 get_timing_register_addr
2375 (lane, 0,
2376 slot, rank),
2377 9, 1);
2378 write_500(info, channel,
2379 timings
2380 [reg_178]
2381 [channel]
2382 [slot][rank]
2383 [lane].
2384 smallest +
2385 info->
2386 training.
2387 lane_timings
2388 [1][channel]
2389 [slot][rank]
2390 [lane]
2391 -
2392 info->
2393 training.
2394 lane_timings
2395 [0][channel]
2396 [slot][rank]
2397 [lane],
2398 get_timing_register_addr
2399 (lane, 1,
2400 slot, rank),
2401 9, 1);
2402 }
2403 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002404 num_successfully_checked[lane]
2405 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002406 }
2407 }
Felix Held04be2dd2018-07-29 04:53:22 +02002408 while (!check_bounded(num_successfully_checked, 2))
2409 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002410
2411 for (lane = 0; lane < 8; lane++)
2412 if (state[lane] == COMPLETE) {
2413 write_500(info, channel,
2414 timings[reg_178][channel][slot][rank]
2415 [lane].largest,
2416 get_timing_register_addr(lane, 0,
2417 slot, rank),
2418 9, 1);
2419 write_500(info, channel,
2420 timings[reg_178][channel][slot][rank]
2421 [lane].largest +
2422 info->training.
2423 lane_timings[1][channel][slot][rank]
2424 [lane]
2425 -
2426 info->training.
2427 lane_timings[0][channel][slot][rank]
2428 [lane], get_timing_register_addr(lane,
2429 1,
2430 slot,
2431 rank),
2432 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002433 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002434 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002435 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002436
2437 do {
2438 int failmask = 0;
2439 int i;
2440 for (i = 0; i < niter; i++) {
2441 if (failmask == 0xFF)
2442 break;
2443 failmask |=
2444 check_testing_type2(info, total_rank, 2, i,
2445 0);
2446 failmask |=
2447 check_testing_type2(info, total_rank, 3, i,
2448 1);
2449 }
2450
Felix Held04be2dd2018-07-29 04:53:22 +02002451 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002452 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002453 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002454 if ((1 << lane) & failmask) {
2455 if (timings[reg_178][channel]
2456 [slot][rank][lane].
2457 largest <=
2458 timings[reg_178][channel]
2459 [slot][rank][lane].
2460 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002461 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002462 [lane] = -1;
2463 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002464 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002465 [lane] = 0;
2466 timings[reg_178]
2467 [channel][slot]
2468 [rank][lane].
2469 largest--;
2470 write_500(info, channel,
2471 timings
2472 [reg_178]
2473 [channel]
2474 [slot][rank]
2475 [lane].
2476 largest,
2477 get_timing_register_addr
2478 (lane, 0,
2479 slot, rank),
2480 9, 1);
2481 write_500(info, channel,
2482 timings
2483 [reg_178]
2484 [channel]
2485 [slot][rank]
2486 [lane].
2487 largest +
2488 info->
2489 training.
2490 lane_timings
2491 [1][channel]
2492 [slot][rank]
2493 [lane]
2494 -
2495 info->
2496 training.
2497 lane_timings
2498 [0][channel]
2499 [slot][rank]
2500 [lane],
2501 get_timing_register_addr
2502 (lane, 1,
2503 slot, rank),
2504 9, 1);
2505 }
2506 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002507 num_successfully_checked[lane]
2508 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002509 }
2510 }
2511 }
Felix Held04be2dd2018-07-29 04:53:22 +02002512 while (!check_bounded(num_successfully_checked, 3))
2513 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002514
2515 for (lane = 0; lane < 8; lane++) {
2516 write_500(info, channel,
2517 info->training.
2518 lane_timings[0][channel][slot][rank][lane],
2519 get_timing_register_addr(lane, 0, slot, rank),
2520 9, 1);
2521 write_500(info, channel,
2522 info->training.
2523 lane_timings[1][channel][slot][rank][lane],
2524 get_timing_register_addr(lane, 1, slot, rank),
2525 9, 1);
2526 if (timings[reg_178][channel][slot][rank][lane].
2527 largest <=
2528 timings[reg_178][channel][slot][rank][lane].
2529 smallest) {
2530 timings[reg_178][channel][slot][rank][lane].
2531 largest = 0;
2532 timings[reg_178][channel][slot][rank][lane].
2533 smallest = 0;
2534 }
2535 }
2536 }
2537}
2538
2539static void set_10b(struct raminfo *info, u8 val)
2540{
2541 int channel;
2542 int slot, rank;
2543 int lane;
2544
2545 if (read_1d0(0x10b, 6) == val)
2546 return;
2547
2548 write_1d0(val, 0x10b, 6, 1);
2549
2550 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2551 u16 reg_500;
2552 reg_500 = read_500(info, channel,
2553 get_timing_register_addr(lane, 0, slot,
2554 rank), 9);
2555 if (val == 1) {
2556 if (lut16[info->clock_speed_index] <= reg_500)
2557 reg_500 -= lut16[info->clock_speed_index];
2558 else
2559 reg_500 = 0;
2560 } else {
2561 reg_500 += lut16[info->clock_speed_index];
2562 }
2563 write_500(info, channel, reg_500,
2564 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2565 }
2566}
2567
2568static void set_ecc(int onoff)
2569{
2570 int channel;
2571 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2572 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002573 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002574 if (onoff)
2575 t |= 1;
2576 else
2577 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002578 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002579 }
2580}
2581
2582static void set_178(u8 val)
2583{
2584 if (val >= 31)
2585 val = val - 31;
2586 else
2587 val = 63 - val;
2588
2589 write_1d0(2 * val, 0x178, 7, 1);
2590}
2591
2592static void
2593write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2594 int type)
2595{
2596 int lane;
2597
2598 for (lane = 0; lane < 8; lane++)
2599 write_500(info, channel,
2600 info->training.
2601 lane_timings[type][channel][slot][rank][lane],
2602 get_timing_register_addr(lane, type, slot, rank), 9,
2603 0);
2604}
2605
2606static void
2607try_timing_offsets(struct raminfo *info, int channel,
2608 int slot, int rank, int totalrank)
2609{
2610 u16 count[8];
2611 enum state state[8];
2612 u8 lower_usable[8], upper_usable[8];
2613 int lane;
2614 int i;
2615 int flip = 1;
2616 int timing_offset;
2617
2618 for (i = 0; i < 8; i++)
2619 state[i] = BEFORE_USABLE;
2620
2621 memset(count, 0, sizeof(count));
2622
2623 for (lane = 0; lane < 8; lane++)
2624 write_500(info, channel,
2625 info->training.
2626 lane_timings[2][channel][slot][rank][lane] + 32,
2627 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2628
2629 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2630 timing_offset++) {
2631 u8 failmask;
2632 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2633 failmask = 0;
2634 for (i = 0; i < 2 && failmask != 0xff; i++) {
2635 flip = !flip;
2636 write_testing(info, totalrank, flip);
2637 failmask |= check_testing(info, totalrank, flip);
2638 }
2639 do_fsm(state, count, failmask, 10, 63, lower_usable,
2640 upper_usable, timing_offset);
2641 }
2642 write_1d0(0, 0x1bb, 6, 1);
2643 dump_timings(info);
2644 if (!validate_state(state))
2645 die("Couldn't discover DRAM timings (1)\n");
2646
2647 for (lane = 0; lane < 8; lane++) {
2648 u8 bias = 0;
2649
2650 if (info->silicon_revision) {
2651 int usable_length;
2652
2653 usable_length = upper_usable[lane] - lower_usable[lane];
2654 if (usable_length >= 20) {
2655 bias = usable_length / 2 - 10;
2656 if (bias >= 2)
2657 bias = 2;
2658 }
2659 }
2660 write_500(info, channel,
2661 info->training.
2662 lane_timings[2][channel][slot][rank][lane] +
2663 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2664 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2665 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2666 info->training.lane_timings[2][channel][slot][rank][lane] +
2667 lower_usable[lane];
2668 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2669 info->training.lane_timings[2][channel][slot][rank][lane] +
2670 upper_usable[lane];
2671 info->training.timing2_offset[channel][slot][rank][lane] =
2672 info->training.lane_timings[2][channel][slot][rank][lane];
2673 }
2674}
2675
2676static u8
2677choose_training(struct raminfo *info, int channel, int slot, int rank,
2678 int lane, timing_bounds_t * timings, u8 center_178)
2679{
2680 u16 central_weight;
2681 u16 side_weight;
2682 unsigned int sum = 0, count = 0;
2683 u8 span;
2684 u8 lower_margin, upper_margin;
2685 u8 reg_178;
2686 u8 result;
2687
2688 span = 12;
2689 central_weight = 20;
2690 side_weight = 20;
2691 if (info->silicon_revision == 1 && channel == 1) {
2692 central_weight = 5;
2693 side_weight = 20;
2694 if ((info->
2695 populated_ranks_mask[1] ^ (info->
2696 populated_ranks_mask[1] >> 2)) &
2697 1)
2698 span = 18;
2699 }
2700 if ((info->populated_ranks_mask[0] & 5) == 5) {
2701 central_weight = 20;
2702 side_weight = 20;
2703 }
2704 if (info->clock_speed_index >= 2
2705 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2706 if (info->silicon_revision == 1) {
2707 switch (channel) {
2708 case 0:
2709 if (lane == 1) {
2710 central_weight = 10;
2711 side_weight = 20;
2712 }
2713 break;
2714 case 1:
2715 if (lane == 6) {
2716 side_weight = 5;
2717 central_weight = 20;
2718 }
2719 break;
2720 }
2721 }
2722 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2723 side_weight = 5;
2724 central_weight = 20;
2725 }
2726 }
2727 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2728 reg_178 += span) {
2729 u8 smallest;
2730 u8 largest;
2731 largest = timings[reg_178][channel][slot][rank][lane].largest;
2732 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2733 if (largest - smallest + 1 >= 5) {
2734 unsigned int weight;
2735 if (reg_178 == center_178)
2736 weight = central_weight;
2737 else
2738 weight = side_weight;
2739 sum += weight * (largest + smallest);
2740 count += weight;
2741 }
2742 }
2743 dump_timings(info);
2744 if (count == 0)
2745 die("Couldn't discover DRAM timings (2)\n");
2746 result = sum / (2 * count);
2747 lower_margin =
2748 result - timings[center_178][channel][slot][rank][lane].smallest;
2749 upper_margin =
2750 timings[center_178][channel][slot][rank][lane].largest - result;
2751 if (upper_margin < 10 && lower_margin > 10)
2752 result -= min(lower_margin - 10, 10 - upper_margin);
2753 if (upper_margin > 10 && lower_margin < 10)
2754 result += min(upper_margin - 10, 10 - lower_margin);
2755 return result;
2756}
2757
2758#define STANDARD_MIN_MARGIN 5
2759
2760static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2761{
2762 u16 margin[64];
2763 int lane, rank, slot, channel;
2764 u8 reg178;
2765 int count = 0, sum = 0;
2766
2767 for (reg178 = reg178_min[info->clock_speed_index];
2768 reg178 < reg178_max[info->clock_speed_index];
2769 reg178 += reg178_step[info->clock_speed_index]) {
2770 margin[reg178] = -1;
2771 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2772 int curmargin =
2773 timings[reg178][channel][slot][rank][lane].largest -
2774 timings[reg178][channel][slot][rank][lane].
2775 smallest + 1;
2776 if (curmargin < margin[reg178])
2777 margin[reg178] = curmargin;
2778 }
2779 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2780 u16 weight;
2781 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2782 sum += weight * reg178;
2783 count += weight;
2784 }
2785 }
2786 dump_timings(info);
2787 if (count == 0)
2788 die("Couldn't discover DRAM timings (3)\n");
2789
2790 u8 threshold;
2791
2792 for (threshold = 30; threshold >= 5; threshold--) {
2793 int usable_length = 0;
2794 int smallest_fount = 0;
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 if (margin[reg178] >= threshold) {
2799 usable_length +=
2800 reg178_step[info->clock_speed_index];
2801 info->training.reg178_largest =
2802 reg178 -
2803 2 * reg178_step[info->clock_speed_index];
2804
2805 if (!smallest_fount) {
2806 smallest_fount = 1;
2807 info->training.reg178_smallest =
2808 reg178 +
2809 reg178_step[info->
2810 clock_speed_index];
2811 }
2812 }
2813 if (usable_length >= 0x21)
2814 break;
2815 }
2816
2817 return sum / count;
2818}
2819
2820static int check_cached_sanity(struct raminfo *info)
2821{
2822 int lane;
2823 int slot, rank;
2824 int channel;
2825
2826 if (!info->cached_training)
2827 return 0;
2828
2829 for (channel = 0; channel < NUM_CHANNELS; channel++)
2830 for (slot = 0; slot < NUM_SLOTS; slot++)
2831 for (rank = 0; rank < NUM_RANKS; rank++)
2832 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2833 u16 cached_value, estimation_value;
2834 cached_value =
2835 info->cached_training->
2836 lane_timings[1][channel][slot][rank]
2837 [lane];
2838 if (cached_value >= 0x18
2839 && cached_value <= 0x1E7) {
2840 estimation_value =
2841 info->training.
2842 lane_timings[1][channel]
2843 [slot][rank][lane];
2844 if (estimation_value <
2845 cached_value - 24)
2846 return 0;
2847 if (estimation_value >
2848 cached_value + 24)
2849 return 0;
2850 }
2851 }
2852 return 1;
2853}
2854
2855static int try_cached_training(struct raminfo *info)
2856{
2857 u8 saved_243[2];
2858 u8 tm;
2859
2860 int channel, slot, rank, lane;
2861 int flip = 1;
2862 int i, j;
2863
2864 if (!check_cached_sanity(info))
2865 return 0;
2866
2867 info->training.reg178_center = info->cached_training->reg178_center;
2868 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2869 info->training.reg178_largest = info->cached_training->reg178_largest;
2870 memcpy(&info->training.timing_bounds,
2871 &info->cached_training->timing_bounds,
2872 sizeof(info->training.timing_bounds));
2873 memcpy(&info->training.timing_offset,
2874 &info->cached_training->timing_offset,
2875 sizeof(info->training.timing_offset));
2876
2877 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002878 saved_243[0] = MCHBAR8(0x243);
2879 saved_243[1] = MCHBAR8(0x643);
2880 MCHBAR8(0x243) = saved_243[0] | 2;
2881 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002882 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002883 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002884 if (read_1d0(0x10b, 6) & 1)
2885 set_10b(info, 0);
2886 for (tm = 0; tm < 2; tm++) {
2887 int totalrank;
2888
2889 set_178(tm ? info->cached_training->reg178_largest : info->
2890 cached_training->reg178_smallest);
2891
2892 totalrank = 0;
2893 /* Check timing ranges. With i == 0 we check smallest one and with
2894 i == 1 the largest bound. With j == 0 we check that on the bound
2895 it still works whereas with j == 1 we check that just outside of
2896 bound we fail.
2897 */
2898 FOR_POPULATED_RANKS_BACKWARDS {
2899 for (i = 0; i < 2; i++) {
2900 for (lane = 0; lane < 8; lane++) {
2901 write_500(info, channel,
2902 info->cached_training->
2903 timing2_bounds[channel][slot]
2904 [rank][lane][i],
2905 get_timing_register_addr(lane,
2906 3,
2907 slot,
2908 rank),
2909 9, 1);
2910
2911 if (!i)
2912 write_500(info, channel,
2913 info->
2914 cached_training->
2915 timing2_offset
2916 [channel][slot][rank]
2917 [lane],
2918 get_timing_register_addr
2919 (lane, 2, slot, rank),
2920 9, 1);
2921 write_500(info, channel,
2922 i ? info->cached_training->
2923 timing_bounds[tm][channel]
2924 [slot][rank][lane].
2925 largest : info->
2926 cached_training->
2927 timing_bounds[tm][channel]
2928 [slot][rank][lane].smallest,
2929 get_timing_register_addr(lane,
2930 0,
2931 slot,
2932 rank),
2933 9, 1);
2934 write_500(info, channel,
2935 info->cached_training->
2936 timing_offset[channel][slot]
2937 [rank][lane] +
2938 (i ? info->cached_training->
2939 timing_bounds[tm][channel]
2940 [slot][rank][lane].
2941 largest : info->
2942 cached_training->
2943 timing_bounds[tm][channel]
2944 [slot][rank][lane].
2945 smallest) - 64,
2946 get_timing_register_addr(lane,
2947 1,
2948 slot,
2949 rank),
2950 9, 1);
2951 }
2952 for (j = 0; j < 2; j++) {
2953 u8 failmask;
2954 u8 expected_failmask;
2955 char reg1b3;
2956
2957 reg1b3 = (j == 1) + 4;
2958 reg1b3 =
2959 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2960 write_1d0(reg1b3, 0x1bb, 6, 1);
2961 write_1d0(reg1b3, 0x1b3, 6, 1);
2962 write_1d0(reg1b3, 0x1a3, 6, 1);
2963
2964 flip = !flip;
2965 write_testing(info, totalrank, flip);
2966 failmask =
2967 check_testing(info, totalrank,
2968 flip);
2969 expected_failmask =
2970 j == 0 ? 0x00 : 0xff;
2971 if (failmask != expected_failmask)
2972 goto fail;
2973 }
2974 }
2975 totalrank++;
2976 }
2977 }
2978
2979 set_178(info->cached_training->reg178_center);
2980 if (info->use_ecc)
2981 set_ecc(1);
2982 write_training_data(info);
2983 write_1d0(0, 322, 3, 1);
2984 info->training = *info->cached_training;
2985
2986 write_1d0(0, 0x1bb, 6, 1);
2987 write_1d0(0, 0x1b3, 6, 1);
2988 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002989 MCHBAR8(0x243) = saved_243[0];
2990 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002991
2992 return 1;
2993
2994fail:
2995 FOR_POPULATED_RANKS {
2996 write_500_timings_type(info, channel, slot, rank, 1);
2997 write_500_timings_type(info, channel, slot, rank, 2);
2998 write_500_timings_type(info, channel, slot, rank, 3);
2999 }
3000
3001 write_1d0(0, 0x1bb, 6, 1);
3002 write_1d0(0, 0x1b3, 6, 1);
3003 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003004 MCHBAR8(0x243) = saved_243[0];
3005 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003006
3007 return 0;
3008}
3009
3010static void do_ram_training(struct raminfo *info)
3011{
3012 u8 saved_243[2];
3013 int totalrank = 0;
3014 u8 reg_178;
3015 int niter;
3016
Matthias Gazzaridfa51252018-05-19 00:44:20 +02003017 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003018 int lane, rank, slot, channel;
3019 u8 reg178_center;
3020
3021 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003022 saved_243[0] = MCHBAR8(0x243);
3023 saved_243[1] = MCHBAR8(0x643);
3024 MCHBAR8(0x243) = saved_243[0] | 2;
3025 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003026 switch (info->clock_speed_index) {
3027 case 0:
3028 niter = 5;
3029 break;
3030 case 1:
3031 niter = 10;
3032 break;
3033 default:
3034 niter = 19;
3035 break;
3036 }
3037 set_ecc(0);
3038
3039 FOR_POPULATED_RANKS_BACKWARDS {
3040 int i;
3041
3042 write_500_timings_type(info, channel, slot, rank, 0);
3043
3044 write_testing(info, totalrank, 0);
3045 for (i = 0; i < niter; i++) {
3046 write_testing_type2(info, totalrank, 2, i, 0);
3047 write_testing_type2(info, totalrank, 3, i, 1);
3048 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003049 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003050 totalrank++;
3051 }
3052
3053 if (reg178_min[info->clock_speed_index] <
3054 reg178_max[info->clock_speed_index])
3055 memset(timings[reg178_min[info->clock_speed_index]], 0,
3056 sizeof(timings[0]) *
3057 (reg178_max[info->clock_speed_index] -
3058 reg178_min[info->clock_speed_index]));
3059 for (reg_178 = reg178_min[info->clock_speed_index];
3060 reg_178 < reg178_max[info->clock_speed_index];
3061 reg_178 += reg178_step[info->clock_speed_index]) {
3062 totalrank = 0;
3063 set_178(reg_178);
3064 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3065 for (slot = 0; slot < NUM_SLOTS; slot++)
3066 for (rank = 0; rank < NUM_RANKS; rank++) {
3067 memset(&timings[reg_178][channel][slot]
3068 [rank][0].smallest, 0, 16);
3069 if (info->
3070 populated_ranks[channel][slot]
3071 [rank]) {
3072 train_ram_at_178(info, channel,
3073 slot, rank,
3074 totalrank,
3075 reg_178, 1,
3076 niter,
3077 timings);
3078 totalrank++;
3079 }
3080 }
3081 }
3082
3083 reg178_center = choose_reg178(info, timings);
3084
3085 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3086 info->training.timing_bounds[0][channel][slot][rank][lane].
3087 smallest =
3088 timings[info->training.
3089 reg178_smallest][channel][slot][rank][lane].
3090 smallest;
3091 info->training.timing_bounds[0][channel][slot][rank][lane].
3092 largest =
3093 timings[info->training.
3094 reg178_smallest][channel][slot][rank][lane].largest;
3095 info->training.timing_bounds[1][channel][slot][rank][lane].
3096 smallest =
3097 timings[info->training.
3098 reg178_largest][channel][slot][rank][lane].smallest;
3099 info->training.timing_bounds[1][channel][slot][rank][lane].
3100 largest =
3101 timings[info->training.
3102 reg178_largest][channel][slot][rank][lane].largest;
3103 info->training.timing_offset[channel][slot][rank][lane] =
3104 info->training.lane_timings[1][channel][slot][rank][lane]
3105 -
3106 info->training.lane_timings[0][channel][slot][rank][lane] +
3107 64;
3108 }
3109
3110 if (info->silicon_revision == 1
3111 && (info->
3112 populated_ranks_mask[1] ^ (info->
3113 populated_ranks_mask[1] >> 2)) & 1) {
3114 int ranks_after_channel1;
3115
3116 totalrank = 0;
3117 for (reg_178 = reg178_center - 18;
3118 reg_178 <= reg178_center + 18; reg_178 += 18) {
3119 totalrank = 0;
3120 set_178(reg_178);
3121 for (slot = 0; slot < NUM_SLOTS; slot++)
3122 for (rank = 0; rank < NUM_RANKS; rank++) {
3123 if (info->
3124 populated_ranks[1][slot][rank]) {
3125 train_ram_at_178(info, 1, slot,
3126 rank,
3127 totalrank,
3128 reg_178, 0,
3129 niter,
3130 timings);
3131 totalrank++;
3132 }
3133 }
3134 }
3135 ranks_after_channel1 = totalrank;
3136
3137 for (reg_178 = reg178_center - 12;
3138 reg_178 <= reg178_center + 12; reg_178 += 12) {
3139 totalrank = ranks_after_channel1;
3140 set_178(reg_178);
3141 for (slot = 0; slot < NUM_SLOTS; slot++)
3142 for (rank = 0; rank < NUM_RANKS; rank++)
3143 if (info->
3144 populated_ranks[0][slot][rank]) {
3145 train_ram_at_178(info, 0, slot,
3146 rank,
3147 totalrank,
3148 reg_178, 0,
3149 niter,
3150 timings);
3151 totalrank++;
3152 }
3153
3154 }
3155 } else {
3156 for (reg_178 = reg178_center - 12;
3157 reg_178 <= reg178_center + 12; reg_178 += 12) {
3158 totalrank = 0;
3159 set_178(reg_178);
3160 FOR_POPULATED_RANKS_BACKWARDS {
3161 train_ram_at_178(info, channel, slot, rank,
3162 totalrank, reg_178, 0, niter,
3163 timings);
3164 totalrank++;
3165 }
3166 }
3167 }
3168
3169 set_178(reg178_center);
3170 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3171 u16 tm0;
3172
3173 tm0 =
3174 choose_training(info, channel, slot, rank, lane, timings,
3175 reg178_center);
3176 write_500(info, channel, tm0,
3177 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3178 write_500(info, channel,
3179 tm0 +
3180 info->training.
3181 lane_timings[1][channel][slot][rank][lane] -
3182 info->training.
3183 lane_timings[0][channel][slot][rank][lane],
3184 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3185 }
3186
3187 totalrank = 0;
3188 FOR_POPULATED_RANKS_BACKWARDS {
3189 try_timing_offsets(info, channel, slot, rank, totalrank);
3190 totalrank++;
3191 }
Felix Held04be2dd2018-07-29 04:53:22 +02003192 MCHBAR8(0x243) = saved_243[0];
3193 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003194 write_1d0(0, 0x142, 3, 1);
3195 info->training.reg178_center = reg178_center;
3196}
3197
3198static void ram_training(struct raminfo *info)
3199{
3200 u16 saved_fc4;
3201
Felix Held04be2dd2018-07-29 04:53:22 +02003202 saved_fc4 = MCHBAR16(0xfc4);
3203 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003204
3205 if (info->revision >= 8)
3206 read_4090(info);
3207
3208 if (!try_cached_training(info))
3209 do_ram_training(info);
3210 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3211 && info->clock_speed_index < 2)
3212 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003213 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003214}
3215
3216static unsigned gcd(unsigned a, unsigned b)
3217{
3218 unsigned t;
3219 if (a > b) {
3220 t = a;
3221 a = b;
3222 b = t;
3223 }
3224 /* invariant a < b. */
3225 while (a) {
3226 t = b % a;
3227 b = a;
3228 a = t;
3229 }
3230 return b;
3231}
3232
3233static inline int div_roundup(int a, int b)
3234{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003235 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003236}
3237
3238static unsigned lcm(unsigned a, unsigned b)
3239{
3240 return (a * b) / gcd(a, b);
3241}
3242
3243struct stru1 {
3244 u8 freqs_reversed;
3245 u8 freq_diff_reduced;
3246 u8 freq_min_reduced;
3247 u8 divisor_f4_to_fmax;
3248 u8 divisor_f3_to_fmax;
3249 u8 freq4_to_max_remainder;
3250 u8 freq3_to_2_remainder;
3251 u8 freq3_to_2_remaindera;
3252 u8 freq4_to_2_remainder;
3253 int divisor_f3_to_f1, divisor_f4_to_f2;
3254 int common_time_unit_ps;
3255 int freq_max_reduced;
3256};
3257
3258static void
3259compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3260 int num_cycles_2, int num_cycles_1, int round_it,
3261 int add_freqs, struct stru1 *result)
3262{
3263 int g;
3264 int common_time_unit_ps;
3265 int freq1_reduced, freq2_reduced;
3266 int freq_min_reduced;
3267 int freq_max_reduced;
3268 int freq3, freq4;
3269
3270 g = gcd(freq1, freq2);
3271 freq1_reduced = freq1 / g;
3272 freq2_reduced = freq2 / g;
3273 freq_min_reduced = min(freq1_reduced, freq2_reduced);
3274 freq_max_reduced = max(freq1_reduced, freq2_reduced);
3275
3276 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3277 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3278 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3279 if (add_freqs) {
3280 freq3 += freq2_reduced;
3281 freq4 += freq1_reduced;
3282 }
3283
3284 if (round_it) {
3285 result->freq3_to_2_remainder = 0;
3286 result->freq3_to_2_remaindera = 0;
3287 result->freq4_to_max_remainder = 0;
3288 result->divisor_f4_to_f2 = 0;
3289 result->divisor_f3_to_f1 = 0;
3290 } else {
3291 if (freq2_reduced < freq1_reduced) {
3292 result->freq3_to_2_remainder =
3293 result->freq3_to_2_remaindera =
3294 freq3 % freq1_reduced - freq1_reduced + 1;
3295 result->freq4_to_max_remainder =
3296 -(freq4 % freq1_reduced);
3297 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3298 result->divisor_f4_to_f2 =
3299 (freq4 -
3300 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3301 result->freq4_to_2_remainder =
3302 -(char)((freq1_reduced - freq2_reduced) +
3303 ((u8) freq4 -
3304 (freq1_reduced -
3305 freq2_reduced)) % (u8) freq2_reduced);
3306 } else {
3307 if (freq2_reduced > freq1_reduced) {
3308 result->freq4_to_max_remainder =
3309 (freq4 % freq2_reduced) - freq2_reduced + 1;
3310 result->freq4_to_2_remainder =
3311 freq4 % freq_max_reduced -
3312 freq_max_reduced + 1;
3313 } else {
3314 result->freq4_to_max_remainder =
3315 -(freq4 % freq2_reduced);
3316 result->freq4_to_2_remainder =
3317 -(char)(freq4 % freq_max_reduced);
3318 }
3319 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3320 result->divisor_f3_to_f1 =
3321 (freq3 -
3322 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3323 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3324 result->freq3_to_2_remaindera =
3325 -(char)((freq_max_reduced - freq_min_reduced) +
3326 (freq3 -
3327 (freq_max_reduced -
3328 freq_min_reduced)) % freq1_reduced);
3329 }
3330 }
3331 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3332 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3333 if (round_it) {
3334 if (freq2_reduced > freq1_reduced) {
3335 if (freq3 % freq_max_reduced)
3336 result->divisor_f3_to_fmax++;
3337 }
3338 if (freq2_reduced < freq1_reduced) {
3339 if (freq4 % freq_max_reduced)
3340 result->divisor_f4_to_fmax++;
3341 }
3342 }
3343 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3344 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3345 result->freq_min_reduced = freq_min_reduced;
3346 result->common_time_unit_ps = common_time_unit_ps;
3347 result->freq_max_reduced = freq_max_reduced;
3348}
3349
3350static void
3351set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3352 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3353 int num_cycles_4, int reverse)
3354{
3355 struct stru1 vv;
3356 char multiplier;
3357
3358 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3359 0, 1, &vv);
3360
3361 multiplier =
3362 div_roundup(max
3363 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3364 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3365 div_roundup(num_cycles_1,
3366 vv.common_time_unit_ps) +
3367 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3368 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3369
3370 u32 y =
3371 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3372 vv.freq_max_reduced * multiplier)
3373 | (vv.
3374 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3375 multiplier) << 16) | ((u8) (vv.
3376 freq_min_reduced
3377 *
3378 multiplier)
3379 << 24);
3380 u32 x =
3381 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3382 divisor_f3_to_f1
3383 << 16)
3384 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3385 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003386 MCHBAR32(reg) = y;
3387 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003388 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003389 MCHBAR32(reg + 4) = y;
3390 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003391 }
3392}
3393
3394static void
3395set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3396 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3397 int num_cycles_4)
3398{
3399 struct stru1 ratios1;
3400 struct stru1 ratios2;
3401
3402 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3403 0, 1, &ratios2);
3404 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3405 0, 1, &ratios1);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003406 printk (BIOS_SPEW, "[%x] <= %x\n", reg,
3407 ratios1.freq4_to_max_remainder | (ratios2.
3408 freq4_to_max_remainder
3409 << 8)
3410 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3411 divisor_f4_to_fmax
3412 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003413 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3414 (ratios2.freq4_to_max_remainder << 8) |
3415 (ratios1.divisor_f4_to_fmax << 16) |
3416 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003417}
3418
3419static void
3420set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3421 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3422{
3423 struct stru1 ratios;
3424
3425 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3426 round_it, add_freqs, &ratios);
3427 switch (mode) {
3428 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003429 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3430 (ratios.freqs_reversed << 8);
3431 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3432 (ratios.freq4_to_max_remainder << 8) |
3433 (ratios.divisor_f3_to_fmax << 16) |
3434 (ratios.divisor_f4_to_fmax << 20) |
3435 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003436 break;
3437
3438 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003439 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3440 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003441 break;
3442
3443 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003444 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3445 (ratios.freq4_to_max_remainder << 8) |
3446 (ratios.divisor_f3_to_fmax << 16) |
3447 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003448 break;
3449
3450 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003451 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3452 (ratios.divisor_f4_to_fmax << 8) |
3453 (ratios.freqs_reversed << 12) |
3454 (ratios.freq_min_reduced << 16) |
3455 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003456 break;
3457 }
3458}
3459
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003460static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003461{
3462 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3463 0, 1);
3464 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3465 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3466 1);
3467 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3468 frequency_11(info), 1231, 1524, 0, 1);
3469 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3470 frequency_11(info) / 2, 1278, 2008, 0, 1);
3471 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3472 1167, 1539, 0, 1);
3473 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3474 frequency_11(info) / 2, 1403, 1318, 0, 1);
3475 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3476 1);
3477 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3478 1);
3479 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3480 1, 1);
3481 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3482 1);
3483 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3484 frequency_11(info) / 2, 4000, 0, 0, 0);
3485 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3486 frequency_11(info) / 2, 4000, 4000, 0, 0);
3487
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003488 if (s3resume) {
3489 printk (BIOS_SPEW, "[6dc] <= %x\n", info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003490 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003491 } else
3492 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3493 info->delay46_ps[0], 0,
3494 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003495 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3496 frequency_11(info), 2500, 0, 0, 0);
3497 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3498 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003499 if (s3resume) {
3500 printk (BIOS_SPEW, "[6e8] <= %x\n", info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003501 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003502 } else
3503 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3504 info->delay46_ps[1], 0,
3505 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003506 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3507 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3508 470, 0);
3509 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3510 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3511 454, 459, 0);
3512 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3513 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3514 2588, 0);
3515 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3516 2405, 0);
3517 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3518 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3519 480, 0);
3520 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003521 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3522 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003523}
3524
3525static u16 get_max_timing(struct raminfo *info, int channel)
3526{
3527 int slot, rank, lane;
3528 u16 ret = 0;
3529
Felix Held04be2dd2018-07-29 04:53:22 +02003530 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003531 return 384;
3532
3533 if (info->revision < 8)
3534 return 256;
3535
3536 for (slot = 0; slot < NUM_SLOTS; slot++)
3537 for (rank = 0; rank < NUM_RANKS; rank++)
3538 if (info->populated_ranks[channel][slot][rank])
3539 for (lane = 0; lane < 8 + info->use_ecc; lane++)
3540 ret = max(ret, read_500(info, channel,
3541 get_timing_register_addr
3542 (lane, 0, slot,
3543 rank), 9));
3544 return ret;
3545}
3546
3547static void set_274265(struct raminfo *info)
3548{
3549 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3550 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3551 int delay_e_over_cycle_ps;
3552 int cycletime_ps;
3553 int channel;
3554
3555 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003556 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003557 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3558 cycletime_ps =
3559 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3560 delay_d_ps =
3561 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3562 - info->some_delay_3_ps_rounded + 200;
3563 if (!
3564 ((info->silicon_revision == 0
3565 || info->silicon_revision == 1)
3566 && (info->revision >= 8)))
3567 delay_d_ps += halfcycle_ps(info) * 2;
3568 delay_d_ps +=
3569 halfcycle_ps(info) * (!info->revision_flag_1 +
3570 info->some_delay_2_halfcycles_ceil +
3571 2 * info->some_delay_1_cycle_floor +
3572 info->clock_speed_index +
3573 2 * info->cas_latency - 7 + 11);
3574 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3575
Felix Held04be2dd2018-07-29 04:53:22 +02003576 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3577 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3578 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003579 delay_d_ps += 650;
3580 delay_c_ps = delay_d_ps + 1800;
3581 if (delay_c_ps <= delay_a_ps)
3582 delay_e_ps = 0;
3583 else
3584 delay_e_ps =
3585 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3586 cycletime_ps);
3587
3588 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3589 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3590 delay_f_cycles =
3591 div_roundup(2500 - delay_e_over_cycle_ps,
3592 2 * halfcycle_ps(info));
3593 if (delay_f_cycles > delay_e_cycles) {
3594 info->delay46_ps[channel] = delay_e_ps;
3595 delay_e_cycles = 0;
3596 } else {
3597 info->delay46_ps[channel] =
3598 delay_e_over_cycle_ps +
3599 2 * halfcycle_ps(info) * delay_f_cycles;
3600 delay_e_cycles -= delay_f_cycles;
3601 }
3602
3603 if (info->delay46_ps[channel] < 2500) {
3604 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003605 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003606 }
3607 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3608 if (delay_b_ps <= delay_a_ps)
3609 delay_b_ps = 0;
3610 else
3611 delay_b_ps -= delay_a_ps;
3612 info->delay54_ps[channel] =
3613 cycletime_ps * div_roundup(delay_b_ps,
3614 cycletime_ps) -
3615 2 * halfcycle_ps(info) * delay_e_cycles;
3616 if (info->delay54_ps[channel] < 2500)
3617 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003618 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003619 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3620 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003621 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003622 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003623 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003624 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3625 4 * halfcycle_ps(info)) - 6;
3626 MCHBAR32((channel << 10) + 0x274) =
3627 info->training.reg274265[channel][1] |
3628 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003629 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003630 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3631 4 * halfcycle_ps(info)) + 1;
3632 MCHBAR16((channel << 10) + 0x265) =
3633 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003634 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003635 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003636 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003637 else
Felix Held04be2dd2018-07-29 04:53:22 +02003638 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003639}
3640
3641static void restore_274265(struct raminfo *info)
3642{
3643 int channel;
3644
3645 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003646 MCHBAR32((channel << 10) + 0x274) =
3647 (info->cached_training->reg274265[channel][0] << 16) |
3648 info->cached_training->reg274265[channel][1];
3649 MCHBAR16((channel << 10) + 0x265) =
3650 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003651 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003652 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003653 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003654 else
Felix Held04be2dd2018-07-29 04:53:22 +02003655 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003656}
3657
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003658static void dmi_setup(void)
3659{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003660 gav(read8(DEFAULT_DMIBAR + 0x254));
3661 write8(DEFAULT_DMIBAR + 0x254, 0x1);
3662 write16(DEFAULT_DMIBAR + 0x1b8, 0x18f2);
Felix Heldf83d80b2018-07-29 05:30:30 +02003663 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003664
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003665 write32(DEFAULT_DMIBAR + 0xd68, read32(DEFAULT_DMIBAR + 0xd68) | 0x08000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003666
3667 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3668 DEFAULT_GPIOBASE | 0x38);
3669 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3670}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003671
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003672void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003673{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003674 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003675 u16 ggc;
3676 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003677
Felix Held04be2dd2018-07-29 04:53:22 +02003678 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003679 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3680 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003681 MCHBAR8(0x2ca8) = 0;
Vladimir Serbinenkoe1eef692014-02-19 22:08:51 +01003682 outb(0x6, 0xcf9);
Patrick Georgi546953c2014-11-29 10:38:17 +01003683 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003684 }
Felix Held29a9c072018-07-29 01:34:45 +02003685#if 0
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003686 if (!s3resume) {
3687 pre_raminit_3(x2ca8);
3688 }
Vladimir Serbinenkof62669c2014-01-09 10:59:38 +01003689 pre_raminit_4a(x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003690#endif
3691
3692 dmi_setup();
3693
Felix Held04be2dd2018-07-29 04:53:22 +02003694 MCHBAR16(0x1170) = 0xa880;
3695 MCHBAR8(0x11c1) = 0x1;
3696 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003697 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003698
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003699 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3700 /* 0 for 32MB */
3701 gfxsize = 0;
3702 }
3703
3704 ggc = 0xb00 | ((gfxsize + 5) << 4);
3705
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003706 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003707
3708 u16 deven;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003709 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003710
3711 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003712 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003713 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003714 MCHBAR16_OR(0x2c30, 0x200);
3715 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003716 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003717 pci_read_config8(GMA, 0x62); // = 0x2
3718 pci_write_config8(GMA, 0x62, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003719 read8(DEFAULT_RCBA + 0x2318);
3720 write8(DEFAULT_RCBA + 0x2318, 0x47);
3721 read8(DEFAULT_RCBA + 0x2320);
3722 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003723 }
3724
Felix Heldf83d80b2018-07-29 05:30:30 +02003725 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003726
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003727 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003728 gav(read32(DEFAULT_RCBA + 0x3428));
3729 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003730}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003731
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003732void raminit(const int s3resume, const u8 *spd_addrmap)
3733{
3734 unsigned channel, slot, lane, rank;
3735 int i;
3736 struct raminfo info;
3737 u8 x2ca8;
3738 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003739 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003740
Felix Heldf83d80b2018-07-29 05:30:30 +02003741 /* only used for dummy reads */
3742 volatile u8 tmp8;
3743 volatile u16 tmp16;
3744 volatile u32 tmp32;
3745
Felix Held04be2dd2018-07-29 04:53:22 +02003746 x2ca8 = MCHBAR8(0x2ca8);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003747 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003748
3749 memset(&info, 0x5a, sizeof(info));
3750
3751 info.last_500_command[0] = 0;
3752 info.last_500_command[1] = 0;
3753
3754 info.fsb_frequency = 135 * 2;
3755 info.board_lane_delay[0] = 0x14;
3756 info.board_lane_delay[1] = 0x07;
3757 info.board_lane_delay[2] = 0x07;
3758 info.board_lane_delay[3] = 0x08;
3759 info.board_lane_delay[4] = 0x56;
3760 info.board_lane_delay[5] = 0x04;
3761 info.board_lane_delay[6] = 0x04;
3762 info.board_lane_delay[7] = 0x05;
3763 info.board_lane_delay[8] = 0x10;
3764
3765 info.training.reg_178 = 0;
3766 info.training.reg_10b = 0;
3767
3768 info.heci_bar = 0;
3769 info.memory_reserved_for_heci_mb = 0;
3770
3771 /* before SPD */
3772 timestamp_add_now(101);
3773
Felix Held29a9c072018-07-29 01:34:45 +02003774 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003775 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003776
3777 collect_system_info(&info);
3778
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003779 /* Enable SMBUS. */
3780 enable_smbus();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003781
3782 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3783
3784 info.use_ecc = 1;
3785 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003786 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003787 int v;
3788 int try;
3789 int addr;
3790 const u8 useful_addresses[] = {
3791 DEVICE_TYPE,
3792 MODULE_TYPE,
3793 DENSITY,
3794 RANKS_AND_DQ,
3795 MEMORY_BUS_WIDTH,
3796 TIMEBASE_DIVIDEND,
3797 TIMEBASE_DIVISOR,
3798 CYCLETIME,
3799 CAS_LATENCIES_LSB,
3800 CAS_LATENCIES_MSB,
3801 CAS_LATENCY_TIME,
3802 0x11, 0x12, 0x13, 0x14, 0x15,
3803 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3804 0x1c, 0x1d,
3805 THERMAL_AND_REFRESH,
3806 0x20,
3807 REFERENCE_RAW_CARD_USED,
3808 RANK1_ADDRESS_MAPPING,
3809 0x75, 0x76, 0x77, 0x78,
3810 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3811 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3812 0x85, 0x86, 0x87, 0x88,
3813 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3814 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3815 0x95
3816 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003817 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003818 continue;
3819 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003820 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003821 DEVICE_TYPE);
3822 if (v >= 0)
3823 break;
3824 }
3825 if (v < 0)
3826 continue;
3827 for (addr = 0;
3828 addr <
3829 sizeof(useful_addresses) /
3830 sizeof(useful_addresses[0]); addr++)
3831 gav(info.
3832 spd[channel][0][useful_addresses
3833 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003834 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003835 useful_addresses
3836 [addr]));
3837 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3838 die("Only DDR3 is supported");
3839
3840 v = info.spd[channel][0][RANKS_AND_DQ];
3841 info.populated_ranks[channel][0][0] = 1;
3842 info.populated_ranks[channel][0][1] =
3843 ((v >> 3) & 7);
3844 if (((v >> 3) & 7) > 1)
3845 die("At most 2 ranks are supported");
3846 if ((v & 7) == 0 || (v & 7) > 2)
3847 die("Only x8 and x16 modules are supported");
3848 if ((info.
3849 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3850 && (info.
3851 spd[channel][slot][MODULE_TYPE] & 0xF)
3852 != 3)
3853 die("Registered memory is not supported");
3854 info.is_x16_module[channel][0] = (v & 7) - 1;
3855 info.density[channel][slot] =
3856 info.spd[channel][slot][DENSITY] & 0xF;
3857 if (!
3858 (info.
3859 spd[channel][slot][MEMORY_BUS_WIDTH] &
3860 0x18))
3861 info.use_ecc = 0;
3862 }
3863
3864 gav(0x55);
3865
3866 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3867 int v = 0;
3868 for (slot = 0; slot < NUM_SLOTS; slot++)
3869 for (rank = 0; rank < NUM_RANKS; rank++)
3870 v |= info.
3871 populated_ranks[channel][slot][rank]
3872 << (2 * slot + rank);
3873 info.populated_ranks_mask[channel] = v;
3874 }
3875
3876 gav(0x55);
3877
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003878 gav(pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003879 }
3880
3881 /* after SPD */
3882 timestamp_add_now(102);
3883
Felix Held04be2dd2018-07-29 04:53:22 +02003884 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003885
3886 collect_system_info(&info);
3887 calculate_timings(&info);
3888
Felix Held29a9c072018-07-29 01:34:45 +02003889#if 0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003890 pci_write_config8(NORTHBRIDGE, 0xdf, 0x82);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003891#endif
3892
3893 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003894 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003895 if (x2ca8 == 0 && (reg8 & 0x80)) {
3896 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3897 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3898 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3899 */
3900
3901 /* Clear bit7. */
3902
3903 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3904 (reg8 & ~(1 << 7)));
3905
3906 printk(BIOS_INFO,
3907 "Interrupted RAM init, reset required.\n");
3908 outb(0x6, 0xcf9);
Patrick Georgi546953c2014-11-29 10:38:17 +01003909 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003910 }
3911 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003912
3913 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003914 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3915 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003916
3917 compute_derived_timings(&info);
3918
3919 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003920 gav(MCHBAR8(0x164));
3921 MCHBAR8(0x164) = 0x26;
3922 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003923 }
3924
Felix Held04be2dd2018-07-29 04:53:22 +02003925 MCHBAR32_OR(0x18b4, 0x210000);
3926 MCHBAR32_OR(0x1890, 0x2000000);
3927 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003928
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003929 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x50)); // !!!!
3930 pci_write_config8(PCI_DEV(0xff, 2, 1), 0x54, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003931
Felix Held04be2dd2018-07-29 04:53:22 +02003932 gav(MCHBAR16(0x2c10));
3933 MCHBAR16(0x2c10) = 0x412;
3934 gav(MCHBAR16(0x2c10));
3935 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003936
Felix Held04be2dd2018-07-29 04:53:22 +02003937 gav(MCHBAR8(0x2ca8)); // !!!!
3938 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003939
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003940 pci_read_config32(PCI_DEV(0xff, 2, 1), 0x6c); // !!!!
3941 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x6c, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003942 gav(MCHBAR32(0x1c04)); // !!!!
3943 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003944
3945 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003946 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003947 }
3948
Felix Held04be2dd2018-07-29 04:53:22 +02003949 MCHBAR32(0x18d8) = 0x120000;
3950 MCHBAR32(0x18dc) = 0x30a484a;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003951 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x0);
3952 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003953 MCHBAR32(0x18d8) = 0x40000;
3954 MCHBAR32(0x18dc) = 0xb000000;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003955 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x60000);
3956 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003957 MCHBAR32(0x18d8) = 0x180000;
3958 MCHBAR32(0x18dc) = 0xc0000142;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003959 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x20000);
3960 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003961 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003962
Felix Held04be2dd2018-07-29 04:53:22 +02003963 gav(MCHBAR32(0x18dc)); // !!!!
3964 MCHBAR32(0x18dc) = 0x3;
3965 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003966
3967 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003968 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003969 }
3970
Felix Held04be2dd2018-07-29 04:53:22 +02003971 MCHBAR32(0x188c) = 0x20bc09;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003972 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xd0, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003973 MCHBAR32(0x1a10) = 0x4200010e;
3974 MCHBAR32_OR(0x18b8, 0x200);
3975 gav(MCHBAR32(0x1918)); // !!!!
3976 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003977
Felix Held04be2dd2018-07-29 04:53:22 +02003978 gav(MCHBAR32(0x18b8)); // !!!!
3979 MCHBAR32(0x18b8) = 0xe00;
3980 gav(MCHBAR32(0x182c)); // !!!!
3981 MCHBAR32(0x182c) = 0x10202;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003982 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x94)); // !!!!
3983 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x94, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003984 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3985 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003986
Felix Held04be2dd2018-07-29 04:53:22 +02003987 MCHBAR32_AND(0x18b4, 0xffff7fff);
3988 gav(MCHBAR32(0x1a68)); // !!!!
3989 MCHBAR32(0x1a68) = 0x343800;
3990 gav(MCHBAR32(0x1e68)); // !!!!
3991 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003992
3993 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003994 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003995 }
3996
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003997 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x048); // !!!!
3998 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x048, 0x140000);
3999 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
4000 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x058, 0x64555);
4001 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
4002 pci_read_config32(PCI_DEV (0xff, 0, 0), 0xd0); // !!!!
4003 pci_write_config32(PCI_DEV (0xff, 0, 0), 0xd0, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02004004 gav(MCHBAR32(0x1af0)); // !!!!
4005 gav(MCHBAR32(0x1af0)); // !!!!
4006 MCHBAR32(0x1af0) = 0x1f020003;
4007 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004008
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10004009 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004010 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004011 }
4012
Felix Held04be2dd2018-07-29 04:53:22 +02004013 gav(MCHBAR32(0x1890)); // !!!!
4014 MCHBAR32(0x1890) = 0x80102;
4015 gav(MCHBAR32(0x18b4)); // !!!!
4016 MCHBAR32(0x18b4) = 0x216000;
4017 MCHBAR32(0x18a4) = 0x22222222;
4018 MCHBAR32(0x18a8) = 0x22222222;
4019 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004020
4021 udelay(1000);
4022
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004023 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004024
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004025 if (x2ca8 == 0) {
4026 int j;
4027 if (s3resume && info.cached_training) {
4028 restore_274265(&info);
4029 printk(BIOS_DEBUG, "reg2ca9_bit0 = %x\n",
4030 info.cached_training->reg2ca9_bit0);
4031 for (i = 0; i < 2; i++)
4032 for (j = 0; j < 3; j++)
4033 printk(BIOS_DEBUG, "reg274265[%d][%d] = %x\n",
4034 i, j, info.cached_training->reg274265[i][j]);
4035 } else {
4036 set_274265(&info);
4037 printk(BIOS_DEBUG, "reg2ca9_bit0 = %x\n",
4038 info.training.reg2ca9_bit0);
4039 for (i = 0; i < 2; i++)
4040 for (j = 0; j < 3; j++)
4041 printk(BIOS_DEBUG, "reg274265[%d][%d] = %x\n",
4042 i, j, info.training.reg274265[i][j]);
4043 }
4044
4045 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004046
4047 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02004048 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004049 }
4050
4051 udelay(1000);
4052
4053 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02004054 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02004055 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004056 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4057 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4058 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004059
Felix Heldf83d80b2018-07-29 05:30:30 +02004060 tmp8 = MCHBAR8(0x1150);
4061 tmp8 = MCHBAR8(0x1151);
4062 tmp8 = MCHBAR8(0x1022);
4063 tmp8 = MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004064 MCHBAR32(0x1300) = 0x60606060;
4065 MCHBAR32(0x1304) = 0x60606060;
4066 MCHBAR32(0x1308) = 0x78797a7b;
4067 MCHBAR32(0x130c) = 0x7c7d7e7f;
4068 MCHBAR32(0x1310) = 0x60606060;
4069 MCHBAR32(0x1314) = 0x60606060;
4070 MCHBAR32(0x1318) = 0x60606060;
4071 MCHBAR32(0x131c) = 0x60606060;
4072 MCHBAR32(0x1320) = 0x50515253;
4073 MCHBAR32(0x1324) = 0x54555657;
4074 MCHBAR32(0x1328) = 0x58595a5b;
4075 MCHBAR32(0x132c) = 0x5c5d5e5f;
4076 MCHBAR32(0x1330) = 0x40414243;
4077 MCHBAR32(0x1334) = 0x44454647;
4078 MCHBAR32(0x1338) = 0x48494a4b;
4079 MCHBAR32(0x133c) = 0x4c4d4e4f;
4080 MCHBAR32(0x1340) = 0x30313233;
4081 MCHBAR32(0x1344) = 0x34353637;
4082 MCHBAR32(0x1348) = 0x38393a3b;
4083 MCHBAR32(0x134c) = 0x3c3d3e3f;
4084 MCHBAR32(0x1350) = 0x20212223;
4085 MCHBAR32(0x1354) = 0x24252627;
4086 MCHBAR32(0x1358) = 0x28292a2b;
4087 MCHBAR32(0x135c) = 0x2c2d2e2f;
4088 MCHBAR32(0x1360) = 0x10111213;
4089 MCHBAR32(0x1364) = 0x14151617;
4090 MCHBAR32(0x1368) = 0x18191a1b;
4091 MCHBAR32(0x136c) = 0x1c1d1e1f;
4092 MCHBAR32(0x1370) = 0x10203;
4093 MCHBAR32(0x1374) = 0x4050607;
4094 MCHBAR32(0x1378) = 0x8090a0b;
4095 MCHBAR32(0x137c) = 0xc0d0e0f;
4096 MCHBAR8(0x11cc) = 0x4e;
4097 MCHBAR32(0x1110) = 0x73970404;
4098 MCHBAR32(0x1114) = 0x72960404;
4099 MCHBAR32(0x1118) = 0x6f950404;
4100 MCHBAR32(0x111c) = 0x6d940404;
4101 MCHBAR32(0x1120) = 0x6a930404;
4102 MCHBAR32(0x1124) = 0x68a41404;
4103 MCHBAR32(0x1128) = 0x66a21404;
4104 MCHBAR32(0x112c) = 0x63a01404;
4105 MCHBAR32(0x1130) = 0x609e1404;
4106 MCHBAR32(0x1134) = 0x5f9c1404;
4107 MCHBAR32(0x1138) = 0x5c961404;
4108 MCHBAR32(0x113c) = 0x58a02404;
4109 MCHBAR32(0x1140) = 0x54942404;
4110 MCHBAR32(0x1190) = 0x900080a;
4111 MCHBAR16(0x11c0) = 0xc40b;
4112 MCHBAR16(0x11c2) = 0x303;
4113 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004114 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004115 MCHBAR32(0x11b8) = 0x70c3000;
4116 MCHBAR8(0x11ec) = 0xa;
4117 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004118 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004119 MCHBAR16(0x11ca) = 0xfa;
4120 MCHBAR32(0x11e4) = 0x4e20;
4121 MCHBAR8(0x11bc) = 0xf;
4122 MCHBAR16(0x11da) = 0x19;
4123 MCHBAR16(0x11ba) = 0x470c;
4124 MCHBAR32(0x1680) = 0xe6ffe4ff;
4125 MCHBAR32(0x1684) = 0xdeffdaff;
4126 MCHBAR32(0x1688) = 0xd4ffd0ff;
4127 MCHBAR32(0x168c) = 0xccffc6ff;
4128 MCHBAR32(0x1690) = 0xc0ffbeff;
4129 MCHBAR32(0x1694) = 0xb8ffb0ff;
4130 MCHBAR32(0x1698) = 0xa8ff0000;
4131 MCHBAR32(0x169c) = 0xc00;
4132 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004133 }
4134
Felix Held04be2dd2018-07-29 04:53:22 +02004135 MCHBAR32(0x124c) = 0x15040d00;
4136 MCHBAR32(0x1250) = 0x7f0000;
4137 MCHBAR32(0x1254) = 0x1e220004;
4138 MCHBAR32(0x1258) = 0x4000004;
4139 MCHBAR32(0x1278) = 0x0;
4140 MCHBAR32(0x125c) = 0x0;
4141 MCHBAR32(0x1260) = 0x0;
4142 MCHBAR32(0x1264) = 0x0;
4143 MCHBAR32(0x1268) = 0x0;
4144 MCHBAR32(0x126c) = 0x0;
4145 MCHBAR32(0x1270) = 0x0;
4146 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004147 }
4148
4149 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004150 MCHBAR16(0x1214) = 0x320;
4151 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004152 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4153 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004154 MCHBAR32(0x1400) = 0x13040020;
4155 MCHBAR32(0x1404) = 0xe090120;
4156 MCHBAR32(0x1408) = 0x5120220;
4157 MCHBAR32(0x140c) = 0x5120330;
4158 MCHBAR32(0x1410) = 0xe090220;
4159 MCHBAR32(0x1414) = 0x1010001;
4160 MCHBAR32(0x1418) = 0x1110000;
4161 MCHBAR32(0x141c) = 0x9020020;
4162 MCHBAR32(0x1420) = 0xd090220;
4163 MCHBAR32(0x1424) = 0x2090220;
4164 MCHBAR32(0x1428) = 0x2090330;
4165 MCHBAR32(0x142c) = 0xd090220;
4166 MCHBAR32(0x1430) = 0x1010001;
4167 MCHBAR32(0x1434) = 0x1110000;
4168 MCHBAR32(0x1438) = 0x11040020;
4169 MCHBAR32(0x143c) = 0x4030220;
4170 MCHBAR32(0x1440) = 0x1060220;
4171 MCHBAR32(0x1444) = 0x1060330;
4172 MCHBAR32(0x1448) = 0x4030220;
4173 MCHBAR32(0x144c) = 0x1010001;
4174 MCHBAR32(0x1450) = 0x1110000;
4175 MCHBAR32(0x1454) = 0x4010020;
4176 MCHBAR32(0x1458) = 0xb090220;
4177 MCHBAR32(0x145c) = 0x1090220;
4178 MCHBAR32(0x1460) = 0x1090330;
4179 MCHBAR32(0x1464) = 0xb090220;
4180 MCHBAR32(0x1468) = 0x1010001;
4181 MCHBAR32(0x146c) = 0x1110000;
4182 MCHBAR32(0x1470) = 0xf040020;
4183 MCHBAR32(0x1474) = 0xa090220;
4184 MCHBAR32(0x1478) = 0x1120220;
4185 MCHBAR32(0x147c) = 0x1120330;
4186 MCHBAR32(0x1480) = 0xa090220;
4187 MCHBAR32(0x1484) = 0x1010001;
4188 MCHBAR32(0x1488) = 0x1110000;
4189 MCHBAR32(0x148c) = 0x7020020;
4190 MCHBAR32(0x1490) = 0x1010220;
4191 MCHBAR32(0x1494) = 0x10210;
4192 MCHBAR32(0x1498) = 0x10320;
4193 MCHBAR32(0x149c) = 0x1010220;
4194 MCHBAR32(0x14a0) = 0x1010001;
4195 MCHBAR32(0x14a4) = 0x1110000;
4196 MCHBAR32(0x14a8) = 0xd040020;
4197 MCHBAR32(0x14ac) = 0x8090220;
4198 MCHBAR32(0x14b0) = 0x1111310;
4199 MCHBAR32(0x14b4) = 0x1111420;
4200 MCHBAR32(0x14b8) = 0x8090220;
4201 MCHBAR32(0x14bc) = 0x1010001;
4202 MCHBAR32(0x14c0) = 0x1110000;
4203 MCHBAR32(0x14c4) = 0x3010020;
4204 MCHBAR32(0x14c8) = 0x7090220;
4205 MCHBAR32(0x14cc) = 0x1081310;
4206 MCHBAR32(0x14d0) = 0x1081420;
4207 MCHBAR32(0x14d4) = 0x7090220;
4208 MCHBAR32(0x14d8) = 0x1010001;
4209 MCHBAR32(0x14dc) = 0x1110000;
4210 MCHBAR32(0x14e0) = 0xb040020;
4211 MCHBAR32(0x14e4) = 0x2030220;
4212 MCHBAR32(0x14e8) = 0x1051310;
4213 MCHBAR32(0x14ec) = 0x1051420;
4214 MCHBAR32(0x14f0) = 0x2030220;
4215 MCHBAR32(0x14f4) = 0x1010001;
4216 MCHBAR32(0x14f8) = 0x1110000;
4217 MCHBAR32(0x14fc) = 0x5020020;
4218 MCHBAR32(0x1500) = 0x5090220;
4219 MCHBAR32(0x1504) = 0x2071310;
4220 MCHBAR32(0x1508) = 0x2071420;
4221 MCHBAR32(0x150c) = 0x5090220;
4222 MCHBAR32(0x1510) = 0x1010001;
4223 MCHBAR32(0x1514) = 0x1110000;
4224 MCHBAR32(0x1518) = 0x7040120;
4225 MCHBAR32(0x151c) = 0x2090220;
4226 MCHBAR32(0x1520) = 0x70b1210;
4227 MCHBAR32(0x1524) = 0x70b1310;
4228 MCHBAR32(0x1528) = 0x2090220;
4229 MCHBAR32(0x152c) = 0x1010001;
4230 MCHBAR32(0x1530) = 0x1110000;
4231 MCHBAR32(0x1534) = 0x1010110;
4232 MCHBAR32(0x1538) = 0x1081310;
4233 MCHBAR32(0x153c) = 0x5041200;
4234 MCHBAR32(0x1540) = 0x5041310;
4235 MCHBAR32(0x1544) = 0x1081310;
4236 MCHBAR32(0x1548) = 0x1010001;
4237 MCHBAR32(0x154c) = 0x1110000;
4238 MCHBAR32(0x1550) = 0x1040120;
4239 MCHBAR32(0x1554) = 0x4051210;
4240 MCHBAR32(0x1558) = 0xd051200;
4241 MCHBAR32(0x155c) = 0xd051200;
4242 MCHBAR32(0x1560) = 0x4051210;
4243 MCHBAR32(0x1564) = 0x1010001;
4244 MCHBAR32(0x1568) = 0x1110000;
4245 MCHBAR16(0x1222) = 0x220a;
4246 MCHBAR16(0x123c) = 0x1fc0;
4247 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004248 }
4249
Felix Heldf83d80b2018-07-29 05:30:30 +02004250 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
4251 tmp32 = MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004252 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004253
Felix Heldf83d80b2018-07-29 05:30:30 +02004254 tmp8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004255
4256 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004257 MCHBAR8_AND(0x2ca8, ~3);
4258 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
4259 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004260 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004261 }
4262
Felix Held04be2dd2018-07-29 04:53:22 +02004263 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004264 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004265 pci_write_config32(PCI_DEV (0xff, 0, 0), 0x60, 0x20220);
Felix Heldf83d80b2018-07-29 05:30:30 +02004266 tmp16 = MCHBAR16(0x2c20); // !!!!
4267 tmp16 = MCHBAR16(0x2c10); // !!!!
4268 tmp16 = MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004269 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004270 udelay(1000);
4271 write_1d0(0, 0x33d, 0, 0);
4272 write_500(&info, 0, 0, 0xb61, 0, 0);
4273 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004274 MCHBAR32(0x1a30) = 0x0;
4275 MCHBAR32(0x1a34) = 0x0;
4276 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4277 (info.populated_ranks[0][0][0] * 0xa0);
4278 MCHBAR16(0x616) = 0x26a;
4279 MCHBAR32(0x134) = 0x856000;
4280 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004281 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4282 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004283 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004284 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4285 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004286 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004287 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004288 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4289 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004290 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4291 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4292 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4293 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4294 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4295 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4296 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4297 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4298 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4299 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004300 }
4301
4302 write_1d0(0x4, 0x151, 4, 1);
4303 write_1d0(0, 0x142, 3, 1);
4304 rdmsr(0x1ac); // !!!!
4305 write_500(&info, 1, 1, 0x6b3, 4, 1);
4306 write_500(&info, 1, 1, 0x6cf, 4, 1);
4307
4308 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4309
4310 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4311 populated_ranks[0]
4312 [0][0]) << 0),
4313 0x1d1, 3, 1);
4314 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004315 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4316 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004317 }
4318
4319 set_334(0);
4320
4321 program_base_timings(&info);
4322
Felix Held04be2dd2018-07-29 04:53:22 +02004323 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004324
4325 write_1d0(0x2, 0x1d5, 2, 1);
4326 write_1d0(0x20, 0x166, 7, 1);
4327 write_1d0(0x0, 0xeb, 3, 1);
4328 write_1d0(0x0, 0xf3, 6, 1);
4329
4330 for (channel = 0; channel < NUM_CHANNELS; channel++)
4331 for (lane = 0; lane < 9; lane++) {
4332 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4333 u8 a;
4334 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4335 write_500(&info, channel, a, addr, 6, 1);
4336 }
4337
4338 udelay(1000);
4339
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004340 if (s3resume) {
4341 if (info.cached_training == NULL) {
4342 u32 reg32;
4343 printk(BIOS_ERR,
4344 "Couldn't find training data. Rebooting\n");
4345 reg32 = inl(DEFAULT_PMBASE + 0x04);
4346 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4347 outb(0xe, 0xcf9);
Patrick Georgi546953c2014-11-29 10:38:17 +01004348 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004349 }
4350 int tm;
4351 info.training = *info.cached_training;
4352 for (tm = 0; tm < 4; tm++)
4353 for (channel = 0; channel < NUM_CHANNELS; channel++)
4354 for (slot = 0; slot < NUM_SLOTS; slot++)
4355 for (rank = 0; rank < NUM_RANKS; rank++)
4356 for (lane = 0; lane < 9; lane++)
4357 write_500(&info,
4358 channel,
4359 info.training.
4360 lane_timings
4361 [tm][channel]
4362 [slot][rank]
4363 [lane],
4364 get_timing_register_addr
4365 (lane, tm,
4366 slot, rank),
4367 9, 0);
4368 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4369 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4370 }
4371
Felix Heldf83d80b2018-07-29 05:30:30 +02004372 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004373 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004374 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
4375 tmp8 = MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004376
4377 program_board_delay(&info);
4378
Felix Held04be2dd2018-07-29 04:53:22 +02004379 MCHBAR8(0x5ff) = 0x0;
4380 MCHBAR8(0x5ff) = 0x80;
4381 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004382
Felix Held04be2dd2018-07-29 04:53:22 +02004383 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004384 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004385 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004386 gav(read_1d0(0x14b, 7)); // = 0x81023100
4387 write_1d0(0x30, 0x14b, 7, 1);
4388 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4389 write_1d0(7, 0xd6, 6, 1);
4390 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4391 write_1d0(7, 0x328, 6, 1);
4392
4393 for (channel = 0; channel < NUM_CHANNELS; channel++)
4394 set_4cf(&info, channel,
4395 info.populated_ranks[channel][0][0] ? 8 : 0);
4396
4397 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4398 write_1d0(2, 0x116, 4, 1);
4399 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4400 write_1d0(0, 0xae, 6, 1);
4401 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4402 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004403 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4404 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004405 MCHBAR32_AND(0x140, ~0x07000000);
4406 MCHBAR32_AND(0x138, ~0x07000000);
4407 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004408 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004409 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004410 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004411
4412 {
4413 u32 t;
4414 u8 val_a1;
4415 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4416 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4417 rmw_1d0(0x320, 0x07,
4418 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4419 rmw_1d0(0x14b, 0x78,
4420 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4421 4), 7,
4422 1);
4423 rmw_1d0(0xce, 0x38,
4424 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4425 4), 6,
4426 1);
4427 }
4428
4429 for (channel = 0; channel < NUM_CHANNELS; channel++)
4430 set_4cf(&info, channel,
4431 info.populated_ranks[channel][0][0] ? 9 : 1);
4432
4433 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Felix Heldf83d80b2018-07-29 05:30:30 +02004434 tmp32 = MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004435 write_1d0(2, 0xae, 6, 1);
4436 write_1d0(2, 0x300, 6, 1);
4437 write_1d0(2, 0x121, 3, 1);
4438 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4439 write_1d0(4, 0xd6, 6, 1);
4440 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4441 write_1d0(4, 0x328, 6, 1);
4442
4443 for (channel = 0; channel < NUM_CHANNELS; channel++)
4444 set_4cf(&info, channel,
4445 info.populated_ranks[channel][0][0] ? 9 : 0);
4446
Felix Held04be2dd2018-07-29 04:53:22 +02004447 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4448 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004449 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004450 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004451 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4452 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4453 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4454 write_1d0(0, 0x21c, 6, 1);
4455 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4456 write_1d0(0x35, 0x14b, 7, 1);
4457
4458 for (channel = 0; channel < NUM_CHANNELS; channel++)
4459 set_4cf(&info, channel,
4460 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4461
4462 set_334(1);
4463
Felix Held04be2dd2018-07-29 04:53:22 +02004464 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004465
4466 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4467 write_500(&info, channel,
4468 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4469 1);
4470 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4471 }
Felix Held04be2dd2018-07-29 04:53:22 +02004472 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4473 MCHBAR16(0x6c0) = 0x14a0;
4474 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4475 MCHBAR16(0x232) = 0x8;
4476 /* 0x40004 or 0 depending on ? */
4477 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4478 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4479 MCHBAR32(0x128) = 0x2150d05;
4480 MCHBAR8(0x12c) = 0x1f;
4481 MCHBAR8(0x12d) = 0x56;
4482 MCHBAR8(0x12e) = 0x31;
4483 MCHBAR8(0x12f) = 0x0;
4484 MCHBAR8(0x271) = 0x2;
4485 MCHBAR8(0x671) = 0x2;
4486 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004487 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004488 MCHBAR32(0x294 + (channel << 10)) =
4489 (info.populated_ranks_mask[channel] & 3) << 16;
4490 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4491 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004492 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004493 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4494 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004495
4496 if (!s3resume)
4497 jedec_init(&info);
4498
4499 int totalrank = 0;
4500 for (channel = 0; channel < NUM_CHANNELS; channel++)
4501 for (slot = 0; slot < NUM_SLOTS; slot++)
4502 for (rank = 0; rank < NUM_RANKS; rank++)
4503 if (info.populated_ranks[channel][slot][rank]) {
4504 jedec_read(&info, channel, slot, rank,
4505 totalrank, 0xa, 0x400);
4506 totalrank++;
4507 }
4508
Felix Held04be2dd2018-07-29 04:53:22 +02004509 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004510
Felix Heldf83d80b2018-07-29 05:30:30 +02004511 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4512 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004513
4514 if (!s3resume) {
4515 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004516 MCHBAR32(0x294 + (channel << 10)) =
4517 (info.populated_ranks_mask[channel] & 3) << 16;
4518 MCHBAR16(0x298 + (channel << 10)) =
4519 info.populated_ranks[channel][0][0] |
4520 (info.populated_ranks[channel][0][1] << 5);
4521 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004522 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004523 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004524
4525 {
4526 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004527 a = MCHBAR8(0x243);
4528 b = MCHBAR8(0x643);
4529 MCHBAR8(0x243) = a | 2;
4530 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004531 }
4532
4533 write_1d0(7, 0x19b, 3, 1);
4534 write_1d0(7, 0x1c0, 3, 1);
4535 write_1d0(4, 0x1c6, 4, 1);
4536 write_1d0(4, 0x1cc, 4, 1);
4537 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4538 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004539 MCHBAR32(0x584) = 0xfffff;
4540 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004541
4542 for (channel = 0; channel < NUM_CHANNELS; channel++)
4543 for (slot = 0; slot < NUM_SLOTS; slot++)
4544 for (rank = 0; rank < NUM_RANKS; rank++)
4545 if (info.
4546 populated_ranks[channel][slot]
4547 [rank])
4548 config_rank(&info, s3resume,
4549 channel, slot,
4550 rank);
4551
Felix Held04be2dd2018-07-29 04:53:22 +02004552 MCHBAR8(0x243) = 0x1;
4553 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004554 }
4555
4556 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004557 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004558 write_26c(0, 0x820);
4559 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004560 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004561 /* end */
4562
4563 if (s3resume) {
4564 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004565 MCHBAR32(0x294 + (channel << 10)) =
4566 (info.populated_ranks_mask[channel] & 3) << 16;
4567 MCHBAR16(0x298 + (channel << 10)) =
4568 info.populated_ranks[channel][0][0] |
4569 (info.populated_ranks[channel][0][1] << 5);
4570 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004571 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004572 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004573 }
4574
Felix Held04be2dd2018-07-29 04:53:22 +02004575 MCHBAR32_AND(0xfa4, ~0x01000002);
4576 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004577
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004578 /* Before training. */
4579 timestamp_add_now(103);
4580
4581 if (!s3resume)
4582 ram_training(&info);
4583
4584 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004585 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004586
4587 dump_timings(&info);
4588
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004589 program_modules_memory_map(&info, 0);
4590 program_total_memory_map(&info);
4591
4592 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004593 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004594 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004595 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004596 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004597 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004598 else
Felix Held04be2dd2018-07-29 04:53:22 +02004599 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004600
Felix Held04be2dd2018-07-29 04:53:22 +02004601 MCHBAR32_AND(0xfac, ~0x80000000);
4602 MCHBAR32(0xfb4) = 0x4800;
4603 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4604 MCHBAR32(0xe94) = 0x7ffff;
4605 MCHBAR32(0xfc0) = 0x80002040;
4606 MCHBAR32(0xfc4) = 0x701246;
4607 MCHBAR8_AND(0xfc8, ~0x70);
4608 MCHBAR32_OR(0xe5c, 0x1000000);
4609 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4610 MCHBAR32(0x50) = 0x700b0;
4611 MCHBAR32(0x3c) = 0x10;
4612 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4613 MCHBAR8_OR(0xff4, 0x2);
4614 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004615
Felix Held29a9c072018-07-29 01:34:45 +02004616#if 1
Felix Held04be2dd2018-07-29 04:53:22 +02004617 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4618 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4619 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004620
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004621 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4622 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4623 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004624
4625#else
4626 {
4627 u32 eax;
Felix Held04be2dd2018-07-29 04:53:22 +02004628 // = 0xe911714b
4629 eax = read32p(0xffc + (MCHBAR32(0xd00) & ~1)) | 0x08000000;
4630 write32p(0xffc + (MCHBAR32(0xd00) & ~1), eax);
4631 // = 0xe911714b
4632 eax = read32p(0xffc + (MCHBAR32(0xdc0) & ~1)) | 0x40000000;
4633 write32p(0xffc + (MCHBAR32(0xdc0) & ~1), eax);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004634 }
4635#endif
4636
4637 {
4638 u32 eax;
4639
4640 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004641 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4642 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4643 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004644 }
4645
4646 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004647 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004648 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004649 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004650 else
Felix Held04be2dd2018-07-29 04:53:22 +02004651 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004652
Felix Held04be2dd2018-07-29 04:53:22 +02004653 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004654
Felix Held04be2dd2018-07-29 04:53:22 +02004655 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004656 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004657 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004658 else
Felix Held04be2dd2018-07-29 04:53:22 +02004659 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004660 }
4661
Felix Held04be2dd2018-07-29 04:53:22 +02004662 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004663
4664 {
4665 u8 al;
4666 al = 0xd;
4667 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4668 al += 2;
4669 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004670 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004671 }
4672
4673 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004674 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4675 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4676 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4677 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004678 }
4679 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004680 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004681 reg1c = read32p(DEFAULT_EPBAR | 0x01c); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004682 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004683 write32p(DEFAULT_EPBAR | 0x01c, reg1c); // OK
Felix Heldf83d80b2018-07-29 05:30:30 +02004684 tmp8 = MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004685 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004686 MCHBAR8_OR(0x1210, 2);
4687 MCHBAR32(0x1200) = 0x8800440;
4688 MCHBAR32(0x1204) = 0x53ff0453;
4689 MCHBAR32(0x1208) = 0x19002043;
4690 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004691
4692 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004693 MCHBAR16(0x1214) = 0x220;
4694 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004695 }
4696
Felix Held04be2dd2018-07-29 04:53:22 +02004697 MCHBAR8_OR(0x1214, 0x4);
4698 MCHBAR8(0x120c) = 0x1;
4699 MCHBAR8(0x1218) = 0x3;
4700 MCHBAR8(0x121a) = 0x3;
4701 MCHBAR8(0x121c) = 0x3;
4702 MCHBAR16(0xc14) = 0x0;
4703 MCHBAR16(0xc20) = 0x0;
4704 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004705
4706 /* revision dependent here. */
4707
Felix Held04be2dd2018-07-29 04:53:22 +02004708 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004709
4710 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004711 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004712
Felix Held04be2dd2018-07-29 04:53:22 +02004713 MCHBAR16_OR(0x1230, 0x8000);
4714 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004715
4716 u8 bl, ebpb;
4717 u16 reg_1020;
4718
Felix Held04be2dd2018-07-29 04:53:22 +02004719 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4720 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004721
Felix Held04be2dd2018-07-29 04:53:22 +02004722 MCHBAR32(0x1000) = 0x100;
4723 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004724
4725 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004726 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004727 bl = reg_1020 >> 8;
4728 ebpb = reg_1020 & 0xff;
4729 } else {
4730 ebpb = 0;
4731 bl = 8;
4732 }
4733
4734 rdmsr(0x1a2);
4735
Felix Held04be2dd2018-07-29 04:53:22 +02004736 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004737
Felix Held04be2dd2018-07-29 04:53:22 +02004738 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004739
Felix Held04be2dd2018-07-29 04:53:22 +02004740 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004741
Felix Held04be2dd2018-07-29 04:53:22 +02004742 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004743 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004744 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4745 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004746 }
4747
4748 setup_heci_uma(&info);
4749
4750 if (info.uma_enabled) {
4751 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004752 MCHBAR32_OR(0x11b0, 0x4000);
4753 MCHBAR32_OR(0x11b4, 0x4000);
4754 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004755
Felix Held04be2dd2018-07-29 04:53:22 +02004756 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4757 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4758 MCHBAR16_OR(0x1170, 0x1000);
4759
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004760 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004761
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004762 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004763 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004764 ;
4765 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004766 }
4767
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004768 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4769 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004770 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004771 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004772
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004773 udelay(1000);
4774 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004775 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4776
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004777 if (!s3resume)
4778 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004779 if (s3resume && cbmem_wasnot_inited) {
4780 u32 reg32;
4781 printk(BIOS_ERR, "Failed S3 resume.\n");
4782 ram_check(0x100000, 0x200000);
4783
4784 /* Clear SLP_TYPE. */
4785 reg32 = inl(DEFAULT_PMBASE + 0x04);
4786 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4787
4788 /* Failed S3 resume, reset to come up cleanly */
4789 outb(0xe, 0xcf9);
Patrick Georgi546953c2014-11-29 10:38:17 +01004790 halt();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004791 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004792}