blob: a2ccbc36a841dfc54dafc70727b6b9d1e5b30719 [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
Stefan Taunerf13bd412017-01-07 07:26:27 +010017/* Please don't remove this. It's needed for debugging and reverse
18 * engineering more nehalem variants in the future. */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010019#ifndef REAL
20#define REAL 1
21#endif
22
23#if REAL
Kyösti Mälkki931c1dc2014-06-30 09:40:19 +030024#include <stdlib.h>
Stefan Reinauer6a001132017-07-13 02:20:27 +020025#include <compiler.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010026#include <console/console.h>
27#include <string.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010028#include <arch/io.h>
29#include <cpu/x86/msr.h>
30#include <cbmem.h>
31#include <arch/cbfs.h>
32#include <cbfs.h>
33#include <ip_checksum.h>
34#include <pc80/mc146818rtc.h>
35#include <device/pci_def.h>
Patrick Rudolph266a1f72016-06-09 18:13:34 +020036#include <device/device.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010037#include <arch/cpu.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010038#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010039#include <spd.h>
40#include "raminit.h"
Patrick Rudolph266a1f72016-06-09 18:13:34 +020041#include "chip.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010042#include <timestamp.h>
43#include <cpu/x86/mtrr.h>
44#include <cpu/intel/speedstep.h>
45#include <cpu/intel/turbo.h>
Alexander Couzens81c5c762016-03-09 03:13:45 +010046#include <northbridge/intel/common/mrc_cache.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010047#endif
48
49#if !REAL
50typedef unsigned char u8;
51typedef unsigned short u16;
52typedef unsigned int u32;
53typedef u32 device_t;
54#endif
55
56#include "nehalem.h"
57
Arthur Heymansd2d2aef2018-01-16 14:19:37 +010058#include <southbridge/intel/common/rcba.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010059#include "southbridge/intel/ibexpeak/me.h"
60
61#if REAL
62#include <delay.h>
63#endif
64
65#define NORTHBRIDGE PCI_DEV(0, 0, 0)
66#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
67#define GMA PCI_DEV (0, 0x2, 0x0)
68#define HECIDEV PCI_DEV(0, 0x16, 0)
69#define HECIBAR 0x10
70
71#define FOR_ALL_RANKS \
72 for (channel = 0; channel < NUM_CHANNELS; channel++) \
73 for (slot = 0; slot < NUM_SLOTS; slot++) \
74 for (rank = 0; rank < NUM_RANKS; rank++)
75
76#define FOR_POPULATED_RANKS \
77 for (channel = 0; channel < NUM_CHANNELS; channel++) \
78 for (slot = 0; slot < NUM_SLOTS; slot++) \
79 for (rank = 0; rank < NUM_RANKS; rank++) \
80 if (info->populated_ranks[channel][slot][rank])
81
82#define FOR_POPULATED_RANKS_BACKWARDS \
83 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
84 for (slot = 0; slot < NUM_SLOTS; slot++) \
85 for (rank = 0; rank < NUM_RANKS; rank++) \
86 if (info->populated_ranks[channel][slot][rank])
87
88/* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */
89typedef struct {
90 u8 smallest;
91 u8 largest;
92} timing_bounds_t[2][2][2][9];
93
94struct ram_training {
95 /* [TM][CHANNEL][SLOT][RANK][LANE] */
96 u16 lane_timings[4][2][2][2][9];
97 u16 reg_178;
98 u16 reg_10b;
99
100 u8 reg178_center;
101 u8 reg178_smallest;
102 u8 reg178_largest;
103 timing_bounds_t timing_bounds[2];
104 u16 timing_offset[2][2][2][9];
105 u16 timing2_offset[2][2][2][9];
106 u16 timing2_bounds[2][2][2][9][2];
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +0100107 u8 reg274265[2][3]; /* [CHANNEL][REGISTER] */
108 u8 reg2ca9_bit0;
109 u32 reg_6dc;
110 u32 reg_6e8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100111};
112
113#if !REAL
114#include "raminit_fake.c"
115#else
116
117#include <lib.h> /* Prototypes */
118
119static inline void write_mchbar32(u32 addr, u32 val)
120{
121 MCHBAR32(addr) = val;
122}
123
124static inline void write_mchbar16(u32 addr, u16 val)
125{
126 MCHBAR16(addr) = val;
127}
128
129static inline void write_mchbar8(u32 addr, u8 val)
130{
131 MCHBAR8(addr) = val;
132}
133
134
135static inline u32 read_mchbar32(u32 addr)
136{
137 return MCHBAR32(addr);
138}
139
140static inline u16 read_mchbar16(u32 addr)
141{
142 return MCHBAR16(addr);
143}
144
145static inline u8 read_mchbar8(u32 addr)
146{
147 return MCHBAR8(addr);
148}
149
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100150static void clflush(u32 addr)
151{
152 asm volatile ("clflush (%0)"::"r" (addr));
153}
154
155typedef struct _u128 {
156 u64 lo;
157 u64 hi;
158} u128;
159
160static void read128(u32 addr, u64 * out)
161{
162 u128 ret;
163 u128 stor;
164 asm volatile ("movdqu %%xmm0, %0\n"
165 "movdqa (%2), %%xmm0\n"
166 "movdqu %%xmm0, %1\n"
167 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
168 out[0] = ret.lo;
169 out[1] = ret.hi;
170}
171
172#endif
173
174/* OK */
175static void write_1d0(u32 val, u16 addr, int bits, int flag)
176{
177 write_mchbar32(0x1d0, 0);
Elyes HAOUAS7db506c2016-10-02 11:56:39 +0200178 while (read_mchbar32(0x1d0) & 0x800000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100179 write_mchbar32(0x1d4,
180 (val & ((1 << bits) - 1)) | (2 << bits) | (flag <<
181 bits));
182 write_mchbar32(0x1d0, 0x40000000 | addr);
Elyes HAOUAS7db506c2016-10-02 11:56:39 +0200183 while (read_mchbar32(0x1d0) & 0x800000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100184}
185
186/* OK */
187static u16 read_1d0(u16 addr, int split)
188{
189 u32 val;
190 write_mchbar32(0x1d0, 0);
Elyes HAOUAS7db506c2016-10-02 11:56:39 +0200191 while (read_mchbar32(0x1d0) & 0x800000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100192 write_mchbar32(0x1d0,
193 0x80000000 | (((read_mchbar8(0x246) >> 2) & 3) +
194 0x361 - addr));
Elyes HAOUAS7db506c2016-10-02 11:56:39 +0200195 while (read_mchbar32(0x1d0) & 0x800000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100196 val = read_mchbar32(0x1d8);
197 write_1d0(0, 0x33d, 0, 0);
198 write_1d0(0, 0x33d, 0, 0);
199 val &= ((1 << split) - 1);
200 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
201 return val;
202}
203
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800204static void write32p(uintptr_t addr, uint32_t val)
205{
206 write32((void *)addr, val);
207}
208
209static uint32_t read32p(uintptr_t addr)
210{
211 return read32((void *)addr);
212}
213
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100214static void sfence(void)
215{
216#if REAL
217 asm volatile ("sfence");
218#endif
219}
220
221static inline u16 get_lane_offset(int slot, int rank, int lane)
222{
223 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
224 0x452 * (lane == 8);
225}
226
227static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
228{
229 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
230 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
231}
232
233#if REAL
234static u32 gav_real(int line, u32 in)
235{
236 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
237 return in;
238}
239
240#define gav(x) gav_real (__LINE__, (x))
241#endif
242struct raminfo {
243 u16 clock_speed_index; /* clock_speed (REAL, not DDR) / 133.(3) - 3 */
244 u16 fsb_frequency; /* in 1.(1)/2 MHz. */
245 u8 is_x16_module[2][2]; /* [CHANNEL][SLOT] */
246 u8 density[2][2]; /* [CHANNEL][SLOT] */
247 u8 populated_ranks[2][2][2]; /* [CHANNEL][SLOT][RANK] */
248 int rank_start[2][2][2];
249 u8 cas_latency;
250 u8 board_lane_delay[9];
251 u8 use_ecc;
252 u8 revision;
253 u8 max_supported_clock_speed_index;
254 u8 uma_enabled;
255 u8 spd[2][2][151]; /* [CHANNEL][SLOT][BYTE] */
256 u8 silicon_revision;
257 u8 populated_ranks_mask[2];
258 u8 max_slots_used_in_channel;
259 u8 mode4030[2];
260 u16 avg4044[2];
261 u16 max4048[2];
262 unsigned total_memory_mb;
263 unsigned interleaved_part_mb;
264 unsigned non_interleaved_part_mb;
265
266 u32 heci_bar;
267 u64 heci_uma_addr;
268 unsigned memory_reserved_for_heci_mb;
269
270 struct ram_training training;
271 u32 last_500_command[2];
272
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100273 u32 delay46_ps[2];
274 u32 delay54_ps[2];
275 u8 revision_flag_1;
276 u8 some_delay_1_cycle_floor;
277 u8 some_delay_2_halfcycles_ceil;
278 u8 some_delay_3_ps_rounded;
279
280 const struct ram_training *cached_training;
281};
282
283static void
284write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
285 int flag);
286
287/* OK */
288static u16
289read_500(struct raminfo *info, int channel, u16 addr, int split)
290{
291 u32 val;
292 info->last_500_command[channel] = 0x80000000;
293 write_mchbar32(0x500 + (channel << 10), 0);
Elyes HAOUAS7db506c2016-10-02 11:56:39 +0200294 while (read_mchbar32(0x500 + (channel << 10)) & 0x800000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100295 write_mchbar32(0x500 + (channel << 10),
296 0x80000000 |
297 (((read_mchbar8(0x246 + (channel << 10)) >> 2) &
298 3) + 0xb88 - addr));
Elyes HAOUAS7db506c2016-10-02 11:56:39 +0200299 while (read_mchbar32(0x500 + (channel << 10)) & 0x800000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100300 val = read_mchbar32(0x508 + (channel << 10));
301 return val & ((1 << split) - 1);
302}
303
304/* OK */
305static void
306write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
307 int flag)
308{
309 if (info->last_500_command[channel] == 0x80000000) {
310 info->last_500_command[channel] = 0x40000000;
311 write_500(info, channel, 0, 0xb61, 0, 0);
312 }
313 write_mchbar32(0x500 + (channel << 10), 0);
Elyes HAOUAS7db506c2016-10-02 11:56:39 +0200314 while (read_mchbar32(0x500 + (channel << 10)) & 0x800000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100315 write_mchbar32(0x504 + (channel << 10),
316 (val & ((1 << bits) - 1)) | (2 << bits) | (flag <<
317 bits));
318 write_mchbar32(0x500 + (channel << 10), 0x40000000 | addr);
Elyes HAOUAS7db506c2016-10-02 11:56:39 +0200319 while (read_mchbar32(0x500 + (channel << 10)) & 0x800000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100320}
321
322static int rw_test(int rank)
323{
324 const u32 mask = 0xf00fc33c;
325 int ok = 0xff;
326 int i;
327 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800328 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100329 sfence();
330 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800331 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100332 sfence();
333 for (i = 0; i < 32; i++) {
334 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800335 write32p((rank << 28) | (i << 3), pat);
336 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100337 }
338 sfence();
339 for (i = 0; i < 32; i++) {
340 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
341 int j;
342 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800343 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100344 for (j = 0; j < 4; j++)
345 if (((val >> (j * 8)) & 0xff) != pat)
346 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800347 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100348 for (j = 0; j < 4; j++)
349 if (((val >> (j * 8)) & 0xff) != pat)
350 ok &= ~(16 << j);
351 }
352 sfence();
353 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800354 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100355 sfence();
356 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800357 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100358
359 return ok;
360}
361
362static void
363program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
364{
365 int lane;
366 for (lane = 0; lane < 8; lane++) {
367 write_500(info, channel,
368 base +
369 info->training.
370 lane_timings[2][channel][slot][rank][lane],
371 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
372 write_500(info, channel,
373 base +
374 info->training.
375 lane_timings[3][channel][slot][rank][lane],
376 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
377 }
378}
379
380static void write_26c(int channel, u16 si)
381{
382 write_mchbar32(0x26c + (channel << 10), 0x03243f35);
383 write_mchbar32(0x268 + (channel << 10), 0xcfc00000 | (si << 9));
384 write_mchbar16(0x2b9 + (channel << 10), si);
385}
386
387static u32 get_580(int channel, u8 addr)
388{
389 u32 ret;
390 gav(read_1d0(0x142, 3));
391 write_mchbar8(0x5ff, 0x0); /* OK */
392 write_mchbar8(0x5ff, 0x80); /* OK */
393 write_mchbar32(0x580 + (channel << 10), 0x8493c012 | addr);
394 write_mchbar8(0x580 + (channel << 10),
395 read_mchbar8(0x580 + (channel << 10)) | 1);
Elyes HAOUAS7db506c2016-10-02 11:56:39 +0200396 while (!((ret = read_mchbar32(0x580 + (channel << 10))) & 0x10000));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100397 write_mchbar8(0x580 + (channel << 10),
398 read_mchbar8(0x580 + (channel << 10)) & ~1);
399 return ret;
400}
401
402const int cached_config = 0;
403
404#define NUM_CHANNELS 2
405#define NUM_SLOTS 2
406#define NUM_RANKS 2
407#define RANK_SHIFT 28
408#define CHANNEL_SHIFT 10
409
410#include "raminit_tables.c"
411
412static void seq9(struct raminfo *info, int channel, int slot, int rank)
413{
414 int i, lane;
415
416 for (i = 0; i < 2; i++)
417 for (lane = 0; lane < 8; lane++)
418 write_500(info, channel,
419 info->training.lane_timings[i +
420 1][channel][slot]
421 [rank][lane], get_timing_register_addr(lane,
422 i + 1,
423 slot,
424 rank),
425 9, 0);
426
427 write_1d0(1, 0x103, 6, 1);
428 for (lane = 0; lane < 8; lane++)
429 write_500(info, channel,
430 info->training.
431 lane_timings[0][channel][slot][rank][lane],
432 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
433
434 for (i = 0; i < 2; i++) {
435 for (lane = 0; lane < 8; lane++)
436 write_500(info, channel,
437 info->training.lane_timings[i +
438 1][channel][slot]
439 [rank][lane], get_timing_register_addr(lane,
440 i + 1,
441 slot,
442 rank),
443 9, 0);
444 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
445 }
446
447 gav(read_1d0(0x142, 3)); // = 0x10408118
448 write_mchbar8(0x5ff, 0x0); /* OK */
449 write_mchbar8(0x5ff, 0x80); /* OK */
450 write_1d0(0x2, 0x142, 3, 1);
451 for (lane = 0; lane < 8; lane++) {
452 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
453 info->training.lane_timings[2][channel][slot][rank][lane] =
454 read_500(info, channel,
455 get_timing_register_addr(lane, 2, slot, rank), 9);
456 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
457 info->training.lane_timings[3][channel][slot][rank][lane] =
458 info->training.lane_timings[2][channel][slot][rank][lane] +
459 0x20;
460 }
461}
462
463static int count_ranks_in_channel(struct raminfo *info, int channel)
464{
465 int slot, rank;
466 int res = 0;
467 for (slot = 0; slot < NUM_SLOTS; slot++)
468 for (rank = 0; rank < NUM_SLOTS; rank++)
469 res += info->populated_ranks[channel][slot][rank];
470 return res;
471}
472
473static void
474config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
475{
476 int add;
477
478 write_1d0(0, 0x178, 7, 1);
479 seq9(info, channel, slot, rank);
480 program_timings(info, 0x80, channel, slot, rank);
481
482 if (channel == 0)
483 add = count_ranks_in_channel(info, 1);
484 else
485 add = 0;
486 if (!s3resume)
487 gav(rw_test(rank + add));
488 program_timings(info, 0x00, channel, slot, rank);
489 if (!s3resume)
490 gav(rw_test(rank + add));
491 if (!s3resume)
492 gav(rw_test(rank + add));
493 write_1d0(0, 0x142, 3, 1);
494 write_1d0(0, 0x103, 6, 1);
495
496 gav(get_580(channel, 0xc | (rank << 5)));
497 gav(read_1d0(0x142, 3));
498
499 write_mchbar8(0x5ff, 0x0); /* OK */
500 write_mchbar8(0x5ff, 0x80); /* OK */
501}
502
503static void set_4cf(struct raminfo *info, int channel, u8 val)
504{
505 gav(read_500(info, channel, 0x4cf, 4)); // = 0xc2300cf9
506 write_500(info, channel, val, 0x4cf, 4, 1);
507 gav(read_500(info, channel, 0x659, 4)); // = 0x80300839
508 write_500(info, channel, val, 0x659, 4, 1);
509 gav(read_500(info, channel, 0x697, 4)); // = 0x80300839
510 write_500(info, channel, val, 0x697, 4, 1);
511}
512
513static void set_334(int zero)
514{
515 int j, k, channel;
516 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
517 u32 vd8[2][16];
518
519 for (channel = 0; channel < NUM_CHANNELS; channel++) {
520 for (j = 0; j < 4; j++) {
521 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
522 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
523 u16 c;
524 if ((j == 0 || j == 3) && zero)
525 c = 0;
526 else if (j == 3)
527 c = 0x5f;
528 else
529 c = 0x5f5f;
530
531 for (k = 0; k < 2; k++) {
532 write_mchbar32(0x138 + 8 * k,
533 (channel << 26) | (j << 24));
534 gav(vd8[1][(channel << 3) | (j << 1) | k] =
535 read_mchbar32(0x138 + 8 * k));
536 gav(vd8[0][(channel << 3) | (j << 1) | k] =
537 read_mchbar32(0x13c + 8 * k));
538 }
539
540 write_mchbar32(0x334 + (channel << 10) + (j * 0x44),
541 zero ? 0 : val3[j]);
542 write_mchbar32(0x32c + (channel << 10) + (j * 0x44),
543 zero ? 0 : (0x18191819 & lmask));
544 write_mchbar16(0x34a + (channel << 10) + (j * 0x44), c);
545 write_mchbar32(0x33c + (channel << 10) + (j * 0x44),
546 zero ? 0 : (a & lmask));
547 write_mchbar32(0x344 + (channel << 10) + (j * 0x44),
548 zero ? 0 : (a & lmask));
549 }
550 }
551
552 write_mchbar32(0x130, read_mchbar32(0x130) | 1); /* OK */
Elyes HAOUAS7db506c2016-10-02 11:56:39 +0200553 while (read_mchbar8(0x130) & 1); /* OK */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100554}
555
556static void rmw_1d0(u16 addr, u32 and, u32 or, int split, int flag)
557{
558 u32 v;
559 v = read_1d0(addr, split);
560 write_1d0((v & and) | or, addr, split, flag);
561}
562
563static int find_highest_bit_set(u16 val)
564{
565 int i;
566 for (i = 15; i >= 0; i--)
567 if (val & (1 << i))
568 return i;
569 return -1;
570}
571
572static int find_lowest_bit_set32(u32 val)
573{
574 int i;
575 for (i = 0; i < 32; i++)
576 if (val & (1 << i))
577 return i;
578 return -1;
579}
580
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100581enum {
582 DEVICE_TYPE = 2,
583 MODULE_TYPE = 3,
584 DENSITY = 4,
585 RANKS_AND_DQ = 7,
586 MEMORY_BUS_WIDTH = 8,
587 TIMEBASE_DIVIDEND = 10,
588 TIMEBASE_DIVISOR = 11,
589 CYCLETIME = 12,
590
591 CAS_LATENCIES_LSB = 14,
592 CAS_LATENCIES_MSB = 15,
593 CAS_LATENCY_TIME = 16,
594 THERMAL_AND_REFRESH = 31,
595 REFERENCE_RAW_CARD_USED = 62,
596 RANK1_ADDRESS_MAPPING = 63
597};
598
599static void calculate_timings(struct raminfo *info)
600{
601 unsigned cycletime;
602 unsigned cas_latency_time;
603 unsigned supported_cas_latencies;
604 unsigned channel, slot;
605 unsigned clock_speed_index;
606 unsigned min_cas_latency;
607 unsigned cas_latency;
608 unsigned max_clock_index;
609
610 /* Find common CAS latency */
611 supported_cas_latencies = 0x3fe;
612 for (channel = 0; channel < NUM_CHANNELS; channel++)
613 for (slot = 0; slot < NUM_SLOTS; slot++)
614 if (info->populated_ranks[channel][slot][0])
615 supported_cas_latencies &=
616 2 *
617 (info->
618 spd[channel][slot][CAS_LATENCIES_LSB] |
619 (info->
620 spd[channel][slot][CAS_LATENCIES_MSB] <<
621 8));
622
623 max_clock_index = min(3, info->max_supported_clock_speed_index);
624
625 cycletime = min_cycletime[max_clock_index];
626 cas_latency_time = min_cas_latency_time[max_clock_index];
627
628 for (channel = 0; channel < NUM_CHANNELS; channel++)
629 for (slot = 0; slot < NUM_SLOTS; slot++)
630 if (info->populated_ranks[channel][slot][0]) {
631 unsigned timebase;
632 timebase =
633 1000 *
634 info->
635 spd[channel][slot][TIMEBASE_DIVIDEND] /
636 info->spd[channel][slot][TIMEBASE_DIVISOR];
637 cycletime =
638 max(cycletime,
639 timebase *
640 info->spd[channel][slot][CYCLETIME]);
641 cas_latency_time =
642 max(cas_latency_time,
643 timebase *
644 info->
645 spd[channel][slot][CAS_LATENCY_TIME]);
646 }
647 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
648 if (cycletime == min_cycletime[clock_speed_index])
649 break;
650 if (cycletime > min_cycletime[clock_speed_index]) {
651 clock_speed_index--;
652 cycletime = min_cycletime[clock_speed_index];
653 break;
654 }
655 }
Edward O'Callaghan7116ac82014-07-08 01:53:24 +1000656 min_cas_latency = CEIL_DIV(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100657 cas_latency = 0;
658 while (supported_cas_latencies) {
659 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
660 if (cas_latency <= min_cas_latency)
661 break;
662 supported_cas_latencies &=
663 ~(1 << find_highest_bit_set(supported_cas_latencies));
664 }
665
666 if (cas_latency != min_cas_latency && clock_speed_index)
667 clock_speed_index--;
668
669 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
670 die("Couldn't configure DRAM");
671 info->clock_speed_index = clock_speed_index;
672 info->cas_latency = cas_latency;
673}
674
675static void program_base_timings(struct raminfo *info)
676{
677 unsigned channel;
678 unsigned slot, rank, lane;
679 unsigned extended_silicon_revision;
680 int i;
681
682 extended_silicon_revision = info->silicon_revision;
683 if (info->silicon_revision == 0)
684 for (channel = 0; channel < NUM_CHANNELS; channel++)
685 for (slot = 0; slot < NUM_SLOTS; slot++)
686 if ((info->
687 spd[channel][slot][MODULE_TYPE] & 0xF) ==
688 3)
689 extended_silicon_revision = 4;
690
691 for (channel = 0; channel < NUM_CHANNELS; channel++) {
692 for (slot = 0; slot < NUM_SLOTS; slot++)
693 for (rank = 0; rank < NUM_SLOTS; rank++) {
694 int card_timing_2;
695 if (!info->populated_ranks[channel][slot][rank])
696 continue;
697
698 for (lane = 0; lane < 9; lane++) {
699 int tm_reg;
700 int card_timing;
701
702 card_timing = 0;
703 if ((info->
704 spd[channel][slot][MODULE_TYPE] &
705 0xF) == 3) {
706 int reference_card;
707 reference_card =
708 info->
709 spd[channel][slot]
710 [REFERENCE_RAW_CARD_USED] &
711 0x1f;
712 if (reference_card == 3)
713 card_timing =
714 u16_ffd1188[0][lane]
715 [info->
716 clock_speed_index];
717 if (reference_card == 5)
718 card_timing =
719 u16_ffd1188[1][lane]
720 [info->
721 clock_speed_index];
722 }
723
724 info->training.
725 lane_timings[0][channel][slot][rank]
726 [lane] =
727 u8_FFFD1218[info->
728 clock_speed_index];
729 info->training.
730 lane_timings[1][channel][slot][rank]
731 [lane] = 256;
732
733 for (tm_reg = 2; tm_reg < 4; tm_reg++)
734 info->training.
735 lane_timings[tm_reg]
736 [channel][slot][rank][lane]
737 =
738 u8_FFFD1240[channel]
739 [extended_silicon_revision]
740 [lane][2 * slot +
741 rank][info->
742 clock_speed_index]
743 + info->max4048[channel]
744 +
745 u8_FFFD0C78[channel]
746 [extended_silicon_revision]
747 [info->
748 mode4030[channel]][slot]
749 [rank][info->
750 clock_speed_index]
751 + card_timing;
752 for (tm_reg = 0; tm_reg < 4; tm_reg++)
753 write_500(info, channel,
754 info->training.
755 lane_timings[tm_reg]
756 [channel][slot][rank]
757 [lane],
758 get_timing_register_addr
759 (lane, tm_reg, slot,
760 rank), 9, 0);
761 }
762
763 card_timing_2 = 0;
764 if (!(extended_silicon_revision != 4
765 || (info->
766 populated_ranks_mask[channel] & 5) ==
767 5)) {
768 if ((info->
769 spd[channel][slot]
770 [REFERENCE_RAW_CARD_USED] & 0x1F)
771 == 3)
772 card_timing_2 =
773 u16_FFFE0EB8[0][info->
774 clock_speed_index];
775 if ((info->
776 spd[channel][slot]
777 [REFERENCE_RAW_CARD_USED] & 0x1F)
778 == 5)
779 card_timing_2 =
780 u16_FFFE0EB8[1][info->
781 clock_speed_index];
782 }
783
784 for (i = 0; i < 3; i++)
785 write_500(info, channel,
786 (card_timing_2 +
787 info->max4048[channel]
788 +
789 u8_FFFD0EF8[channel]
790 [extended_silicon_revision]
791 [info->
792 mode4030[channel]][info->
793 clock_speed_index]),
794 u16_fffd0c50[i][slot][rank],
795 8, 1);
796 write_500(info, channel,
797 (info->max4048[channel] +
798 u8_FFFD0C78[channel]
799 [extended_silicon_revision][info->
800 mode4030
801 [channel]]
802 [slot][rank][info->
803 clock_speed_index]),
804 u16_fffd0c70[slot][rank], 7, 1);
805 }
806 if (!info->populated_ranks_mask[channel])
807 continue;
808 for (i = 0; i < 3; i++)
809 write_500(info, channel,
810 (info->max4048[channel] +
811 info->avg4044[channel]
812 +
813 u8_FFFD17E0[channel]
814 [extended_silicon_revision][info->
815 mode4030
816 [channel]][info->
817 clock_speed_index]),
818 u16_fffd0c68[i], 8, 1);
819 }
820}
821
822static unsigned int fsbcycle_ps(struct raminfo *info)
823{
824 return 900000 / info->fsb_frequency;
825}
826
827/* The time of DDR transfer in ps. */
828static unsigned int halfcycle_ps(struct raminfo *info)
829{
830 return 3750 / (info->clock_speed_index + 3);
831}
832
833/* The time of clock cycle in ps. */
834static unsigned int cycle_ps(struct raminfo *info)
835{
836 return 2 * halfcycle_ps(info);
837}
838
839/* Frequency in 1.(1)=10/9 MHz units. */
840static unsigned frequency_11(struct raminfo *info)
841{
842 return (info->clock_speed_index + 3) * 120;
843}
844
845/* Frequency in 0.1 MHz units. */
846static unsigned frequency_01(struct raminfo *info)
847{
848 return 100 * frequency_11(info) / 9;
849}
850
851static unsigned ps_to_halfcycles(struct raminfo *info, unsigned int ps)
852{
853 return (frequency_11(info) * 2) * ps / 900000;
854}
855
856static unsigned ns_to_cycles(struct raminfo *info, unsigned int ns)
857{
858 return (frequency_11(info)) * ns / 900;
859}
860
861static void compute_derived_timings(struct raminfo *info)
862{
863 unsigned channel, slot, rank;
864 int extended_silicon_revision;
865 int some_delay_1_ps;
866 int some_delay_2_ps;
867 int some_delay_2_halfcycles_ceil;
868 int some_delay_2_halfcycles_floor;
869 int some_delay_3_ps;
870 int some_delay_3_halfcycles;
871 int some_delay_3_ps_rounded;
872 int some_delay_1_cycle_ceil;
873 int some_delay_1_cycle_floor;
874
875 some_delay_3_halfcycles = 0;
876 some_delay_3_ps_rounded = 0;
877 extended_silicon_revision = info->silicon_revision;
878 if (!info->silicon_revision)
879 for (channel = 0; channel < NUM_CHANNELS; channel++)
880 for (slot = 0; slot < NUM_SLOTS; slot++)
881 if ((info->
882 spd[channel][slot][MODULE_TYPE] & 0xF) ==
883 3)
884 extended_silicon_revision = 4;
885 if (info->board_lane_delay[7] < 5)
886 info->board_lane_delay[7] = 5;
887 info->revision_flag_1 = 2;
888 if (info->silicon_revision == 2 || info->silicon_revision == 3)
889 info->revision_flag_1 = 0;
890 if (info->revision < 16)
891 info->revision_flag_1 = 0;
892
893 if (info->revision < 8)
894 info->revision_flag_1 = 0;
895 if (info->revision >= 8 && (info->silicon_revision == 0
896 || info->silicon_revision == 1))
897 some_delay_2_ps = 735;
898 else
899 some_delay_2_ps = 750;
900
901 if (info->revision >= 0x10 && (info->silicon_revision == 0
902 || info->silicon_revision == 1))
903 some_delay_1_ps = 3929;
904 else
905 some_delay_1_ps = 3490;
906
907 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
908 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
909 if (some_delay_1_ps % cycle_ps(info))
910 some_delay_1_cycle_ceil++;
911 else
912 some_delay_1_cycle_floor--;
913 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
914 if (info->revision_flag_1)
915 some_delay_2_ps = halfcycle_ps(info) >> 6;
916 some_delay_2_ps +=
917 max(some_delay_1_ps - 30,
918 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
919 375;
920 some_delay_3_ps =
921 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
922 if (info->revision_flag_1) {
923 if (some_delay_3_ps < 150)
924 some_delay_3_halfcycles = 0;
925 else
926 some_delay_3_halfcycles =
927 (some_delay_3_ps << 6) / halfcycle_ps(info);
928 some_delay_3_ps_rounded =
929 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
930 }
931 some_delay_2_halfcycles_ceil =
932 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
933 2 * (some_delay_1_cycle_ceil - 1);
934 if (info->revision_flag_1 && some_delay_3_ps < 150)
935 some_delay_2_halfcycles_ceil++;
936 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
937 if (info->revision < 0x10)
938 some_delay_2_halfcycles_floor =
939 some_delay_2_halfcycles_ceil - 1;
940 if (!info->revision_flag_1)
941 some_delay_2_halfcycles_floor++;
942 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
943 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
944 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
945 || (info->populated_ranks[1][0][0]
946 && info->populated_ranks[1][1][0]))
947 info->max_slots_used_in_channel = 2;
948 else
949 info->max_slots_used_in_channel = 1;
950 for (channel = 0; channel < 2; channel++)
951 write_mchbar32(0x244 + (channel << 10),
952 ((info->revision < 8) ? 1 : 0x200)
953 | ((2 - info->max_slots_used_in_channel) << 17) |
954 (channel << 21) | (info->
955 some_delay_1_cycle_floor <<
956 18) | 0x9510);
957 if (info->max_slots_used_in_channel == 1) {
958 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
959 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
960 } else {
961 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 */
962 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
963 || (count_ranks_in_channel(info, 1) ==
964 2)) ? 2 : 3;
965 }
966 for (channel = 0; channel < NUM_CHANNELS; channel++) {
967 int max_of_unk;
968 int min_of_unk_2;
969
970 int i, count;
971 int sum;
972
973 if (!info->populated_ranks_mask[channel])
974 continue;
975
976 max_of_unk = 0;
977 min_of_unk_2 = 32767;
978
979 sum = 0;
980 count = 0;
981 for (i = 0; i < 3; i++) {
982 int unk1;
983 if (info->revision < 8)
984 unk1 =
985 u8_FFFD1891[0][channel][info->
986 clock_speed_index]
987 [i];
988 else if (!
989 (info->revision >= 0x10
990 || info->revision_flag_1))
991 unk1 =
992 u8_FFFD1891[1][channel][info->
993 clock_speed_index]
994 [i];
995 else
996 unk1 = 0;
997 for (slot = 0; slot < NUM_SLOTS; slot++)
998 for (rank = 0; rank < NUM_RANKS; rank++) {
999 int a = 0;
1000 int b = 0;
1001
1002 if (!info->
1003 populated_ranks[channel][slot]
1004 [rank])
1005 continue;
1006 if (extended_silicon_revision == 4
1007 && (info->
1008 populated_ranks_mask[channel] &
1009 5) != 5) {
1010 if ((info->
1011 spd[channel][slot]
1012 [REFERENCE_RAW_CARD_USED] &
1013 0x1F) == 3) {
1014 a = u16_ffd1178[0]
1015 [info->
1016 clock_speed_index];
1017 b = u16_fe0eb8[0][info->
1018 clock_speed_index];
1019 } else
1020 if ((info->
1021 spd[channel][slot]
1022 [REFERENCE_RAW_CARD_USED]
1023 & 0x1F) == 5) {
1024 a = u16_ffd1178[1]
1025 [info->
1026 clock_speed_index];
1027 b = u16_fe0eb8[1][info->
1028 clock_speed_index];
1029 }
1030 }
1031 min_of_unk_2 = min(min_of_unk_2, a);
1032 min_of_unk_2 = min(min_of_unk_2, b);
1033 if (rank == 0) {
1034 sum += a;
1035 count++;
1036 }
1037 {
1038 int t;
1039 t = b +
1040 u8_FFFD0EF8[channel]
1041 [extended_silicon_revision]
1042 [info->
1043 mode4030[channel]][info->
1044 clock_speed_index];
1045 if (unk1 >= t)
1046 max_of_unk =
1047 max(max_of_unk,
1048 unk1 - t);
1049 }
1050 }
1051 {
1052 int t =
1053 u8_FFFD17E0[channel]
1054 [extended_silicon_revision][info->
1055 mode4030
1056 [channel]]
1057 [info->clock_speed_index] + min_of_unk_2;
1058 if (unk1 >= t)
1059 max_of_unk = max(max_of_unk, unk1 - t);
1060 }
1061 }
1062
1063 info->avg4044[channel] = sum / count;
1064 info->max4048[channel] = max_of_unk;
1065 }
1066}
1067
1068static void jedec_read(struct raminfo *info,
1069 int channel, int slot, int rank,
1070 int total_rank, u8 addr3, unsigned int value)
1071{
1072 /* Handle mirrored mapping. */
1073 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1074 addr3 =
1075 (addr3 & 0xCF) | ((addr3 & 0x10) << 1) | ((addr3 >> 1) &
1076 0x10);
1077 write_mchbar8(0x271, addr3 | (read_mchbar8(0x271) & 0xC1));
1078 write_mchbar8(0x671, addr3 | (read_mchbar8(0x671) & 0xC1));
1079
1080 /* Handle mirrored mapping. */
1081 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1082 value =
1083 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1084 << 1);
1085
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001086 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001087
1088 write_mchbar8(0x271, (read_mchbar8(0x271) & 0xC3) | 2);
1089 write_mchbar8(0x671, (read_mchbar8(0x671) & 0xC3) | 2);
1090
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001091 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001092}
1093
1094enum {
1095 MR1_RZQ12 = 512,
1096 MR1_RZQ2 = 64,
1097 MR1_RZQ4 = 4,
1098 MR1_ODS34OHM = 2
1099};
1100
1101enum {
1102 MR0_BT_INTERLEAVED = 8,
1103 MR0_DLL_RESET_ON = 256
1104};
1105
1106enum {
1107 MR2_RTT_WR_DISABLED = 0,
1108 MR2_RZQ2 = 1 << 10
1109};
1110
1111static void jedec_init(struct raminfo *info)
1112{
1113 int write_recovery;
1114 int channel, slot, rank;
1115 int total_rank;
1116 int dll_on;
1117 int self_refresh_temperature;
1118 int auto_self_refresh;
1119
1120 auto_self_refresh = 1;
1121 self_refresh_temperature = 1;
1122 if (info->board_lane_delay[3] <= 10) {
1123 if (info->board_lane_delay[3] <= 8)
1124 write_recovery = info->board_lane_delay[3] - 4;
1125 else
1126 write_recovery = 5;
1127 } else {
1128 write_recovery = 6;
1129 }
1130 FOR_POPULATED_RANKS {
1131 auto_self_refresh &=
1132 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1133 self_refresh_temperature &=
1134 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1135 }
1136 if (auto_self_refresh == 1)
1137 self_refresh_temperature = 0;
1138
1139 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1140 || (info->populated_ranks[0][0][0]
1141 && info->populated_ranks[0][1][0])
1142 || (info->populated_ranks[1][0][0]
1143 && info->populated_ranks[1][1][0]));
1144
1145 total_rank = 0;
1146
1147 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1148 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1149 int rzq_reg58e;
1150
1151 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1152 rzq_reg58e = 64;
1153 rtt = MR1_RZQ2;
1154 if (info->clock_speed_index != 0) {
1155 rzq_reg58e = 4;
1156 if (info->populated_ranks_mask[channel] == 3)
1157 rtt = MR1_RZQ4;
1158 }
1159 } else {
1160 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1161 rtt = MR1_RZQ12;
1162 rzq_reg58e = 64;
1163 rtt_wr = MR2_RZQ2;
1164 } else {
1165 rzq_reg58e = 4;
1166 rtt = MR1_RZQ4;
1167 }
1168 }
1169
1170 write_mchbar16(0x588 + (channel << 10), 0x0);
1171 write_mchbar16(0x58a + (channel << 10), 0x4);
1172 write_mchbar16(0x58c + (channel << 10), rtt | MR1_ODS34OHM);
1173 write_mchbar16(0x58e + (channel << 10), rzq_reg58e | 0x82);
1174 write_mchbar16(0x590 + (channel << 10), 0x1282);
1175
1176 for (slot = 0; slot < NUM_SLOTS; slot++)
1177 for (rank = 0; rank < NUM_RANKS; rank++)
1178 if (info->populated_ranks[channel][slot][rank]) {
1179 jedec_read(info, channel, slot, rank,
1180 total_rank, 0x28,
1181 rtt_wr | (info->
1182 clock_speed_index
1183 << 3)
1184 | (auto_self_refresh << 6) |
1185 (self_refresh_temperature <<
1186 7));
1187 jedec_read(info, channel, slot, rank,
1188 total_rank, 0x38, 0);
1189 jedec_read(info, channel, slot, rank,
1190 total_rank, 0x18,
1191 rtt | MR1_ODS34OHM);
1192 jedec_read(info, channel, slot, rank,
1193 total_rank, 6,
1194 (dll_on << 12) |
1195 (write_recovery << 9)
1196 | ((info->cas_latency - 4) <<
1197 4) | MR0_BT_INTERLEAVED |
1198 MR0_DLL_RESET_ON);
1199 total_rank++;
1200 }
1201 }
1202}
1203
1204static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1205{
1206 unsigned channel, slot, rank;
1207 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1208 unsigned int channel_0_non_interleaved;
1209
1210 FOR_ALL_RANKS {
1211 if (info->populated_ranks[channel][slot][rank]) {
1212 total_mb[channel] +=
1213 pre_jedec ? 256 : (256 << info->
1214 density[channel][slot] >> info->
1215 is_x16_module[channel][slot]);
1216 write_mchbar8(0x208 + rank + 2 * slot + (channel << 10),
1217 (pre_jedec ? (1 | ((1 + 1) << 1))
1218 : (info->
1219 is_x16_module[channel][slot] |
1220 ((info->density[channel][slot] +
1221 1) << 1))) | 0x80);
1222 }
1223 write_mchbar16(0x200 + (channel << 10) + 4 * slot + 2 * rank,
1224 total_mb[channel] >> 6);
1225 }
1226
1227 info->total_memory_mb = total_mb[0] + total_mb[1];
1228
1229 info->interleaved_part_mb =
1230 pre_jedec ? 0 : 2 * min(total_mb[0], total_mb[1]);
1231 info->non_interleaved_part_mb =
1232 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1233 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
1234 write_mchbar32(0x100,
1235 channel_0_non_interleaved | (info->
1236 non_interleaved_part_mb <<
1237 16));
1238 if (!pre_jedec)
1239 write_mchbar16(0x104, info->interleaved_part_mb);
1240}
1241
1242static void program_board_delay(struct raminfo *info)
1243{
1244 int cas_latency_shift;
1245 int some_delay_ns;
1246 int some_delay_3_half_cycles;
1247
1248 unsigned channel, i;
1249 int high_multiplier;
1250 int lane_3_delay;
1251 int cas_latency_derived;
1252
1253 high_multiplier = 0;
1254 some_delay_ns = 200;
1255 some_delay_3_half_cycles = 4;
1256 cas_latency_shift = info->silicon_revision == 0
1257 || info->silicon_revision == 1 ? 1 : 0;
1258 if (info->revision < 8) {
1259 some_delay_ns = 600;
1260 cas_latency_shift = 0;
1261 }
1262 {
1263 int speed_bit;
1264 speed_bit =
1265 ((info->clock_speed_index > 1
1266 || (info->silicon_revision != 2
1267 && info->silicon_revision != 3))) ^ (info->revision >=
1268 0x10);
1269 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1270 3, 1);
1271 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1272 3, 1);
1273 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1274 && (info->silicon_revision == 2
1275 || info->silicon_revision == 3))
1276 rmw_1d0(0x116, 5, 2, 4, 1);
1277 }
1278 write_mchbar32(0x120,
1279 (1 << (info->max_slots_used_in_channel + 28)) |
1280 0x188e7f9f);
1281
1282 write_mchbar8(0x124,
1283 info->board_lane_delay[4] +
1284 ((frequency_01(info) + 999) / 1000));
1285 write_mchbar16(0x125, 0x1360);
1286 write_mchbar8(0x127, 0x40);
1287 if (info->fsb_frequency < frequency_11(info) / 2) {
1288 unsigned some_delay_2_half_cycles;
1289 high_multiplier = 1;
1290 some_delay_2_half_cycles = ps_to_halfcycles(info,
1291 ((3 *
1292 fsbcycle_ps(info))
1293 >> 1) +
1294 (halfcycle_ps(info)
1295 *
1296 reg178_min[info->
1297 clock_speed_index]
1298 >> 6)
1299 +
1300 4 *
1301 halfcycle_ps(info)
1302 + 2230);
1303 some_delay_3_half_cycles =
1304 min((some_delay_2_half_cycles +
1305 (frequency_11(info) * 2) * (28 -
1306 some_delay_2_half_cycles) /
1307 (frequency_11(info) * 2 -
1308 4 * (info->fsb_frequency))) >> 3, 7);
1309 }
1310 if (read_mchbar8(0x2ca9) & 1)
1311 some_delay_3_half_cycles = 3;
1312 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1313 write_mchbar32(0x220 + (channel << 10),
1314 read_mchbar32(0x220 +
1315 (channel << 10)) | 0x18001117);
1316 write_mchbar32(0x224 + (channel << 10),
1317 (info->max_slots_used_in_channel - 1)
1318 |
1319 ((info->cas_latency - 5 -
1320 info->clock_speed_index) << 21)
1321 |
1322 ((info->max_slots_used_in_channel +
1323 info->cas_latency - cas_latency_shift -
1324 4) << 16)
1325 | ((info->cas_latency - cas_latency_shift - 4) <<
1326 26)
1327 |
1328 ((info->cas_latency - info->clock_speed_index +
1329 info->max_slots_used_in_channel - 6) << 8));
1330 write_mchbar32(0x228 + (channel << 10),
1331 info->max_slots_used_in_channel);
1332 write_mchbar8(0x239 + (channel << 10), 32);
1333 write_mchbar32(0x248 + (channel << 10),
1334 (high_multiplier << 24) |
1335 (some_delay_3_half_cycles << 25) | 0x840000);
1336 write_mchbar32(0x278 + (channel << 10), 0xc362042);
1337 write_mchbar32(0x27c + (channel << 10), 0x8b000062);
1338 write_mchbar32(0x24c + (channel << 10),
1339 ((! !info->
1340 clock_speed_index) << 17) | (((2 +
1341 info->
1342 clock_speed_index
1343 -
1344 (! !info->
1345 clock_speed_index)))
1346 << 12) | 0x10200);
1347
1348 write_mchbar8(0x267 + (channel << 10), 0x4);
1349 write_mchbar16(0x272 + (channel << 10), 0x155);
1350 write_mchbar32(0x2bc + (channel << 10),
1351 (read_mchbar32(0x2bc + (channel << 10)) &
1352 0xFF000000)
1353 | 0x707070);
1354
1355 write_500(info, channel,
1356 ((!info->populated_ranks[channel][1][1])
1357 | (!info->populated_ranks[channel][1][0] << 1)
1358 | (!info->populated_ranks[channel][0][1] << 2)
1359 | (!info->populated_ranks[channel][0][0] << 3)),
1360 0x4c9, 4, 1);
1361 }
1362
1363 write_mchbar8(0x2c4, ((1 + (info->clock_speed_index != 0)) << 6) | 0xC);
1364 {
1365 u8 freq_divisor = 2;
1366 if (info->fsb_frequency == frequency_11(info))
1367 freq_divisor = 3;
1368 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1369 freq_divisor = 1;
1370 else
1371 freq_divisor = 2;
1372 write_mchbar32(0x2c0, (freq_divisor << 11) | 0x6009c400);
1373 }
1374
1375 if (info->board_lane_delay[3] <= 10) {
1376 if (info->board_lane_delay[3] <= 8)
1377 lane_3_delay = info->board_lane_delay[3];
1378 else
1379 lane_3_delay = 10;
1380 } else {
1381 lane_3_delay = 12;
1382 }
1383 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1384 if (info->clock_speed_index > 1)
1385 cas_latency_derived++;
1386 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1387 write_mchbar32(0x240 + (channel << 10),
1388 ((info->clock_speed_index ==
1389 0) * 0x11000) | 0x1002100 | ((2 +
1390 info->
1391 clock_speed_index)
1392 << 4) | (info->
1393 cas_latency
1394 - 3));
1395 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1396 0x609, 6, 1);
1397 write_500(info, channel,
1398 info->clock_speed_index + 2 * info->cas_latency - 7,
1399 0x601, 6, 1);
1400
1401 write_mchbar32(0x250 + (channel << 10),
1402 ((lane_3_delay + info->clock_speed_index +
1403 9) << 6)
1404 | (info->board_lane_delay[7] << 2) | (info->
1405 board_lane_delay
1406 [4] << 16)
1407 | (info->board_lane_delay[1] << 25) | (info->
1408 board_lane_delay
1409 [1] << 29)
1410 | 1);
1411 write_mchbar32(0x254 + (channel << 10),
1412 (info->
1413 board_lane_delay[1] >> 3) | ((info->
1414 board_lane_delay
1415 [8] +
1416 4 *
1417 info->
1418 use_ecc) << 6) |
1419 0x80 | (info->board_lane_delay[6] << 1) | (info->
1420 board_lane_delay
1421 [2] <<
1422 28) |
1423 (cas_latency_derived << 16) | 0x4700000);
1424 write_mchbar32(0x258 + (channel << 10),
1425 ((info->board_lane_delay[5] +
1426 info->clock_speed_index +
1427 9) << 12) | ((info->clock_speed_index -
1428 info->cas_latency + 12) << 8)
1429 | (info->board_lane_delay[2] << 17) | (info->
1430 board_lane_delay
1431 [4] << 24)
1432 | 0x47);
1433 write_mchbar32(0x25c + (channel << 10),
1434 (info->board_lane_delay[1] << 1) | (info->
1435 board_lane_delay
1436 [0] << 8) |
1437 0x1da50000);
1438 write_mchbar8(0x264 + (channel << 10), 0xff);
1439 write_mchbar8(0x5f8 + (channel << 10),
1440 (cas_latency_shift << 3) | info->use_ecc);
1441 }
1442
1443 program_modules_memory_map(info, 1);
1444
1445 write_mchbar16(0x610,
1446 (min(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
1447 | (read_mchbar16(0x610) & 0x1C3) | 0x3C);
1448 write_mchbar16(0x612, read_mchbar16(0x612) | 0x100);
1449 write_mchbar16(0x214, read_mchbar16(0x214) | 0x3E00);
1450 for (i = 0; i < 8; i++) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001451 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0x80 + 4 * i,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001452 (info->total_memory_mb - 64) | !i | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001453 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0xc0 + 4 * i, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001454 }
1455}
1456
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001457#define DEFAULT_PCI_MMIO_SIZE 2048
1458#define HOST_BRIDGE PCI_DEVFN(0, 0)
1459
1460static unsigned int get_mmio_size(void)
1461{
1462 const struct device *dev;
1463 const struct northbridge_intel_nehalem_config *cfg = NULL;
1464
1465 dev = dev_find_slot(0, HOST_BRIDGE);
1466 if (dev)
1467 cfg = dev->chip_info;
1468
1469 /* If this is zero, it just means devicetree.cb didn't set it */
1470 if (!cfg || cfg->pci_mmio_size == 0)
1471 return DEFAULT_PCI_MMIO_SIZE;
1472 else
1473 return cfg->pci_mmio_size;
1474}
1475
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001476#define BETTER_MEMORY_MAP 0
1477
1478static void program_total_memory_map(struct raminfo *info)
1479{
1480 unsigned int TOM, TOLUD, TOUUD;
1481 unsigned int quickpath_reserved;
1482 unsigned int REMAPbase;
1483 unsigned int uma_base_igd;
1484 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001485 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001486 int memory_remap;
1487 unsigned int memory_map[8];
1488 int i;
1489 unsigned int current_limit;
1490 unsigned int tseg_base;
1491 int uma_size_igd = 0, uma_size_gtt = 0;
1492
1493 memset(memory_map, 0, sizeof(memory_map));
1494
1495#if REAL
1496 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001497 u16 t = pci_read_config16(NORTHBRIDGE, D0F0_GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001498 gav(t);
1499 const int uma_sizes_gtt[16] =
1500 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1501 /* Igd memory */
1502 const int uma_sizes_igd[16] = {
1503 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1504 256, 512
1505 };
1506
1507 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1508 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1509 }
1510#endif
1511
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001512 mmio_size = get_mmio_size();
1513
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001514 TOM = info->total_memory_mb;
1515 if (TOM == 4096)
1516 TOM = 4032;
1517 TOUUD = ALIGN_DOWN(TOM - info->memory_reserved_for_heci_mb, 64);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001518 TOLUD = ALIGN_DOWN(min(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001519 , TOUUD), 64);
1520 memory_remap = 0;
1521 if (TOUUD - TOLUD > 64) {
1522 memory_remap = 1;
1523 REMAPbase = max(4096, TOUUD);
1524 TOUUD = TOUUD - TOLUD + 4096;
1525 }
1526 if (TOUUD > 4096)
1527 memory_map[2] = TOUUD | 1;
1528 quickpath_reserved = 0;
1529
1530 {
1531 u32 t;
1532
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001533 gav(t = pci_read_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 0x68));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001534 if (t & 0x800)
1535 quickpath_reserved =
1536 (1 << find_lowest_bit_set32(t >> 20));
1537 }
1538 if (memory_remap)
1539 TOUUD -= quickpath_reserved;
1540
1541#if !REAL
1542 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001543 u16 t = pci_read_config16(NORTHBRIDGE, D0F0_GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001544 gav(t);
1545 const int uma_sizes_gtt[16] =
1546 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1547 /* Igd memory */
1548 const int uma_sizes_igd[16] = {
1549 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1550 256, 512
1551 };
1552
1553 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1554 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1555 }
1556#endif
1557
1558 uma_base_igd = TOLUD - uma_size_igd;
1559 uma_base_gtt = uma_base_igd - uma_size_gtt;
1560 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1561 if (!memory_remap)
1562 tseg_base -= quickpath_reserved;
1563 tseg_base = ALIGN_DOWN(tseg_base, 8);
1564
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001565 pci_write_config16(NORTHBRIDGE, D0F0_TOLUD, TOLUD << 4);
1566 pci_write_config16(NORTHBRIDGE, D0F0_TOM, TOM >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001567 if (memory_remap) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001568 pci_write_config16(NORTHBRIDGE, D0F0_REMAPBASE, REMAPbase >> 6);
1569 pci_write_config16(NORTHBRIDGE, D0F0_REMAPLIMIT, (TOUUD - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001570 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001571 pci_write_config16(NORTHBRIDGE, D0F0_TOUUD, TOUUD);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001572
1573 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001574 pci_write_config32(NORTHBRIDGE, D0F0_IGD_BASE, uma_base_igd << 20);
1575 pci_write_config32(NORTHBRIDGE, D0F0_GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001576 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001577 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001578
1579 current_limit = 0;
1580 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1581 memory_map[1] = 4096;
1582 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
1583 current_limit = max(current_limit, memory_map[i] & ~1);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001584 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0x80,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001585 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1586 1, 64) | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001587 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0xc0, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001588 }
1589}
1590
1591static void collect_system_info(struct raminfo *info)
1592{
1593 u32 capid0[3];
1594 int i;
1595 unsigned channel;
1596
1597 /* Wait for some bit, maybe TXT clear. */
Elyes HAOUAS7db506c2016-10-02 11:56:39 +02001598 while (!(read8((u8 *)0xfed40000) & (1 << 7)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001599
1600 if (!info->heci_bar)
1601 gav(info->heci_bar =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001602 pci_read_config32(HECIDEV, HECIBAR) & 0xFFFFFFF8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001603 if (!info->memory_reserved_for_heci_mb) {
1604 /* Wait for ME to be ready */
1605 intel_early_me_init();
1606 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1607 }
1608
1609 for (i = 0; i < 3; i++)
1610 gav(capid0[i] =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001611 pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 | (i << 2)));
1612 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001613 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1614
1615 if ((capid0[1] >> 11) & 1)
1616 info->uma_enabled = 0;
1617 else
1618 gav(info->uma_enabled =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001619 pci_read_config8(NORTHBRIDGE, D0F0_DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001620 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1621 info->silicon_revision = 0;
1622
1623 if (capid0[2] & 2) {
1624 info->silicon_revision = 0;
1625 info->max_supported_clock_speed_index = 2;
1626 for (channel = 0; channel < NUM_CHANNELS; channel++)
1627 if (info->populated_ranks[channel][0][0]
1628 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1629 3) {
1630 info->silicon_revision = 2;
1631 info->max_supported_clock_speed_index = 1;
1632 }
1633 } else {
1634 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1635 case 1:
1636 case 2:
1637 info->silicon_revision = 3;
1638 break;
1639 case 3:
1640 info->silicon_revision = 0;
1641 break;
1642 case 0:
1643 info->silicon_revision = 2;
1644 break;
1645 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001646 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001647 case 0x40:
1648 info->silicon_revision = 0;
1649 break;
1650 case 0x48:
1651 info->silicon_revision = 1;
1652 break;
1653 }
1654 }
1655}
1656
1657static void write_training_data(struct raminfo *info)
1658{
1659 int tm, channel, slot, rank, lane;
1660 if (info->revision < 8)
1661 return;
1662
1663 for (tm = 0; tm < 4; tm++)
1664 for (channel = 0; channel < NUM_CHANNELS; channel++)
1665 for (slot = 0; slot < NUM_SLOTS; slot++)
1666 for (rank = 0; rank < NUM_RANKS; rank++)
1667 for (lane = 0; lane < 9; lane++)
1668 write_500(info, channel,
1669 info->
1670 cached_training->
1671 lane_timings[tm]
1672 [channel][slot][rank]
1673 [lane],
1674 get_timing_register_addr
1675 (lane, tm, slot,
1676 rank), 9, 0);
1677 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1678 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1679}
1680
1681static void dump_timings(struct raminfo *info)
1682{
1683#if REAL
1684 int channel, slot, rank, lane, i;
1685 printk(BIOS_DEBUG, "Timings:\n");
1686 FOR_POPULATED_RANKS {
1687 printk(BIOS_DEBUG, "channel %d, slot %d, rank %d\n", channel,
1688 slot, rank);
1689 for (lane = 0; lane < 9; lane++) {
1690 printk(BIOS_DEBUG, "lane %d: ", lane);
1691 for (i = 0; i < 4; i++) {
1692 printk(BIOS_DEBUG, "%x (%x) ",
1693 read_500(info, channel,
1694 get_timing_register_addr
1695 (lane, i, slot, rank),
1696 9),
1697 info->training.
1698 lane_timings[i][channel][slot][rank]
1699 [lane]);
1700 }
1701 printk(BIOS_DEBUG, "\n");
1702 }
1703 }
1704 printk(BIOS_DEBUG, "[178] = %x (%x)\n", read_1d0(0x178, 7),
1705 info->training.reg_178);
1706 printk(BIOS_DEBUG, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
1707 info->training.reg_10b);
1708#endif
1709}
1710
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001711/* Read timings and other registers that need to be restored verbatim and
1712 put them to CBMEM.
1713 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001714static void save_timings(struct raminfo *info)
1715{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001716 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001717 int channel, slot, rank, lane, i;
1718
1719 train = info->training;
1720 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1721 for (i = 0; i < 4; i++)
1722 train.lane_timings[i][channel][slot][rank][lane] =
1723 read_500(info, channel,
1724 get_timing_register_addr(lane, i, slot,
1725 rank), 9);
1726 train.reg_178 = read_1d0(0x178, 7);
1727 train.reg_10b = read_1d0(0x10b, 6);
1728
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001729 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1730 u32 reg32;
1731 reg32 = read_mchbar32 ((channel << 10) + 0x274);
1732 train.reg274265[channel][0] = reg32 >> 16;
1733 train.reg274265[channel][1] = reg32 & 0xffff;
1734 train.reg274265[channel][2] = read_mchbar16 ((channel << 10) + 0x265) >> 8;
1735 }
1736 train.reg2ca9_bit0 = read_mchbar8(0x2ca9) & 1;
1737 train.reg_6dc = read_mchbar32 (0x6dc);
1738 train.reg_6e8 = read_mchbar32 (0x6e8);
1739
1740 printk (BIOS_SPEW, "[6dc] = %x\n", train.reg_6dc);
1741 printk (BIOS_SPEW, "[6e8] = %x\n", train.reg_6e8);
1742
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001743 /* Save the MRC S3 restore data to cbmem */
Patrick Rudolphbb9c90a2016-05-29 17:05:06 +02001744 store_current_mrc_cache(&train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001745}
1746
1747#if REAL
1748static const struct ram_training *get_cached_training(void)
1749{
1750 struct mrc_data_container *cont;
1751 cont = find_current_mrc_cache();
1752 if (!cont)
1753 return 0;
1754 return (void *)cont->mrc_data;
1755}
1756#endif
1757
1758/* FIXME: add timeout. */
1759static void wait_heci_ready(void)
1760{
Elyes HAOUAS7db506c2016-10-02 11:56:39 +02001761 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)); // = 0x8000000c
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001762 write32((DEFAULT_HECIBAR + 0x4),
1763 (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001764}
1765
1766/* FIXME: add timeout. */
1767static void wait_heci_cb_avail(int len)
1768{
1769 union {
1770 struct mei_csr csr;
1771 u32 raw;
1772 } csr;
1773
Elyes HAOUAS7db506c2016-10-02 11:56:39 +02001774 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001775
1776 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001777 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001778 while (len >
1779 csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
1780 csr.csr.buffer_read_ptr));
1781}
1782
1783static void send_heci_packet(struct mei_header *head, u32 * payload)
1784{
1785 int len = (head->length + 3) / 4;
1786 int i;
1787
1788 wait_heci_cb_avail(len + 1);
1789
1790 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001791 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001792 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001793 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001794
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001795 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1796 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001797}
1798
1799static void
1800send_heci_message(u8 * msg, int len, u8 hostaddress, u8 clientaddress)
1801{
1802 struct mei_header head;
1803 int maxlen;
1804
1805 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001806 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001807
1808 while (len) {
1809 int cur = len;
1810 if (cur > maxlen) {
1811 cur = maxlen;
1812 head.is_complete = 0;
1813 } else
1814 head.is_complete = 1;
1815 head.length = cur;
1816 head.reserved = 0;
1817 head.client_address = clientaddress;
1818 head.host_address = hostaddress;
1819 send_heci_packet(&head, (u32 *) msg);
1820 len -= cur;
1821 msg += cur;
1822 }
1823}
1824
1825/* FIXME: Add timeout. */
1826static int
1827recv_heci_packet(struct raminfo *info, struct mei_header *head, u32 * packet,
1828 u32 * packet_size)
1829{
1830 union {
1831 struct mei_csr csr;
1832 u32 raw;
1833 } csr;
1834 int i = 0;
1835
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001836 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001837 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001838 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001839#if !REAL
1840 if (i++ > 346)
1841 return -1;
1842#endif
1843 }
1844 while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001845 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001846 if (!head->length) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001847 write32(DEFAULT_HECIBAR + 0x4,
1848 read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001849 *packet_size = 0;
1850 return 0;
1851 }
1852 if (head->length + 4 > 4 * csr.csr.buffer_depth
1853 || head->length > *packet_size) {
1854 *packet_size = 0;
1855 return -1;
1856 }
1857
1858 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001859 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001860 while ((head->length + 3) >> 2 >
1861 csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr);
1862
1863 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001864 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001865 *packet_size = head->length;
1866 if (!csr.csr.ready)
1867 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001868 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001869 return 0;
1870}
1871
1872/* FIXME: Add timeout. */
1873static int
1874recv_heci_message(struct raminfo *info, u32 * message, u32 * message_size)
1875{
1876 struct mei_header head;
1877 int current_position;
1878
1879 current_position = 0;
1880 while (1) {
1881 u32 current_size;
1882 current_size = *message_size - current_position;
1883 if (recv_heci_packet
1884 (info, &head, message + (current_position >> 2),
1885 &current_size) == -1)
1886 break;
1887 if (!current_size)
1888 break;
1889 current_position += current_size;
1890 if (head.is_complete) {
1891 *message_size = current_position;
1892 return 0;
1893 }
1894
1895 if (current_position >= *message_size)
1896 break;
1897 }
1898 *message_size = 0;
1899 return -1;
1900}
1901
1902static void send_heci_uma_message(struct raminfo *info)
1903{
1904 struct uma_reply {
1905 u8 group_id;
1906 u8 command;
1907 u8 reserved;
1908 u8 result;
1909 u8 field2;
1910 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001911 } __packed reply;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001912 struct uma_message {
1913 u8 group_id;
1914 u8 cmd;
1915 u8 reserved;
1916 u8 result;
1917 u32 c2;
1918 u64 heci_uma_addr;
1919 u32 memory_reserved_for_heci_mb;
1920 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001921 } __packed msg = {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001922 0, MKHI_SET_UMA, 0, 0,
1923 0x82,
1924 info->heci_uma_addr, info->memory_reserved_for_heci_mb, 0};
1925 u32 reply_size;
1926
1927 send_heci_message((u8 *) & msg, sizeof(msg), 0, 7);
1928
1929 reply_size = sizeof(reply);
1930 if (recv_heci_message(info, (u32 *) & reply, &reply_size) == -1)
1931 return;
1932
1933 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1934 die("HECI init failed\n");
1935}
1936
1937static void setup_heci_uma(struct raminfo *info)
1938{
1939 u32 reg44;
1940
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001941 reg44 = pci_read_config32(HECIDEV, 0x44); // = 0x80010020
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001942 info->memory_reserved_for_heci_mb = 0;
1943 info->heci_uma_addr = 0;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001944 if (!((reg44 & 0x10000) && !(pci_read_config32(HECIDEV, 0x40) & 0x20)))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001945 return;
1946
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001947 info->heci_bar = pci_read_config32(HECIDEV, 0x10) & 0xFFFFFFF0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001948 info->memory_reserved_for_heci_mb = reg44 & 0x3f;
1949 info->heci_uma_addr =
1950 ((u64)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001951 ((((u64) pci_read_config16(NORTHBRIDGE, D0F0_TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001952 info->memory_reserved_for_heci_mb)) << 20;
1953
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001954 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001955 if (info->memory_reserved_for_heci_mb) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001956 write32(DEFAULT_DMIBAR + 0x14,
1957 read32(DEFAULT_DMIBAR + 0x14) & ~0x80);
1958 write32(DEFAULT_RCBA + 0x14,
1959 read32(DEFAULT_RCBA + 0x14) & ~0x80);
1960 write32(DEFAULT_DMIBAR + 0x20,
1961 read32(DEFAULT_DMIBAR + 0x20) & ~0x80);
1962 write32(DEFAULT_RCBA + 0x20,
1963 read32(DEFAULT_RCBA + 0x20) & ~0x80);
1964 write32(DEFAULT_DMIBAR + 0x2c,
1965 read32(DEFAULT_DMIBAR + 0x2c) & ~0x80);
1966 write32(DEFAULT_RCBA + 0x30,
1967 read32(DEFAULT_RCBA + 0x30) & ~0x80);
1968 write32(DEFAULT_DMIBAR + 0x38,
1969 read32(DEFAULT_DMIBAR + 0x38) & ~0x80);
1970 write32(DEFAULT_RCBA + 0x40,
1971 read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001972
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001973 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
1974 write32(DEFAULT_DMIBAR + 0x38, 0x87000080); // OK
1975 while (read16(DEFAULT_RCBA + 0x46) & 2
Elyes HAOUAS7db506c2016-10-02 11:56:39 +02001976 && read16(DEFAULT_DMIBAR + 0x3e) & 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001977 }
1978
1979 write_mchbar32(0x24, 0x10000 + info->memory_reserved_for_heci_mb);
1980
1981 send_heci_uma_message(info);
1982
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001983 pci_write_config32(HECIDEV, 0x10, 0x0);
1984 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001985
1986}
1987
1988static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1989{
1990 int ranks_in_channel;
1991 ranks_in_channel = info->populated_ranks[channel][0][0]
1992 + info->populated_ranks[channel][0][1]
1993 + info->populated_ranks[channel][1][0]
1994 + info->populated_ranks[channel][1][1];
1995
1996 /* empty channel */
1997 if (ranks_in_channel == 0)
1998 return 1;
1999
2000 if (ranks_in_channel != ranks)
2001 return 0;
2002 /* single slot */
2003 if (info->populated_ranks[channel][0][0] !=
2004 info->populated_ranks[channel][1][0])
2005 return 1;
2006 if (info->populated_ranks[channel][0][1] !=
2007 info->populated_ranks[channel][1][1])
2008 return 1;
2009 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
2010 return 0;
2011 if (info->density[channel][0] != info->density[channel][1])
2012 return 0;
2013 return 1;
2014}
2015
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002016static void read_4090(struct raminfo *info)
2017{
2018 int i, channel, slot, rank, lane;
2019 for (i = 0; i < 2; i++)
2020 for (slot = 0; slot < NUM_SLOTS; slot++)
2021 for (rank = 0; rank < NUM_RANKS; rank++)
2022 for (lane = 0; lane < 9; lane++)
2023 info->training.
2024 lane_timings[0][i][slot][rank][lane]
2025 = 32;
2026
2027 for (i = 1; i < 4; i++)
2028 for (channel = 0; channel < NUM_CHANNELS; channel++)
2029 for (slot = 0; slot < NUM_SLOTS; slot++)
2030 for (rank = 0; rank < NUM_RANKS; rank++)
2031 for (lane = 0; lane < 9; lane++) {
2032 info->training.
2033 lane_timings[i][channel]
2034 [slot][rank][lane] =
2035 read_500(info, channel,
2036 get_timing_register_addr
2037 (lane, i, slot,
2038 rank), 9)
2039 + (i == 1) * 11; // !!!!
2040 }
2041
2042}
2043
2044static u32 get_etalon2(int flip, u32 addr)
2045{
2046 const u16 invmask[] = {
2047 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
2048 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
2049 };
2050 u32 ret;
2051 u32 comp4 = addr / 480;
2052 addr %= 480;
2053 u32 comp1 = addr & 0xf;
2054 u32 comp2 = (addr >> 4) & 1;
2055 u32 comp3 = addr >> 5;
2056
2057 if (comp4)
2058 ret = 0x1010101 << (comp4 - 1);
2059 else
2060 ret = 0;
2061 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
2062 ret = ~ret;
2063
2064 return ret;
2065}
2066
2067static void disable_cache(void)
2068{
2069 msr_t msr = {.lo = 0, .hi = 0 };
2070
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07002071 wrmsr(MTRR_PHYS_BASE(3), msr);
2072 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002073}
2074
2075static void enable_cache(unsigned int base, unsigned int size)
2076{
2077 msr_t msr;
2078 msr.lo = base | MTRR_TYPE_WRPROT;
2079 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07002080 wrmsr(MTRR_PHYS_BASE(3), msr);
2081 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002082 & 0xffffffff);
2083 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07002084 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002085}
2086
2087static void flush_cache(u32 start, u32 size)
2088{
2089 u32 end;
2090 u32 addr;
2091
2092 end = start + (ALIGN_DOWN(size + 4096, 4096));
2093 for (addr = start; addr < end; addr += 64)
2094 clflush(addr);
2095}
2096
2097static void clear_errors(void)
2098{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002099 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002100}
2101
2102static void write_testing(struct raminfo *info, int totalrank, int flip)
2103{
2104 int nwrites = 0;
2105 /* in 8-byte units. */
2106 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002107 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002108
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002109 base = (u8 *)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002110 for (offset = 0; offset < 9 * 480; offset += 2) {
2111 write32(base + offset * 8, get_etalon2(flip, offset));
2112 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
2113 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
2114 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
2115 nwrites += 4;
2116 if (nwrites >= 320) {
2117 clear_errors();
2118 nwrites = 0;
2119 }
2120 }
2121}
2122
2123static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
2124{
2125 u8 failmask = 0;
2126 int i;
2127 int comp1, comp2, comp3;
2128 u32 failxor[2] = { 0, 0 };
2129
2130 enable_cache((total_rank << 28), 1728 * 5 * 4);
2131
2132 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
2133 for (comp1 = 0; comp1 < 4; comp1++)
2134 for (comp2 = 0; comp2 < 60; comp2++) {
2135 u32 re[4];
2136 u32 curroffset =
2137 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
2138 read128((total_rank << 28) | (curroffset << 3),
2139 (u64 *) re);
2140 failxor[0] |=
2141 get_etalon2(flip, curroffset) ^ re[0];
2142 failxor[1] |=
2143 get_etalon2(flip, curroffset) ^ re[1];
2144 failxor[0] |=
2145 get_etalon2(flip, curroffset | 1) ^ re[2];
2146 failxor[1] |=
2147 get_etalon2(flip, curroffset | 1) ^ re[3];
2148 }
2149 for (i = 0; i < 8; i++)
2150 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2151 failmask |= 1 << i;
2152 }
2153 disable_cache();
2154 flush_cache((total_rank << 28), 1728 * 5 * 4);
2155 return failmask;
2156}
2157
2158const u32 seed1[0x18] = {
2159 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2160 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2161 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2162 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2163 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2164 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2165};
2166
2167static u32 get_seed2(int a, int b)
2168{
2169 const u32 seed2[5] = {
2170 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2171 0x5b6db6db,
2172 };
2173 u32 r;
2174 r = seed2[(a + (a >= 10)) / 5];
2175 return b ? ~r : r;
2176}
2177
2178static int make_shift(int comp2, int comp5, int x)
2179{
2180 const u8 seed3[32] = {
2181 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2182 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2183 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2184 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2185 };
2186
2187 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2188}
2189
2190static u32 get_etalon(int flip, u32 addr)
2191{
2192 u32 mask_byte = 0;
2193 int comp1 = (addr >> 1) & 1;
2194 int comp2 = (addr >> 3) & 0x1f;
2195 int comp3 = (addr >> 8) & 0xf;
2196 int comp4 = (addr >> 12) & 0xf;
2197 int comp5 = (addr >> 16) & 0x1f;
2198 u32 mask_bit = ~(0x10001 << comp3);
2199 u32 part1;
2200 u32 part2;
2201 int byte;
2202
2203 part2 =
2204 ((seed1[comp5] >>
2205 make_shift(comp2, comp5,
2206 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2207 part1 =
2208 ((seed1[comp5] >>
2209 make_shift(comp2, comp5,
2210 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2211
2212 for (byte = 0; byte < 4; byte++)
2213 if ((get_seed2(comp5, comp4) >>
2214 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2215 mask_byte |= 0xff << (8 * byte);
2216
2217 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2218 (comp3 + 16));
2219}
2220
2221static void
2222write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2223 char flip)
2224{
2225 int i;
2226 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002227 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2228 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002229}
2230
2231static u8
2232check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2233 char flip)
2234{
2235 u8 failmask = 0;
2236 u32 failxor[2];
2237 int i;
2238 int comp1, comp2, comp3;
2239
2240 failxor[0] = 0;
2241 failxor[1] = 0;
2242
2243 enable_cache(totalrank << 28, 134217728);
2244 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2245 for (comp1 = 0; comp1 < 16; comp1++)
2246 for (comp2 = 0; comp2 < 64; comp2++) {
2247 u32 addr =
2248 (totalrank << 28) | (region << 25) | (block
2249 << 16)
2250 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2251 2);
2252 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002253 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002254 }
2255 for (i = 0; i < 8; i++)
2256 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2257 failmask |= 1 << i;
2258 }
2259 disable_cache();
2260 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2261 return failmask;
2262}
2263
2264static int check_bounded(unsigned short *vals, u16 bound)
2265{
2266 int i;
2267
2268 for (i = 0; i < 8; i++)
2269 if (vals[i] < bound)
2270 return 0;
2271 return 1;
2272}
2273
2274enum state {
2275 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2276};
2277
2278static int validate_state(enum state *in)
2279{
2280 int i;
2281 for (i = 0; i < 8; i++)
2282 if (in[i] != COMPLETE)
2283 return 0;
2284 return 1;
2285}
2286
2287static void
2288do_fsm(enum state *state, u16 * counter,
2289 u8 fail_mask, int margin, int uplimit,
2290 u8 * res_low, u8 * res_high, u8 val)
2291{
2292 int lane;
2293
2294 for (lane = 0; lane < 8; lane++) {
2295 int is_fail = (fail_mask >> lane) & 1;
2296 switch (state[lane]) {
2297 case BEFORE_USABLE:
2298 if (!is_fail) {
2299 counter[lane] = 1;
2300 state[lane] = AT_USABLE;
2301 break;
2302 }
2303 counter[lane] = 0;
2304 state[lane] = BEFORE_USABLE;
2305 break;
2306 case AT_USABLE:
2307 if (!is_fail) {
2308 ++counter[lane];
2309 if (counter[lane] >= margin) {
2310 state[lane] = AT_MARGIN;
2311 res_low[lane] = val - margin + 1;
2312 break;
2313 }
2314 state[lane] = 1;
2315 break;
2316 }
2317 counter[lane] = 0;
2318 state[lane] = BEFORE_USABLE;
2319 break;
2320 case AT_MARGIN:
2321 if (is_fail) {
2322 state[lane] = COMPLETE;
2323 res_high[lane] = val - 1;
2324 } else {
2325 counter[lane]++;
2326 state[lane] = AT_MARGIN;
2327 if (val == uplimit) {
2328 state[lane] = COMPLETE;
2329 res_high[lane] = uplimit;
2330 }
2331 }
2332 break;
2333 case COMPLETE:
2334 break;
2335 }
2336 }
2337}
2338
2339static void
2340train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2341 u8 total_rank, u8 reg_178, int first_run, int niter,
2342 timing_bounds_t * timings)
2343{
2344 int lane;
2345 enum state state[8];
2346 u16 count[8];
2347 u8 lower_usable[8];
2348 u8 upper_usable[8];
2349 unsigned short num_sucessfully_checked[8];
2350 u8 secondary_total_rank;
2351 u8 reg1b3;
2352
2353 if (info->populated_ranks_mask[1]) {
2354 if (channel == 1)
2355 secondary_total_rank =
2356 info->populated_ranks[1][0][0] +
2357 info->populated_ranks[1][0][1]
2358 + info->populated_ranks[1][1][0] +
2359 info->populated_ranks[1][1][1];
2360 else
2361 secondary_total_rank = 0;
2362 } else
2363 secondary_total_rank = total_rank;
2364
2365 {
2366 int i;
2367 for (i = 0; i < 8; i++)
2368 state[i] = BEFORE_USABLE;
2369 }
2370
2371 if (!first_run) {
2372 int is_all_ok = 1;
2373 for (lane = 0; lane < 8; lane++)
2374 if (timings[reg_178][channel][slot][rank][lane].
2375 smallest ==
2376 timings[reg_178][channel][slot][rank][lane].
2377 largest) {
2378 timings[reg_178][channel][slot][rank][lane].
2379 smallest = 0;
2380 timings[reg_178][channel][slot][rank][lane].
2381 largest = 0;
2382 is_all_ok = 0;
2383 }
2384 if (is_all_ok) {
2385 int i;
2386 for (i = 0; i < 8; i++)
2387 state[i] = COMPLETE;
2388 }
2389 }
2390
2391 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2392 u8 failmask = 0;
2393 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2394 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2395 failmask = check_testing(info, total_rank, 0);
2396 write_mchbar32(0xfb0, read_mchbar32(0xfb0) | 0x00030000);
2397 do_fsm(state, count, failmask, 5, 47, lower_usable,
2398 upper_usable, reg1b3);
2399 }
2400
2401 if (reg1b3) {
2402 write_1d0(0, 0x1b3, 6, 1);
2403 write_1d0(0, 0x1a3, 6, 1);
2404 for (lane = 0; lane < 8; lane++) {
2405 if (state[lane] == COMPLETE) {
2406 timings[reg_178][channel][slot][rank][lane].
2407 smallest =
2408 lower_usable[lane] +
2409 (info->training.
2410 lane_timings[0][channel][slot][rank][lane]
2411 & 0x3F) - 32;
2412 timings[reg_178][channel][slot][rank][lane].
2413 largest =
2414 upper_usable[lane] +
2415 (info->training.
2416 lane_timings[0][channel][slot][rank][lane]
2417 & 0x3F) - 32;
2418 }
2419 }
2420 }
2421
2422 if (!first_run) {
2423 for (lane = 0; lane < 8; lane++)
2424 if (state[lane] == COMPLETE) {
2425 write_500(info, channel,
2426 timings[reg_178][channel][slot][rank]
2427 [lane].smallest,
2428 get_timing_register_addr(lane, 0,
2429 slot, rank),
2430 9, 1);
2431 write_500(info, channel,
2432 timings[reg_178][channel][slot][rank]
2433 [lane].smallest +
2434 info->training.
2435 lane_timings[1][channel][slot][rank]
2436 [lane]
2437 -
2438 info->training.
2439 lane_timings[0][channel][slot][rank]
2440 [lane], get_timing_register_addr(lane,
2441 1,
2442 slot,
2443 rank),
2444 9, 1);
2445 num_sucessfully_checked[lane] = 0;
2446 } else
2447 num_sucessfully_checked[lane] = -1;
2448
2449 do {
2450 u8 failmask = 0;
2451 int i;
2452 for (i = 0; i < niter; i++) {
2453 if (failmask == 0xFF)
2454 break;
2455 failmask |=
2456 check_testing_type2(info, total_rank, 2, i,
2457 0);
2458 failmask |=
2459 check_testing_type2(info, total_rank, 3, i,
2460 1);
2461 }
2462 write_mchbar32(0xfb0,
2463 read_mchbar32(0xfb0) | 0x00030000);
2464 for (lane = 0; lane < 8; lane++)
2465 if (num_sucessfully_checked[lane] != 0xffff) {
2466 if ((1 << lane) & failmask) {
2467 if (timings[reg_178][channel]
2468 [slot][rank][lane].
2469 largest <=
2470 timings[reg_178][channel]
2471 [slot][rank][lane].smallest)
2472 num_sucessfully_checked
2473 [lane] = -1;
2474 else {
2475 num_sucessfully_checked
2476 [lane] = 0;
2477 timings[reg_178]
2478 [channel][slot]
2479 [rank][lane].
2480 smallest++;
2481 write_500(info, channel,
2482 timings
2483 [reg_178]
2484 [channel]
2485 [slot][rank]
2486 [lane].
2487 smallest,
2488 get_timing_register_addr
2489 (lane, 0,
2490 slot, rank),
2491 9, 1);
2492 write_500(info, channel,
2493 timings
2494 [reg_178]
2495 [channel]
2496 [slot][rank]
2497 [lane].
2498 smallest +
2499 info->
2500 training.
2501 lane_timings
2502 [1][channel]
2503 [slot][rank]
2504 [lane]
2505 -
2506 info->
2507 training.
2508 lane_timings
2509 [0][channel]
2510 [slot][rank]
2511 [lane],
2512 get_timing_register_addr
2513 (lane, 1,
2514 slot, rank),
2515 9, 1);
2516 }
2517 } else
2518 num_sucessfully_checked[lane]++;
2519 }
2520 }
2521 while (!check_bounded(num_sucessfully_checked, 2));
2522
2523 for (lane = 0; lane < 8; lane++)
2524 if (state[lane] == COMPLETE) {
2525 write_500(info, channel,
2526 timings[reg_178][channel][slot][rank]
2527 [lane].largest,
2528 get_timing_register_addr(lane, 0,
2529 slot, rank),
2530 9, 1);
2531 write_500(info, channel,
2532 timings[reg_178][channel][slot][rank]
2533 [lane].largest +
2534 info->training.
2535 lane_timings[1][channel][slot][rank]
2536 [lane]
2537 -
2538 info->training.
2539 lane_timings[0][channel][slot][rank]
2540 [lane], get_timing_register_addr(lane,
2541 1,
2542 slot,
2543 rank),
2544 9, 1);
2545 num_sucessfully_checked[lane] = 0;
2546 } else
2547 num_sucessfully_checked[lane] = -1;
2548
2549 do {
2550 int failmask = 0;
2551 int i;
2552 for (i = 0; i < niter; i++) {
2553 if (failmask == 0xFF)
2554 break;
2555 failmask |=
2556 check_testing_type2(info, total_rank, 2, i,
2557 0);
2558 failmask |=
2559 check_testing_type2(info, total_rank, 3, i,
2560 1);
2561 }
2562
2563 write_mchbar32(0xfb0,
2564 read_mchbar32(0xfb0) | 0x00030000);
2565 for (lane = 0; lane < 8; lane++) {
2566 if (num_sucessfully_checked[lane] != 0xffff) {
2567 if ((1 << lane) & failmask) {
2568 if (timings[reg_178][channel]
2569 [slot][rank][lane].
2570 largest <=
2571 timings[reg_178][channel]
2572 [slot][rank][lane].
2573 smallest) {
2574 num_sucessfully_checked
2575 [lane] = -1;
2576 } else {
2577 num_sucessfully_checked
2578 [lane] = 0;
2579 timings[reg_178]
2580 [channel][slot]
2581 [rank][lane].
2582 largest--;
2583 write_500(info, channel,
2584 timings
2585 [reg_178]
2586 [channel]
2587 [slot][rank]
2588 [lane].
2589 largest,
2590 get_timing_register_addr
2591 (lane, 0,
2592 slot, rank),
2593 9, 1);
2594 write_500(info, channel,
2595 timings
2596 [reg_178]
2597 [channel]
2598 [slot][rank]
2599 [lane].
2600 largest +
2601 info->
2602 training.
2603 lane_timings
2604 [1][channel]
2605 [slot][rank]
2606 [lane]
2607 -
2608 info->
2609 training.
2610 lane_timings
2611 [0][channel]
2612 [slot][rank]
2613 [lane],
2614 get_timing_register_addr
2615 (lane, 1,
2616 slot, rank),
2617 9, 1);
2618 }
2619 } else
2620 num_sucessfully_checked[lane]++;
2621 }
2622 }
2623 }
2624 while (!check_bounded(num_sucessfully_checked, 3));
2625
2626 for (lane = 0; lane < 8; lane++) {
2627 write_500(info, channel,
2628 info->training.
2629 lane_timings[0][channel][slot][rank][lane],
2630 get_timing_register_addr(lane, 0, slot, rank),
2631 9, 1);
2632 write_500(info, channel,
2633 info->training.
2634 lane_timings[1][channel][slot][rank][lane],
2635 get_timing_register_addr(lane, 1, slot, rank),
2636 9, 1);
2637 if (timings[reg_178][channel][slot][rank][lane].
2638 largest <=
2639 timings[reg_178][channel][slot][rank][lane].
2640 smallest) {
2641 timings[reg_178][channel][slot][rank][lane].
2642 largest = 0;
2643 timings[reg_178][channel][slot][rank][lane].
2644 smallest = 0;
2645 }
2646 }
2647 }
2648}
2649
2650static void set_10b(struct raminfo *info, u8 val)
2651{
2652 int channel;
2653 int slot, rank;
2654 int lane;
2655
2656 if (read_1d0(0x10b, 6) == val)
2657 return;
2658
2659 write_1d0(val, 0x10b, 6, 1);
2660
2661 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2662 u16 reg_500;
2663 reg_500 = read_500(info, channel,
2664 get_timing_register_addr(lane, 0, slot,
2665 rank), 9);
2666 if (val == 1) {
2667 if (lut16[info->clock_speed_index] <= reg_500)
2668 reg_500 -= lut16[info->clock_speed_index];
2669 else
2670 reg_500 = 0;
2671 } else {
2672 reg_500 += lut16[info->clock_speed_index];
2673 }
2674 write_500(info, channel, reg_500,
2675 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2676 }
2677}
2678
2679static void set_ecc(int onoff)
2680{
2681 int channel;
2682 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2683 u8 t;
2684 t = read_mchbar8((channel << 10) + 0x5f8);
2685 if (onoff)
2686 t |= 1;
2687 else
2688 t &= ~1;
2689 write_mchbar8((channel << 10) + 0x5f8, t);
2690 }
2691}
2692
2693static void set_178(u8 val)
2694{
2695 if (val >= 31)
2696 val = val - 31;
2697 else
2698 val = 63 - val;
2699
2700 write_1d0(2 * val, 0x178, 7, 1);
2701}
2702
2703static void
2704write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2705 int type)
2706{
2707 int lane;
2708
2709 for (lane = 0; lane < 8; lane++)
2710 write_500(info, channel,
2711 info->training.
2712 lane_timings[type][channel][slot][rank][lane],
2713 get_timing_register_addr(lane, type, slot, rank), 9,
2714 0);
2715}
2716
2717static void
2718try_timing_offsets(struct raminfo *info, int channel,
2719 int slot, int rank, int totalrank)
2720{
2721 u16 count[8];
2722 enum state state[8];
2723 u8 lower_usable[8], upper_usable[8];
2724 int lane;
2725 int i;
2726 int flip = 1;
2727 int timing_offset;
2728
2729 for (i = 0; i < 8; i++)
2730 state[i] = BEFORE_USABLE;
2731
2732 memset(count, 0, sizeof(count));
2733
2734 for (lane = 0; lane < 8; lane++)
2735 write_500(info, channel,
2736 info->training.
2737 lane_timings[2][channel][slot][rank][lane] + 32,
2738 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2739
2740 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2741 timing_offset++) {
2742 u8 failmask;
2743 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2744 failmask = 0;
2745 for (i = 0; i < 2 && failmask != 0xff; i++) {
2746 flip = !flip;
2747 write_testing(info, totalrank, flip);
2748 failmask |= check_testing(info, totalrank, flip);
2749 }
2750 do_fsm(state, count, failmask, 10, 63, lower_usable,
2751 upper_usable, timing_offset);
2752 }
2753 write_1d0(0, 0x1bb, 6, 1);
2754 dump_timings(info);
2755 if (!validate_state(state))
2756 die("Couldn't discover DRAM timings (1)\n");
2757
2758 for (lane = 0; lane < 8; lane++) {
2759 u8 bias = 0;
2760
2761 if (info->silicon_revision) {
2762 int usable_length;
2763
2764 usable_length = upper_usable[lane] - lower_usable[lane];
2765 if (usable_length >= 20) {
2766 bias = usable_length / 2 - 10;
2767 if (bias >= 2)
2768 bias = 2;
2769 }
2770 }
2771 write_500(info, channel,
2772 info->training.
2773 lane_timings[2][channel][slot][rank][lane] +
2774 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2775 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2776 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2777 info->training.lane_timings[2][channel][slot][rank][lane] +
2778 lower_usable[lane];
2779 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2780 info->training.lane_timings[2][channel][slot][rank][lane] +
2781 upper_usable[lane];
2782 info->training.timing2_offset[channel][slot][rank][lane] =
2783 info->training.lane_timings[2][channel][slot][rank][lane];
2784 }
2785}
2786
2787static u8
2788choose_training(struct raminfo *info, int channel, int slot, int rank,
2789 int lane, timing_bounds_t * timings, u8 center_178)
2790{
2791 u16 central_weight;
2792 u16 side_weight;
2793 unsigned int sum = 0, count = 0;
2794 u8 span;
2795 u8 lower_margin, upper_margin;
2796 u8 reg_178;
2797 u8 result;
2798
2799 span = 12;
2800 central_weight = 20;
2801 side_weight = 20;
2802 if (info->silicon_revision == 1 && channel == 1) {
2803 central_weight = 5;
2804 side_weight = 20;
2805 if ((info->
2806 populated_ranks_mask[1] ^ (info->
2807 populated_ranks_mask[1] >> 2)) &
2808 1)
2809 span = 18;
2810 }
2811 if ((info->populated_ranks_mask[0] & 5) == 5) {
2812 central_weight = 20;
2813 side_weight = 20;
2814 }
2815 if (info->clock_speed_index >= 2
2816 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2817 if (info->silicon_revision == 1) {
2818 switch (channel) {
2819 case 0:
2820 if (lane == 1) {
2821 central_weight = 10;
2822 side_weight = 20;
2823 }
2824 break;
2825 case 1:
2826 if (lane == 6) {
2827 side_weight = 5;
2828 central_weight = 20;
2829 }
2830 break;
2831 }
2832 }
2833 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2834 side_weight = 5;
2835 central_weight = 20;
2836 }
2837 }
2838 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2839 reg_178 += span) {
2840 u8 smallest;
2841 u8 largest;
2842 largest = timings[reg_178][channel][slot][rank][lane].largest;
2843 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2844 if (largest - smallest + 1 >= 5) {
2845 unsigned int weight;
2846 if (reg_178 == center_178)
2847 weight = central_weight;
2848 else
2849 weight = side_weight;
2850 sum += weight * (largest + smallest);
2851 count += weight;
2852 }
2853 }
2854 dump_timings(info);
2855 if (count == 0)
2856 die("Couldn't discover DRAM timings (2)\n");
2857 result = sum / (2 * count);
2858 lower_margin =
2859 result - timings[center_178][channel][slot][rank][lane].smallest;
2860 upper_margin =
2861 timings[center_178][channel][slot][rank][lane].largest - result;
2862 if (upper_margin < 10 && lower_margin > 10)
2863 result -= min(lower_margin - 10, 10 - upper_margin);
2864 if (upper_margin > 10 && lower_margin < 10)
2865 result += min(upper_margin - 10, 10 - lower_margin);
2866 return result;
2867}
2868
2869#define STANDARD_MIN_MARGIN 5
2870
2871static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2872{
2873 u16 margin[64];
2874 int lane, rank, slot, channel;
2875 u8 reg178;
2876 int count = 0, sum = 0;
2877
2878 for (reg178 = reg178_min[info->clock_speed_index];
2879 reg178 < reg178_max[info->clock_speed_index];
2880 reg178 += reg178_step[info->clock_speed_index]) {
2881 margin[reg178] = -1;
2882 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2883 int curmargin =
2884 timings[reg178][channel][slot][rank][lane].largest -
2885 timings[reg178][channel][slot][rank][lane].
2886 smallest + 1;
2887 if (curmargin < margin[reg178])
2888 margin[reg178] = curmargin;
2889 }
2890 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2891 u16 weight;
2892 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2893 sum += weight * reg178;
2894 count += weight;
2895 }
2896 }
2897 dump_timings(info);
2898 if (count == 0)
2899 die("Couldn't discover DRAM timings (3)\n");
2900
2901 u8 threshold;
2902
2903 for (threshold = 30; threshold >= 5; threshold--) {
2904 int usable_length = 0;
2905 int smallest_fount = 0;
2906 for (reg178 = reg178_min[info->clock_speed_index];
2907 reg178 < reg178_max[info->clock_speed_index];
2908 reg178 += reg178_step[info->clock_speed_index])
2909 if (margin[reg178] >= threshold) {
2910 usable_length +=
2911 reg178_step[info->clock_speed_index];
2912 info->training.reg178_largest =
2913 reg178 -
2914 2 * reg178_step[info->clock_speed_index];
2915
2916 if (!smallest_fount) {
2917 smallest_fount = 1;
2918 info->training.reg178_smallest =
2919 reg178 +
2920 reg178_step[info->
2921 clock_speed_index];
2922 }
2923 }
2924 if (usable_length >= 0x21)
2925 break;
2926 }
2927
2928 return sum / count;
2929}
2930
2931static int check_cached_sanity(struct raminfo *info)
2932{
2933 int lane;
2934 int slot, rank;
2935 int channel;
2936
2937 if (!info->cached_training)
2938 return 0;
2939
2940 for (channel = 0; channel < NUM_CHANNELS; channel++)
2941 for (slot = 0; slot < NUM_SLOTS; slot++)
2942 for (rank = 0; rank < NUM_RANKS; rank++)
2943 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2944 u16 cached_value, estimation_value;
2945 cached_value =
2946 info->cached_training->
2947 lane_timings[1][channel][slot][rank]
2948 [lane];
2949 if (cached_value >= 0x18
2950 && cached_value <= 0x1E7) {
2951 estimation_value =
2952 info->training.
2953 lane_timings[1][channel]
2954 [slot][rank][lane];
2955 if (estimation_value <
2956 cached_value - 24)
2957 return 0;
2958 if (estimation_value >
2959 cached_value + 24)
2960 return 0;
2961 }
2962 }
2963 return 1;
2964}
2965
2966static int try_cached_training(struct raminfo *info)
2967{
2968 u8 saved_243[2];
2969 u8 tm;
2970
2971 int channel, slot, rank, lane;
2972 int flip = 1;
2973 int i, j;
2974
2975 if (!check_cached_sanity(info))
2976 return 0;
2977
2978 info->training.reg178_center = info->cached_training->reg178_center;
2979 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2980 info->training.reg178_largest = info->cached_training->reg178_largest;
2981 memcpy(&info->training.timing_bounds,
2982 &info->cached_training->timing_bounds,
2983 sizeof(info->training.timing_bounds));
2984 memcpy(&info->training.timing_offset,
2985 &info->cached_training->timing_offset,
2986 sizeof(info->training.timing_offset));
2987
2988 write_1d0(2, 0x142, 3, 1);
2989 saved_243[0] = read_mchbar8(0x243);
2990 saved_243[1] = read_mchbar8(0x643);
2991 write_mchbar8(0x243, saved_243[0] | 2);
2992 write_mchbar8(0x643, saved_243[1] | 2);
2993 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002994 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002995 if (read_1d0(0x10b, 6) & 1)
2996 set_10b(info, 0);
2997 for (tm = 0; tm < 2; tm++) {
2998 int totalrank;
2999
3000 set_178(tm ? info->cached_training->reg178_largest : info->
3001 cached_training->reg178_smallest);
3002
3003 totalrank = 0;
3004 /* Check timing ranges. With i == 0 we check smallest one and with
3005 i == 1 the largest bound. With j == 0 we check that on the bound
3006 it still works whereas with j == 1 we check that just outside of
3007 bound we fail.
3008 */
3009 FOR_POPULATED_RANKS_BACKWARDS {
3010 for (i = 0; i < 2; i++) {
3011 for (lane = 0; lane < 8; lane++) {
3012 write_500(info, channel,
3013 info->cached_training->
3014 timing2_bounds[channel][slot]
3015 [rank][lane][i],
3016 get_timing_register_addr(lane,
3017 3,
3018 slot,
3019 rank),
3020 9, 1);
3021
3022 if (!i)
3023 write_500(info, channel,
3024 info->
3025 cached_training->
3026 timing2_offset
3027 [channel][slot][rank]
3028 [lane],
3029 get_timing_register_addr
3030 (lane, 2, slot, rank),
3031 9, 1);
3032 write_500(info, channel,
3033 i ? info->cached_training->
3034 timing_bounds[tm][channel]
3035 [slot][rank][lane].
3036 largest : info->
3037 cached_training->
3038 timing_bounds[tm][channel]
3039 [slot][rank][lane].smallest,
3040 get_timing_register_addr(lane,
3041 0,
3042 slot,
3043 rank),
3044 9, 1);
3045 write_500(info, channel,
3046 info->cached_training->
3047 timing_offset[channel][slot]
3048 [rank][lane] +
3049 (i ? info->cached_training->
3050 timing_bounds[tm][channel]
3051 [slot][rank][lane].
3052 largest : info->
3053 cached_training->
3054 timing_bounds[tm][channel]
3055 [slot][rank][lane].
3056 smallest) - 64,
3057 get_timing_register_addr(lane,
3058 1,
3059 slot,
3060 rank),
3061 9, 1);
3062 }
3063 for (j = 0; j < 2; j++) {
3064 u8 failmask;
3065 u8 expected_failmask;
3066 char reg1b3;
3067
3068 reg1b3 = (j == 1) + 4;
3069 reg1b3 =
3070 j == i ? reg1b3 : (-reg1b3) & 0x3f;
3071 write_1d0(reg1b3, 0x1bb, 6, 1);
3072 write_1d0(reg1b3, 0x1b3, 6, 1);
3073 write_1d0(reg1b3, 0x1a3, 6, 1);
3074
3075 flip = !flip;
3076 write_testing(info, totalrank, flip);
3077 failmask =
3078 check_testing(info, totalrank,
3079 flip);
3080 expected_failmask =
3081 j == 0 ? 0x00 : 0xff;
3082 if (failmask != expected_failmask)
3083 goto fail;
3084 }
3085 }
3086 totalrank++;
3087 }
3088 }
3089
3090 set_178(info->cached_training->reg178_center);
3091 if (info->use_ecc)
3092 set_ecc(1);
3093 write_training_data(info);
3094 write_1d0(0, 322, 3, 1);
3095 info->training = *info->cached_training;
3096
3097 write_1d0(0, 0x1bb, 6, 1);
3098 write_1d0(0, 0x1b3, 6, 1);
3099 write_1d0(0, 0x1a3, 6, 1);
3100 write_mchbar8(0x243, saved_243[0]);
3101 write_mchbar8(0x643, saved_243[1]);
3102
3103 return 1;
3104
3105fail:
3106 FOR_POPULATED_RANKS {
3107 write_500_timings_type(info, channel, slot, rank, 1);
3108 write_500_timings_type(info, channel, slot, rank, 2);
3109 write_500_timings_type(info, channel, slot, rank, 3);
3110 }
3111
3112 write_1d0(0, 0x1bb, 6, 1);
3113 write_1d0(0, 0x1b3, 6, 1);
3114 write_1d0(0, 0x1a3, 6, 1);
3115 write_mchbar8(0x243, saved_243[0]);
3116 write_mchbar8(0x643, saved_243[1]);
3117
3118 return 0;
3119}
3120
3121static void do_ram_training(struct raminfo *info)
3122{
3123 u8 saved_243[2];
3124 int totalrank = 0;
3125 u8 reg_178;
3126 int niter;
3127
3128 timing_bounds_t timings[64];
3129 int lane, rank, slot, channel;
3130 u8 reg178_center;
3131
3132 write_1d0(2, 0x142, 3, 1);
3133 saved_243[0] = read_mchbar8(0x243);
3134 saved_243[1] = read_mchbar8(0x643);
3135 write_mchbar8(0x243, saved_243[0] | 2);
3136 write_mchbar8(0x643, saved_243[1] | 2);
3137 switch (info->clock_speed_index) {
3138 case 0:
3139 niter = 5;
3140 break;
3141 case 1:
3142 niter = 10;
3143 break;
3144 default:
3145 niter = 19;
3146 break;
3147 }
3148 set_ecc(0);
3149
3150 FOR_POPULATED_RANKS_BACKWARDS {
3151 int i;
3152
3153 write_500_timings_type(info, channel, slot, rank, 0);
3154
3155 write_testing(info, totalrank, 0);
3156 for (i = 0; i < niter; i++) {
3157 write_testing_type2(info, totalrank, 2, i, 0);
3158 write_testing_type2(info, totalrank, 3, i, 1);
3159 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003160 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003161 totalrank++;
3162 }
3163
3164 if (reg178_min[info->clock_speed_index] <
3165 reg178_max[info->clock_speed_index])
3166 memset(timings[reg178_min[info->clock_speed_index]], 0,
3167 sizeof(timings[0]) *
3168 (reg178_max[info->clock_speed_index] -
3169 reg178_min[info->clock_speed_index]));
3170 for (reg_178 = reg178_min[info->clock_speed_index];
3171 reg_178 < reg178_max[info->clock_speed_index];
3172 reg_178 += reg178_step[info->clock_speed_index]) {
3173 totalrank = 0;
3174 set_178(reg_178);
3175 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3176 for (slot = 0; slot < NUM_SLOTS; slot++)
3177 for (rank = 0; rank < NUM_RANKS; rank++) {
3178 memset(&timings[reg_178][channel][slot]
3179 [rank][0].smallest, 0, 16);
3180 if (info->
3181 populated_ranks[channel][slot]
3182 [rank]) {
3183 train_ram_at_178(info, channel,
3184 slot, rank,
3185 totalrank,
3186 reg_178, 1,
3187 niter,
3188 timings);
3189 totalrank++;
3190 }
3191 }
3192 }
3193
3194 reg178_center = choose_reg178(info, timings);
3195
3196 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3197 info->training.timing_bounds[0][channel][slot][rank][lane].
3198 smallest =
3199 timings[info->training.
3200 reg178_smallest][channel][slot][rank][lane].
3201 smallest;
3202 info->training.timing_bounds[0][channel][slot][rank][lane].
3203 largest =
3204 timings[info->training.
3205 reg178_smallest][channel][slot][rank][lane].largest;
3206 info->training.timing_bounds[1][channel][slot][rank][lane].
3207 smallest =
3208 timings[info->training.
3209 reg178_largest][channel][slot][rank][lane].smallest;
3210 info->training.timing_bounds[1][channel][slot][rank][lane].
3211 largest =
3212 timings[info->training.
3213 reg178_largest][channel][slot][rank][lane].largest;
3214 info->training.timing_offset[channel][slot][rank][lane] =
3215 info->training.lane_timings[1][channel][slot][rank][lane]
3216 -
3217 info->training.lane_timings[0][channel][slot][rank][lane] +
3218 64;
3219 }
3220
3221 if (info->silicon_revision == 1
3222 && (info->
3223 populated_ranks_mask[1] ^ (info->
3224 populated_ranks_mask[1] >> 2)) & 1) {
3225 int ranks_after_channel1;
3226
3227 totalrank = 0;
3228 for (reg_178 = reg178_center - 18;
3229 reg_178 <= reg178_center + 18; reg_178 += 18) {
3230 totalrank = 0;
3231 set_178(reg_178);
3232 for (slot = 0; slot < NUM_SLOTS; slot++)
3233 for (rank = 0; rank < NUM_RANKS; rank++) {
3234 if (info->
3235 populated_ranks[1][slot][rank]) {
3236 train_ram_at_178(info, 1, slot,
3237 rank,
3238 totalrank,
3239 reg_178, 0,
3240 niter,
3241 timings);
3242 totalrank++;
3243 }
3244 }
3245 }
3246 ranks_after_channel1 = totalrank;
3247
3248 for (reg_178 = reg178_center - 12;
3249 reg_178 <= reg178_center + 12; reg_178 += 12) {
3250 totalrank = ranks_after_channel1;
3251 set_178(reg_178);
3252 for (slot = 0; slot < NUM_SLOTS; slot++)
3253 for (rank = 0; rank < NUM_RANKS; rank++)
3254 if (info->
3255 populated_ranks[0][slot][rank]) {
3256 train_ram_at_178(info, 0, slot,
3257 rank,
3258 totalrank,
3259 reg_178, 0,
3260 niter,
3261 timings);
3262 totalrank++;
3263 }
3264
3265 }
3266 } else {
3267 for (reg_178 = reg178_center - 12;
3268 reg_178 <= reg178_center + 12; reg_178 += 12) {
3269 totalrank = 0;
3270 set_178(reg_178);
3271 FOR_POPULATED_RANKS_BACKWARDS {
3272 train_ram_at_178(info, channel, slot, rank,
3273 totalrank, reg_178, 0, niter,
3274 timings);
3275 totalrank++;
3276 }
3277 }
3278 }
3279
3280 set_178(reg178_center);
3281 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3282 u16 tm0;
3283
3284 tm0 =
3285 choose_training(info, channel, slot, rank, lane, timings,
3286 reg178_center);
3287 write_500(info, channel, tm0,
3288 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3289 write_500(info, channel,
3290 tm0 +
3291 info->training.
3292 lane_timings[1][channel][slot][rank][lane] -
3293 info->training.
3294 lane_timings[0][channel][slot][rank][lane],
3295 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3296 }
3297
3298 totalrank = 0;
3299 FOR_POPULATED_RANKS_BACKWARDS {
3300 try_timing_offsets(info, channel, slot, rank, totalrank);
3301 totalrank++;
3302 }
3303 write_mchbar8(0x243, saved_243[0]);
3304 write_mchbar8(0x643, saved_243[1]);
3305 write_1d0(0, 0x142, 3, 1);
3306 info->training.reg178_center = reg178_center;
3307}
3308
3309static void ram_training(struct raminfo *info)
3310{
3311 u16 saved_fc4;
3312
3313 saved_fc4 = read_mchbar16(0xfc4);
3314 write_mchbar16(0xfc4, 0xffff);
3315
3316 if (info->revision >= 8)
3317 read_4090(info);
3318
3319 if (!try_cached_training(info))
3320 do_ram_training(info);
3321 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3322 && info->clock_speed_index < 2)
3323 set_10b(info, 1);
3324 write_mchbar16(0xfc4, saved_fc4);
3325}
3326
3327static unsigned gcd(unsigned a, unsigned b)
3328{
3329 unsigned t;
3330 if (a > b) {
3331 t = a;
3332 a = b;
3333 b = t;
3334 }
3335 /* invariant a < b. */
3336 while (a) {
3337 t = b % a;
3338 b = a;
3339 a = t;
3340 }
3341 return b;
3342}
3343
3344static inline int div_roundup(int a, int b)
3345{
Edward O'Callaghan7116ac82014-07-08 01:53:24 +10003346 return CEIL_DIV(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003347}
3348
3349static unsigned lcm(unsigned a, unsigned b)
3350{
3351 return (a * b) / gcd(a, b);
3352}
3353
3354struct stru1 {
3355 u8 freqs_reversed;
3356 u8 freq_diff_reduced;
3357 u8 freq_min_reduced;
3358 u8 divisor_f4_to_fmax;
3359 u8 divisor_f3_to_fmax;
3360 u8 freq4_to_max_remainder;
3361 u8 freq3_to_2_remainder;
3362 u8 freq3_to_2_remaindera;
3363 u8 freq4_to_2_remainder;
3364 int divisor_f3_to_f1, divisor_f4_to_f2;
3365 int common_time_unit_ps;
3366 int freq_max_reduced;
3367};
3368
3369static void
3370compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3371 int num_cycles_2, int num_cycles_1, int round_it,
3372 int add_freqs, struct stru1 *result)
3373{
3374 int g;
3375 int common_time_unit_ps;
3376 int freq1_reduced, freq2_reduced;
3377 int freq_min_reduced;
3378 int freq_max_reduced;
3379 int freq3, freq4;
3380
3381 g = gcd(freq1, freq2);
3382 freq1_reduced = freq1 / g;
3383 freq2_reduced = freq2 / g;
3384 freq_min_reduced = min(freq1_reduced, freq2_reduced);
3385 freq_max_reduced = max(freq1_reduced, freq2_reduced);
3386
3387 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3388 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3389 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3390 if (add_freqs) {
3391 freq3 += freq2_reduced;
3392 freq4 += freq1_reduced;
3393 }
3394
3395 if (round_it) {
3396 result->freq3_to_2_remainder = 0;
3397 result->freq3_to_2_remaindera = 0;
3398 result->freq4_to_max_remainder = 0;
3399 result->divisor_f4_to_f2 = 0;
3400 result->divisor_f3_to_f1 = 0;
3401 } else {
3402 if (freq2_reduced < freq1_reduced) {
3403 result->freq3_to_2_remainder =
3404 result->freq3_to_2_remaindera =
3405 freq3 % freq1_reduced - freq1_reduced + 1;
3406 result->freq4_to_max_remainder =
3407 -(freq4 % freq1_reduced);
3408 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3409 result->divisor_f4_to_f2 =
3410 (freq4 -
3411 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3412 result->freq4_to_2_remainder =
3413 -(char)((freq1_reduced - freq2_reduced) +
3414 ((u8) freq4 -
3415 (freq1_reduced -
3416 freq2_reduced)) % (u8) freq2_reduced);
3417 } else {
3418 if (freq2_reduced > freq1_reduced) {
3419 result->freq4_to_max_remainder =
3420 (freq4 % freq2_reduced) - freq2_reduced + 1;
3421 result->freq4_to_2_remainder =
3422 freq4 % freq_max_reduced -
3423 freq_max_reduced + 1;
3424 } else {
3425 result->freq4_to_max_remainder =
3426 -(freq4 % freq2_reduced);
3427 result->freq4_to_2_remainder =
3428 -(char)(freq4 % freq_max_reduced);
3429 }
3430 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3431 result->divisor_f3_to_f1 =
3432 (freq3 -
3433 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3434 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3435 result->freq3_to_2_remaindera =
3436 -(char)((freq_max_reduced - freq_min_reduced) +
3437 (freq3 -
3438 (freq_max_reduced -
3439 freq_min_reduced)) % freq1_reduced);
3440 }
3441 }
3442 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3443 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3444 if (round_it) {
3445 if (freq2_reduced > freq1_reduced) {
3446 if (freq3 % freq_max_reduced)
3447 result->divisor_f3_to_fmax++;
3448 }
3449 if (freq2_reduced < freq1_reduced) {
3450 if (freq4 % freq_max_reduced)
3451 result->divisor_f4_to_fmax++;
3452 }
3453 }
3454 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3455 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3456 result->freq_min_reduced = freq_min_reduced;
3457 result->common_time_unit_ps = common_time_unit_ps;
3458 result->freq_max_reduced = freq_max_reduced;
3459}
3460
3461static void
3462set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3463 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3464 int num_cycles_4, int reverse)
3465{
3466 struct stru1 vv;
3467 char multiplier;
3468
3469 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3470 0, 1, &vv);
3471
3472 multiplier =
3473 div_roundup(max
3474 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3475 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3476 div_roundup(num_cycles_1,
3477 vv.common_time_unit_ps) +
3478 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3479 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3480
3481 u32 y =
3482 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3483 vv.freq_max_reduced * multiplier)
3484 | (vv.
3485 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3486 multiplier) << 16) | ((u8) (vv.
3487 freq_min_reduced
3488 *
3489 multiplier)
3490 << 24);
3491 u32 x =
3492 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3493 divisor_f3_to_f1
3494 << 16)
3495 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3496 if (reverse) {
3497 write_mchbar32(reg, y);
3498 write_mchbar32(reg + 4, x);
3499 } else {
3500 write_mchbar32(reg + 4, y);
3501 write_mchbar32(reg, x);
3502 }
3503}
3504
3505static void
3506set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3507 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3508 int num_cycles_4)
3509{
3510 struct stru1 ratios1;
3511 struct stru1 ratios2;
3512
3513 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3514 0, 1, &ratios2);
3515 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3516 0, 1, &ratios1);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003517 printk (BIOS_SPEW, "[%x] <= %x\n", reg,
3518 ratios1.freq4_to_max_remainder | (ratios2.
3519 freq4_to_max_remainder
3520 << 8)
3521 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3522 divisor_f4_to_fmax
3523 << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003524 write_mchbar32(reg,
3525 ratios1.freq4_to_max_remainder | (ratios2.
3526 freq4_to_max_remainder
3527 << 8)
3528 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3529 divisor_f4_to_fmax
3530 << 20));
3531}
3532
3533static void
3534set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3535 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3536{
3537 struct stru1 ratios;
3538
3539 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3540 round_it, add_freqs, &ratios);
3541 switch (mode) {
3542 case 0:
3543 write_mchbar32(reg + 4,
3544 ratios.freq_diff_reduced | (ratios.
3545 freqs_reversed <<
3546 8));
3547 write_mchbar32(reg,
3548 ratios.freq3_to_2_remainder | (ratios.
3549 freq4_to_max_remainder
3550 << 8)
3551 | (ratios.divisor_f3_to_fmax << 16) | (ratios.
3552 divisor_f4_to_fmax
3553 << 20) |
3554 (ratios.freq_min_reduced << 24));
3555 break;
3556
3557 case 1:
3558 write_mchbar32(reg,
3559 ratios.freq3_to_2_remainder | (ratios.
3560 divisor_f3_to_fmax
3561 << 16));
3562 break;
3563
3564 case 2:
3565 write_mchbar32(reg,
3566 ratios.freq3_to_2_remainder | (ratios.
3567 freq4_to_max_remainder
3568 << 8) | (ratios.
3569 divisor_f3_to_fmax
3570 << 16) |
3571 (ratios.divisor_f4_to_fmax << 20));
3572 break;
3573
3574 case 4:
3575 write_mchbar32(reg, (ratios.divisor_f3_to_fmax << 4)
3576 | (ratios.divisor_f4_to_fmax << 8) | (ratios.
3577 freqs_reversed
3578 << 12) |
3579 (ratios.freq_min_reduced << 16) | (ratios.
3580 freq_diff_reduced
3581 << 24));
3582 break;
3583 }
3584}
3585
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003586static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003587{
3588 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3589 0, 1);
3590 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3591 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3592 1);
3593 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3594 frequency_11(info), 1231, 1524, 0, 1);
3595 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3596 frequency_11(info) / 2, 1278, 2008, 0, 1);
3597 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3598 1167, 1539, 0, 1);
3599 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3600 frequency_11(info) / 2, 1403, 1318, 0, 1);
3601 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3602 1);
3603 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3604 1);
3605 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3606 1, 1);
3607 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3608 1);
3609 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3610 frequency_11(info) / 2, 4000, 0, 0, 0);
3611 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3612 frequency_11(info) / 2, 4000, 4000, 0, 0);
3613
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003614 if (s3resume) {
3615 printk (BIOS_SPEW, "[6dc] <= %x\n", info->cached_training->reg_6dc);
3616 write_mchbar32(0x6dc, info->cached_training->reg_6dc);
3617 } else
3618 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3619 info->delay46_ps[0], 0,
3620 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003621 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3622 frequency_11(info), 2500, 0, 0, 0);
3623 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3624 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003625 if (s3resume) {
3626 printk (BIOS_SPEW, "[6e8] <= %x\n", info->cached_training->reg_6e8);
3627 write_mchbar32(0x6e8, info->cached_training->reg_6e8);
3628 } else
3629 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3630 info->delay46_ps[1], 0,
3631 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003632 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3633 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3634 470, 0);
3635 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3636 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3637 454, 459, 0);
3638 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3639 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3640 2588, 0);
3641 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3642 2405, 0);
3643 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3644 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3645 480, 0);
3646 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
3647 write_mchbar32(0x2dbc, ((frequency_11(info) / 2) - 1) | 0xe00000);
3648 write_mchbar32(0x2db8, ((info->fsb_frequency - 1) << 16) | 0x77);
3649}
3650
3651static u16 get_max_timing(struct raminfo *info, int channel)
3652{
3653 int slot, rank, lane;
3654 u16 ret = 0;
3655
3656 if ((read_mchbar8(0x2ca8) >> 2) < 1)
3657 return 384;
3658
3659 if (info->revision < 8)
3660 return 256;
3661
3662 for (slot = 0; slot < NUM_SLOTS; slot++)
3663 for (rank = 0; rank < NUM_RANKS; rank++)
3664 if (info->populated_ranks[channel][slot][rank])
3665 for (lane = 0; lane < 8 + info->use_ecc; lane++)
3666 ret = max(ret, read_500(info, channel,
3667 get_timing_register_addr
3668 (lane, 0, slot,
3669 rank), 9));
3670 return ret;
3671}
3672
3673static void set_274265(struct raminfo *info)
3674{
3675 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3676 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3677 int delay_e_over_cycle_ps;
3678 int cycletime_ps;
3679 int channel;
3680
3681 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003682 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003683 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3684 cycletime_ps =
3685 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3686 delay_d_ps =
3687 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3688 - info->some_delay_3_ps_rounded + 200;
3689 if (!
3690 ((info->silicon_revision == 0
3691 || info->silicon_revision == 1)
3692 && (info->revision >= 8)))
3693 delay_d_ps += halfcycle_ps(info) * 2;
3694 delay_d_ps +=
3695 halfcycle_ps(info) * (!info->revision_flag_1 +
3696 info->some_delay_2_halfcycles_ceil +
3697 2 * info->some_delay_1_cycle_floor +
3698 info->clock_speed_index +
3699 2 * info->cas_latency - 7 + 11);
3700 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3701
3702 write_mchbar32(0x140,
3703 (read_mchbar32(0x140) & 0xfaffffff) | 0x2000000);
3704 write_mchbar32(0x138,
3705 (read_mchbar32(0x138) & 0xfaffffff) | 0x2000000);
3706 if ((read_mchbar8(0x144) & 0x1f) > 0x13)
3707 delay_d_ps += 650;
3708 delay_c_ps = delay_d_ps + 1800;
3709 if (delay_c_ps <= delay_a_ps)
3710 delay_e_ps = 0;
3711 else
3712 delay_e_ps =
3713 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3714 cycletime_ps);
3715
3716 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3717 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3718 delay_f_cycles =
3719 div_roundup(2500 - delay_e_over_cycle_ps,
3720 2 * halfcycle_ps(info));
3721 if (delay_f_cycles > delay_e_cycles) {
3722 info->delay46_ps[channel] = delay_e_ps;
3723 delay_e_cycles = 0;
3724 } else {
3725 info->delay46_ps[channel] =
3726 delay_e_over_cycle_ps +
3727 2 * halfcycle_ps(info) * delay_f_cycles;
3728 delay_e_cycles -= delay_f_cycles;
3729 }
3730
3731 if (info->delay46_ps[channel] < 2500) {
3732 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003733 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003734 }
3735 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3736 if (delay_b_ps <= delay_a_ps)
3737 delay_b_ps = 0;
3738 else
3739 delay_b_ps -= delay_a_ps;
3740 info->delay54_ps[channel] =
3741 cycletime_ps * div_roundup(delay_b_ps,
3742 cycletime_ps) -
3743 2 * halfcycle_ps(info) * delay_e_cycles;
3744 if (info->delay54_ps[channel] < 2500)
3745 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003746 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003747 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3748 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003749 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003750 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003751 info->training.reg274265[channel][1] =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003752 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3753 4 * halfcycle_ps(info)) - 6;
3754 write_mchbar32((channel << 10) + 0x274,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003755 info->training.reg274265[channel][1]
3756 | (info->training.reg274265[channel][0] << 16));
3757 info->training.reg274265[channel][2] =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003758 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3759 4 * halfcycle_ps(info)) + 1;
3760 write_mchbar16((channel << 10) + 0x265,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003761 info->training.reg274265[channel][2] << 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003762 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003763 if (info->training.reg2ca9_bit0)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003764 write_mchbar8(0x2ca9, read_mchbar8(0x2ca9) | 1);
3765 else
3766 write_mchbar8(0x2ca9, read_mchbar8(0x2ca9) & ~1);
3767}
3768
3769static void restore_274265(struct raminfo *info)
3770{
3771 int channel;
3772
3773 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3774 write_mchbar32((channel << 10) + 0x274,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003775 (info->cached_training->reg274265[channel][0] << 16)
3776 | info->cached_training->reg274265[channel][1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003777 write_mchbar16((channel << 10) + 0x265,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003778 info->cached_training->reg274265[channel][2] << 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003779 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003780 if (info->cached_training->reg2ca9_bit0)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003781 write_mchbar8(0x2ca9, read_mchbar8(0x2ca9) | 1);
3782 else
3783 write_mchbar8(0x2ca9, read_mchbar8(0x2ca9) & ~1);
3784}
3785
3786#if REAL
3787static void dmi_setup(void)
3788{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003789 gav(read8(DEFAULT_DMIBAR + 0x254));
3790 write8(DEFAULT_DMIBAR + 0x254, 0x1);
3791 write16(DEFAULT_DMIBAR + 0x1b8, 0x18f2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003792 read_mchbar16(0x48);
3793 write_mchbar16(0x48, 0x2);
3794
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003795 write32(DEFAULT_DMIBAR + 0xd68, read32(DEFAULT_DMIBAR + 0xd68) | 0x08000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003796
3797 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3798 DEFAULT_GPIOBASE | 0x38);
3799 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3800}
3801#endif
3802
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003803void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003804{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003805 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003806 u16 ggc;
3807 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003808
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003809 x2ca8 = read_mchbar8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003810 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3811 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
3812 write_mchbar8(0x2ca8, 0);
Vladimir Serbinenkoe1eef692014-02-19 22:08:51 +01003813 outb(0x6, 0xcf9);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003814#if REAL
Patrick Georgi546953c2014-11-29 10:38:17 +01003815 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003816#else
3817 printf("CP5\n");
3818 exit(0);
3819#endif
3820 }
3821#if !REAL
3822 if (!s3resume) {
3823 pre_raminit_3(x2ca8);
3824 }
Vladimir Serbinenkof62669c2014-01-09 10:59:38 +01003825 pre_raminit_4a(x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003826#endif
3827
3828 dmi_setup();
3829
3830 write_mchbar16(0x1170, 0xa880);
3831 write_mchbar8(0x11c1, 0x1);
3832 write_mchbar16(0x1170, 0xb880);
3833 read_mchbar8(0x1210);
3834 write_mchbar8(0x1210, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003835
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003836 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3837 /* 0 for 32MB */
3838 gfxsize = 0;
3839 }
3840
3841 ggc = 0xb00 | ((gfxsize + 5) << 4);
3842
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003843 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003844
3845 u16 deven;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003846 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003847
3848 if (deven & 8) {
3849 write_mchbar8(0x2c30, 0x20);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003850 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003851 write_mchbar16(0x2c30, read_mchbar16(0x2c30) | 0x200);
3852 write_mchbar16(0x2c32, 0x434);
3853 read_mchbar32(0x2c44);
3854 write_mchbar32(0x2c44, 0x1053687);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003855 pci_read_config8(GMA, 0x62); // = 0x2
3856 pci_write_config8(GMA, 0x62, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003857 read8(DEFAULT_RCBA + 0x2318);
3858 write8(DEFAULT_RCBA + 0x2318, 0x47);
3859 read8(DEFAULT_RCBA + 0x2320);
3860 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003861 }
3862
3863 read_mchbar32(0x30);
3864 write_mchbar32(0x30, 0x40);
3865
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003866 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003867 gav(read32(DEFAULT_RCBA + 0x3428));
3868 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003869}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003870
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003871void raminit(const int s3resume, const u8 *spd_addrmap)
3872{
3873 unsigned channel, slot, lane, rank;
3874 int i;
3875 struct raminfo info;
3876 u8 x2ca8;
3877 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003878 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003879
3880 x2ca8 = read_mchbar8(0x2ca8);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003881 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003882
3883 memset(&info, 0x5a, sizeof(info));
3884
3885 info.last_500_command[0] = 0;
3886 info.last_500_command[1] = 0;
3887
3888 info.fsb_frequency = 135 * 2;
3889 info.board_lane_delay[0] = 0x14;
3890 info.board_lane_delay[1] = 0x07;
3891 info.board_lane_delay[2] = 0x07;
3892 info.board_lane_delay[3] = 0x08;
3893 info.board_lane_delay[4] = 0x56;
3894 info.board_lane_delay[5] = 0x04;
3895 info.board_lane_delay[6] = 0x04;
3896 info.board_lane_delay[7] = 0x05;
3897 info.board_lane_delay[8] = 0x10;
3898
3899 info.training.reg_178 = 0;
3900 info.training.reg_10b = 0;
3901
3902 info.heci_bar = 0;
3903 info.memory_reserved_for_heci_mb = 0;
3904
3905 /* before SPD */
3906 timestamp_add_now(101);
3907
3908 if (!s3resume || REAL) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003909 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003910
3911 collect_system_info(&info);
3912
3913#if REAL
3914 /* Enable SMBUS. */
3915 enable_smbus();
3916#endif
3917
3918 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3919
3920 info.use_ecc = 1;
3921 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003922 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003923 int v;
3924 int try;
3925 int addr;
3926 const u8 useful_addresses[] = {
3927 DEVICE_TYPE,
3928 MODULE_TYPE,
3929 DENSITY,
3930 RANKS_AND_DQ,
3931 MEMORY_BUS_WIDTH,
3932 TIMEBASE_DIVIDEND,
3933 TIMEBASE_DIVISOR,
3934 CYCLETIME,
3935 CAS_LATENCIES_LSB,
3936 CAS_LATENCIES_MSB,
3937 CAS_LATENCY_TIME,
3938 0x11, 0x12, 0x13, 0x14, 0x15,
3939 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3940 0x1c, 0x1d,
3941 THERMAL_AND_REFRESH,
3942 0x20,
3943 REFERENCE_RAW_CARD_USED,
3944 RANK1_ADDRESS_MAPPING,
3945 0x75, 0x76, 0x77, 0x78,
3946 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3947 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3948 0x85, 0x86, 0x87, 0x88,
3949 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3950 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3951 0x95
3952 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003953 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003954 continue;
3955 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003956 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003957 DEVICE_TYPE);
3958 if (v >= 0)
3959 break;
3960 }
3961 if (v < 0)
3962 continue;
3963 for (addr = 0;
3964 addr <
3965 sizeof(useful_addresses) /
3966 sizeof(useful_addresses[0]); addr++)
3967 gav(info.
3968 spd[channel][0][useful_addresses
3969 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003970 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003971 useful_addresses
3972 [addr]));
3973 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3974 die("Only DDR3 is supported");
3975
3976 v = info.spd[channel][0][RANKS_AND_DQ];
3977 info.populated_ranks[channel][0][0] = 1;
3978 info.populated_ranks[channel][0][1] =
3979 ((v >> 3) & 7);
3980 if (((v >> 3) & 7) > 1)
3981 die("At most 2 ranks are supported");
3982 if ((v & 7) == 0 || (v & 7) > 2)
3983 die("Only x8 and x16 modules are supported");
3984 if ((info.
3985 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3986 && (info.
3987 spd[channel][slot][MODULE_TYPE] & 0xF)
3988 != 3)
3989 die("Registered memory is not supported");
3990 info.is_x16_module[channel][0] = (v & 7) - 1;
3991 info.density[channel][slot] =
3992 info.spd[channel][slot][DENSITY] & 0xF;
3993 if (!
3994 (info.
3995 spd[channel][slot][MEMORY_BUS_WIDTH] &
3996 0x18))
3997 info.use_ecc = 0;
3998 }
3999
4000 gav(0x55);
4001
4002 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4003 int v = 0;
4004 for (slot = 0; slot < NUM_SLOTS; slot++)
4005 for (rank = 0; rank < NUM_RANKS; rank++)
4006 v |= info.
4007 populated_ranks[channel][slot][rank]
4008 << (2 * slot + rank);
4009 info.populated_ranks_mask[channel] = v;
4010 }
4011
4012 gav(0x55);
4013
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004014 gav(pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004015 }
4016
4017 /* after SPD */
4018 timestamp_add_now(102);
4019
4020 write_mchbar8(0x2ca8, read_mchbar8(0x2ca8) & 0xfc);
4021#if !REAL
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07004022 rdmsr (MTRR_PHYS_MASK (3));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004023#endif
4024
4025 collect_system_info(&info);
4026 calculate_timings(&info);
4027
4028#if !REAL
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004029 pci_write_config8(NORTHBRIDGE, 0xdf, 0x82);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004030#endif
4031
4032 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004033 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004034 if (x2ca8 == 0 && (reg8 & 0x80)) {
4035 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
4036 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
4037 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
4038 */
4039
4040 /* Clear bit7. */
4041
4042 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4043 (reg8 & ~(1 << 7)));
4044
4045 printk(BIOS_INFO,
4046 "Interrupted RAM init, reset required.\n");
4047 outb(0x6, 0xcf9);
4048#if REAL
Patrick Georgi546953c2014-11-29 10:38:17 +01004049 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004050#endif
4051 }
4052 }
4053#if !REAL
4054 gav(read_mchbar8(0x2ca8)); ///!!!!
4055#endif
4056
4057 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004058 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4059 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004060
4061 compute_derived_timings(&info);
4062
4063 if (x2ca8 == 0) {
4064 gav(read_mchbar8(0x164));
4065 write_mchbar8(0x164, 0x26);
4066 write_mchbar16(0x2c20, 0x10);
4067 }
4068
4069 write_mchbar32(0x18b4, read_mchbar32(0x18b4) | 0x210000); /* OK */
4070 write_mchbar32(0x1890, read_mchbar32(0x1890) | 0x2000000); /* OK */
4071 write_mchbar32(0x18b4, read_mchbar32(0x18b4) | 0x8000);
4072
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004073 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x50)); // !!!!
4074 pci_write_config8(PCI_DEV(0xff, 2, 1), 0x54, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004075
4076 gav(read_mchbar16(0x2c10)); // !!!!
4077 write_mchbar16(0x2c10, 0x412);
4078 gav(read_mchbar16(0x2c10)); // !!!!
4079 write_mchbar16(0x2c12, read_mchbar16(0x2c12) | 0x100); /* OK */
4080
4081 gav(read_mchbar8(0x2ca8)); // !!!!
4082 write_mchbar32(0x1804,
4083 (read_mchbar32(0x1804) & 0xfffffffc) | 0x8400080);
4084
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004085 pci_read_config32(PCI_DEV(0xff, 2, 1), 0x6c); // !!!!
4086 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x6c, 0x40a0a0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004087 gav(read_mchbar32(0x1c04)); // !!!!
4088 gav(read_mchbar32(0x1804)); // !!!!
4089
4090 if (x2ca8 == 0) {
4091 write_mchbar8(0x2ca8, read_mchbar8(0x2ca8) | 1);
4092 }
4093
4094 write_mchbar32(0x18d8, 0x120000);
4095 write_mchbar32(0x18dc, 0x30a484a);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004096 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x0);
4097 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x9444a);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004098 write_mchbar32(0x18d8, 0x40000);
4099 write_mchbar32(0x18dc, 0xb000000);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004100 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x60000);
4101 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004102 write_mchbar32(0x18d8, 0x180000);
4103 write_mchbar32(0x18dc, 0xc0000142);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004104 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x20000);
4105 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x142);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004106 write_mchbar32(0x18d8, 0x1e0000);
4107
4108 gav(read_mchbar32(0x18dc)); // !!!!
4109 write_mchbar32(0x18dc, 0x3);
4110 gav(read_mchbar32(0x18dc)); // !!!!
4111
4112 if (x2ca8 == 0) {
4113 write_mchbar8(0x2ca8, read_mchbar8(0x2ca8) | 1); // guess
4114 }
4115
4116 write_mchbar32(0x188c, 0x20bc09);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004117 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xd0, 0x40b0c09);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004118 write_mchbar32(0x1a10, 0x4200010e);
4119 write_mchbar32(0x18b8, read_mchbar32(0x18b8) | 0x200);
4120 gav(read_mchbar32(0x1918)); // !!!!
4121 write_mchbar32(0x1918, 0x332);
4122
4123 gav(read_mchbar32(0x18b8)); // !!!!
4124 write_mchbar32(0x18b8, 0xe00);
4125 gav(read_mchbar32(0x182c)); // !!!!
4126 write_mchbar32(0x182c, 0x10202);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004127 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x94)); // !!!!
4128 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x94, 0x10202);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004129 write_mchbar32(0x1a1c, read_mchbar32(0x1a1c) & 0x8fffffff);
4130 write_mchbar32(0x1a70, read_mchbar32(0x1a70) | 0x100000);
4131
4132 write_mchbar32(0x18b4, read_mchbar32(0x18b4) & 0xffff7fff);
4133 gav(read_mchbar32(0x1a68)); // !!!!
4134 write_mchbar32(0x1a68, 0x343800);
4135 gav(read_mchbar32(0x1e68)); // !!!!
4136 gav(read_mchbar32(0x1a68)); // !!!!
4137
4138 if (x2ca8 == 0) {
4139 write_mchbar8(0x2ca8, read_mchbar8(0x2ca8) | 1); // guess
4140 }
4141
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004142 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x048); // !!!!
4143 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x048, 0x140000);
4144 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
4145 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x058, 0x64555);
4146 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
4147 pci_read_config32(PCI_DEV (0xff, 0, 0), 0xd0); // !!!!
4148 pci_write_config32(PCI_DEV (0xff, 0, 0), 0xd0, 0x180);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004149 gav(read_mchbar32(0x1af0)); // !!!!
4150 gav(read_mchbar32(0x1af0)); // !!!!
4151 write_mchbar32(0x1af0, 0x1f020003);
4152 gav(read_mchbar32(0x1af0)); // !!!!
4153
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10004154 if (x2ca8 == 0) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004155 write_mchbar8(0x2ca8, read_mchbar8(0x2ca8) | 1); // guess
4156 }
4157
4158 gav(read_mchbar32(0x1890)); // !!!!
4159 write_mchbar32(0x1890, 0x80102);
4160 gav(read_mchbar32(0x18b4)); // !!!!
4161 write_mchbar32(0x18b4, 0x216000);
4162 write_mchbar32(0x18a4, 0x22222222);
4163 write_mchbar32(0x18a8, 0x22222222);
4164 write_mchbar32(0x18ac, 0x22222);
4165
4166 udelay(1000);
4167
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004168 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004169
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004170 if (x2ca8 == 0) {
4171 int j;
4172 if (s3resume && info.cached_training) {
4173 restore_274265(&info);
4174 printk(BIOS_DEBUG, "reg2ca9_bit0 = %x\n",
4175 info.cached_training->reg2ca9_bit0);
4176 for (i = 0; i < 2; i++)
4177 for (j = 0; j < 3; j++)
4178 printk(BIOS_DEBUG, "reg274265[%d][%d] = %x\n",
4179 i, j, info.cached_training->reg274265[i][j]);
4180 } else {
4181 set_274265(&info);
4182 printk(BIOS_DEBUG, "reg2ca9_bit0 = %x\n",
4183 info.training.reg2ca9_bit0);
4184 for (i = 0; i < 2; i++)
4185 for (j = 0; j < 3; j++)
4186 printk(BIOS_DEBUG, "reg274265[%d][%d] = %x\n",
4187 i, j, info.training.reg274265[i][j]);
4188 }
4189
4190 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004191
4192 if (!(deven & 8)) {
4193 read_mchbar32(0x2cb0);
4194 write_mchbar32(0x2cb0, 0x40);
4195 }
4196
4197 udelay(1000);
4198
4199 if (deven & 8) {
4200 write_mchbar32(0xff8, 0x1800 | read_mchbar32(0xff8));
4201 read_mchbar32(0x2cb0);
4202 write_mchbar32(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004203 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4204 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4205 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004206
4207 read_mchbar8(0x1150);
4208 read_mchbar8(0x1151);
4209 read_mchbar8(0x1022);
4210 read_mchbar8(0x16d0);
4211 write_mchbar32(0x1300, 0x60606060);
4212 write_mchbar32(0x1304, 0x60606060);
4213 write_mchbar32(0x1308, 0x78797a7b);
4214 write_mchbar32(0x130c, 0x7c7d7e7f);
4215 write_mchbar32(0x1310, 0x60606060);
4216 write_mchbar32(0x1314, 0x60606060);
4217 write_mchbar32(0x1318, 0x60606060);
4218 write_mchbar32(0x131c, 0x60606060);
4219 write_mchbar32(0x1320, 0x50515253);
4220 write_mchbar32(0x1324, 0x54555657);
4221 write_mchbar32(0x1328, 0x58595a5b);
4222 write_mchbar32(0x132c, 0x5c5d5e5f);
4223 write_mchbar32(0x1330, 0x40414243);
4224 write_mchbar32(0x1334, 0x44454647);
4225 write_mchbar32(0x1338, 0x48494a4b);
4226 write_mchbar32(0x133c, 0x4c4d4e4f);
4227 write_mchbar32(0x1340, 0x30313233);
4228 write_mchbar32(0x1344, 0x34353637);
4229 write_mchbar32(0x1348, 0x38393a3b);
4230 write_mchbar32(0x134c, 0x3c3d3e3f);
4231 write_mchbar32(0x1350, 0x20212223);
4232 write_mchbar32(0x1354, 0x24252627);
4233 write_mchbar32(0x1358, 0x28292a2b);
4234 write_mchbar32(0x135c, 0x2c2d2e2f);
4235 write_mchbar32(0x1360, 0x10111213);
4236 write_mchbar32(0x1364, 0x14151617);
4237 write_mchbar32(0x1368, 0x18191a1b);
4238 write_mchbar32(0x136c, 0x1c1d1e1f);
4239 write_mchbar32(0x1370, 0x10203);
4240 write_mchbar32(0x1374, 0x4050607);
4241 write_mchbar32(0x1378, 0x8090a0b);
4242 write_mchbar32(0x137c, 0xc0d0e0f);
4243 write_mchbar8(0x11cc, 0x4e);
4244 write_mchbar32(0x1110, 0x73970404);
4245 write_mchbar32(0x1114, 0x72960404);
4246 write_mchbar32(0x1118, 0x6f950404);
4247 write_mchbar32(0x111c, 0x6d940404);
4248 write_mchbar32(0x1120, 0x6a930404);
4249 write_mchbar32(0x1124, 0x68a41404);
4250 write_mchbar32(0x1128, 0x66a21404);
4251 write_mchbar32(0x112c, 0x63a01404);
4252 write_mchbar32(0x1130, 0x609e1404);
4253 write_mchbar32(0x1134, 0x5f9c1404);
4254 write_mchbar32(0x1138, 0x5c961404);
4255 write_mchbar32(0x113c, 0x58a02404);
4256 write_mchbar32(0x1140, 0x54942404);
4257 write_mchbar32(0x1190, 0x900080a);
4258 write_mchbar16(0x11c0, 0xc40b);
4259 write_mchbar16(0x11c2, 0x303);
4260 write_mchbar16(0x11c4, 0x301);
4261 read_mchbar32(0x1190);
4262 write_mchbar32(0x1190, 0x8900080a);
4263 write_mchbar32(0x11b8, 0x70c3000);
4264 write_mchbar8(0x11ec, 0xa);
4265 write_mchbar16(0x1100, 0x800);
4266 read_mchbar32(0x11bc);
4267 write_mchbar32(0x11bc, 0x1e84800);
4268 write_mchbar16(0x11ca, 0xfa);
4269 write_mchbar32(0x11e4, 0x4e20);
4270 write_mchbar8(0x11bc, 0xf);
4271 write_mchbar16(0x11da, 0x19);
4272 write_mchbar16(0x11ba, 0x470c);
4273 write_mchbar32(0x1680, 0xe6ffe4ff);
4274 write_mchbar32(0x1684, 0xdeffdaff);
4275 write_mchbar32(0x1688, 0xd4ffd0ff);
4276 write_mchbar32(0x168c, 0xccffc6ff);
4277 write_mchbar32(0x1690, 0xc0ffbeff);
4278 write_mchbar32(0x1694, 0xb8ffb0ff);
4279 write_mchbar32(0x1698, 0xa8ff0000);
4280 write_mchbar32(0x169c, 0xc00);
4281 write_mchbar32(0x1290, 0x5000000);
4282 }
4283
4284 write_mchbar32(0x124c, 0x15040d00);
4285 write_mchbar32(0x1250, 0x7f0000);
4286 write_mchbar32(0x1254, 0x1e220004);
4287 write_mchbar32(0x1258, 0x4000004);
4288 write_mchbar32(0x1278, 0x0);
4289 write_mchbar32(0x125c, 0x0);
4290 write_mchbar32(0x1260, 0x0);
4291 write_mchbar32(0x1264, 0x0);
4292 write_mchbar32(0x1268, 0x0);
4293 write_mchbar32(0x126c, 0x0);
4294 write_mchbar32(0x1270, 0x0);
4295 write_mchbar32(0x1274, 0x0);
4296 }
4297
4298 if ((deven & 8) && x2ca8 == 0) {
4299 write_mchbar16(0x1214, 0x320);
4300 write_mchbar32(0x1600, 0x40000000);
4301 read_mchbar32(0x11f4);
4302 write_mchbar32(0x11f4, 0x10000000);
4303 read_mchbar16(0x1230);
4304 write_mchbar16(0x1230, 0x8000);
4305 write_mchbar32(0x1400, 0x13040020);
4306 write_mchbar32(0x1404, 0xe090120);
4307 write_mchbar32(0x1408, 0x5120220);
4308 write_mchbar32(0x140c, 0x5120330);
4309 write_mchbar32(0x1410, 0xe090220);
4310 write_mchbar32(0x1414, 0x1010001);
4311 write_mchbar32(0x1418, 0x1110000);
4312 write_mchbar32(0x141c, 0x9020020);
4313 write_mchbar32(0x1420, 0xd090220);
4314 write_mchbar32(0x1424, 0x2090220);
4315 write_mchbar32(0x1428, 0x2090330);
4316 write_mchbar32(0x142c, 0xd090220);
4317 write_mchbar32(0x1430, 0x1010001);
4318 write_mchbar32(0x1434, 0x1110000);
4319 write_mchbar32(0x1438, 0x11040020);
4320 write_mchbar32(0x143c, 0x4030220);
4321 write_mchbar32(0x1440, 0x1060220);
4322 write_mchbar32(0x1444, 0x1060330);
4323 write_mchbar32(0x1448, 0x4030220);
4324 write_mchbar32(0x144c, 0x1010001);
4325 write_mchbar32(0x1450, 0x1110000);
4326 write_mchbar32(0x1454, 0x4010020);
4327 write_mchbar32(0x1458, 0xb090220);
4328 write_mchbar32(0x145c, 0x1090220);
4329 write_mchbar32(0x1460, 0x1090330);
4330 write_mchbar32(0x1464, 0xb090220);
4331 write_mchbar32(0x1468, 0x1010001);
4332 write_mchbar32(0x146c, 0x1110000);
4333 write_mchbar32(0x1470, 0xf040020);
4334 write_mchbar32(0x1474, 0xa090220);
4335 write_mchbar32(0x1478, 0x1120220);
4336 write_mchbar32(0x147c, 0x1120330);
4337 write_mchbar32(0x1480, 0xa090220);
4338 write_mchbar32(0x1484, 0x1010001);
4339 write_mchbar32(0x1488, 0x1110000);
4340 write_mchbar32(0x148c, 0x7020020);
4341 write_mchbar32(0x1490, 0x1010220);
4342 write_mchbar32(0x1494, 0x10210);
4343 write_mchbar32(0x1498, 0x10320);
4344 write_mchbar32(0x149c, 0x1010220);
4345 write_mchbar32(0x14a0, 0x1010001);
4346 write_mchbar32(0x14a4, 0x1110000);
4347 write_mchbar32(0x14a8, 0xd040020);
4348 write_mchbar32(0x14ac, 0x8090220);
4349 write_mchbar32(0x14b0, 0x1111310);
4350 write_mchbar32(0x14b4, 0x1111420);
4351 write_mchbar32(0x14b8, 0x8090220);
4352 write_mchbar32(0x14bc, 0x1010001);
4353 write_mchbar32(0x14c0, 0x1110000);
4354 write_mchbar32(0x14c4, 0x3010020);
4355 write_mchbar32(0x14c8, 0x7090220);
4356 write_mchbar32(0x14cc, 0x1081310);
4357 write_mchbar32(0x14d0, 0x1081420);
4358 write_mchbar32(0x14d4, 0x7090220);
4359 write_mchbar32(0x14d8, 0x1010001);
4360 write_mchbar32(0x14dc, 0x1110000);
4361 write_mchbar32(0x14e0, 0xb040020);
4362 write_mchbar32(0x14e4, 0x2030220);
4363 write_mchbar32(0x14e8, 0x1051310);
4364 write_mchbar32(0x14ec, 0x1051420);
4365 write_mchbar32(0x14f0, 0x2030220);
4366 write_mchbar32(0x14f4, 0x1010001);
4367 write_mchbar32(0x14f8, 0x1110000);
4368 write_mchbar32(0x14fc, 0x5020020);
4369 write_mchbar32(0x1500, 0x5090220);
4370 write_mchbar32(0x1504, 0x2071310);
4371 write_mchbar32(0x1508, 0x2071420);
4372 write_mchbar32(0x150c, 0x5090220);
4373 write_mchbar32(0x1510, 0x1010001);
4374 write_mchbar32(0x1514, 0x1110000);
4375 write_mchbar32(0x1518, 0x7040120);
4376 write_mchbar32(0x151c, 0x2090220);
4377 write_mchbar32(0x1520, 0x70b1210);
4378 write_mchbar32(0x1524, 0x70b1310);
4379 write_mchbar32(0x1528, 0x2090220);
4380 write_mchbar32(0x152c, 0x1010001);
4381 write_mchbar32(0x1530, 0x1110000);
4382 write_mchbar32(0x1534, 0x1010110);
4383 write_mchbar32(0x1538, 0x1081310);
4384 write_mchbar32(0x153c, 0x5041200);
4385 write_mchbar32(0x1540, 0x5041310);
4386 write_mchbar32(0x1544, 0x1081310);
4387 write_mchbar32(0x1548, 0x1010001);
4388 write_mchbar32(0x154c, 0x1110000);
4389 write_mchbar32(0x1550, 0x1040120);
4390 write_mchbar32(0x1554, 0x4051210);
4391 write_mchbar32(0x1558, 0xd051200);
4392 write_mchbar32(0x155c, 0xd051200);
4393 write_mchbar32(0x1560, 0x4051210);
4394 write_mchbar32(0x1564, 0x1010001);
4395 write_mchbar32(0x1568, 0x1110000);
4396 write_mchbar16(0x1222, 0x220a);
4397 write_mchbar16(0x123c, 0x1fc0);
4398 write_mchbar16(0x1220, 0x1388);
4399 }
4400
4401 read_mchbar32(0x2c80); // !!!!
4402 write_mchbar32(0x2c80, 0x1053688);
4403 read_mchbar32(0x1c04); // !!!!
4404 write_mchbar32(0x1804, 0x406080);
4405
4406 read_mchbar8(0x2ca8);
4407
4408 if (x2ca8 == 0) {
4409 write_mchbar8(0x2ca8, read_mchbar8(0x2ca8) & ~3);
4410 write_mchbar8(0x2ca8, read_mchbar8(0x2ca8) + 4);
4411 write_mchbar32(0x1af0, read_mchbar32(0x1af0) | 0x10);
4412#if REAL
Patrick Georgi546953c2014-11-29 10:38:17 +01004413 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004414#else
4415 printf("CP5\n");
4416 exit(0);
4417#endif
4418 }
4419
4420 write_mchbar8(0x2ca8, read_mchbar8(0x2ca8));
4421 read_mchbar32(0x2c80); // !!!!
4422 write_mchbar32(0x2c80, 0x53688);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004423 pci_write_config32(PCI_DEV (0xff, 0, 0), 0x60, 0x20220);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004424 read_mchbar16(0x2c20); // !!!!
4425 read_mchbar16(0x2c10); // !!!!
4426 read_mchbar16(0x2c00); // !!!!
4427 write_mchbar16(0x2c00, 0x8c0);
4428 udelay(1000);
4429 write_1d0(0, 0x33d, 0, 0);
4430 write_500(&info, 0, 0, 0xb61, 0, 0);
4431 write_500(&info, 1, 0, 0xb61, 0, 0);
4432 write_mchbar32(0x1a30, 0x0);
4433 write_mchbar32(0x1a34, 0x0);
4434 write_mchbar16(0x614,
4435 0xb5b | (info.populated_ranks[1][0][0] *
4436 0x404) | (info.populated_ranks[0][0][0] *
4437 0xa0));
4438 write_mchbar16(0x616, 0x26a);
4439 write_mchbar32(0x134, 0x856000);
4440 write_mchbar32(0x160, 0x5ffffff);
4441 read_mchbar32(0x114); // !!!!
4442 write_mchbar32(0x114, 0xc2024440);
4443 read_mchbar32(0x118); // !!!!
4444 write_mchbar32(0x118, 0x4);
4445 for (channel = 0; channel < NUM_CHANNELS; channel++)
4446 write_mchbar32(0x260 + (channel << 10),
4447 0x30809ff |
4448 ((info.
4449 populated_ranks_mask[channel] & 3) << 20));
4450 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4451 write_mchbar16(0x31c + (channel << 10), 0x101);
4452 write_mchbar16(0x360 + (channel << 10), 0x909);
4453 write_mchbar16(0x3a4 + (channel << 10), 0x101);
4454 write_mchbar16(0x3e8 + (channel << 10), 0x101);
4455 write_mchbar32(0x320 + (channel << 10), 0x29002900);
4456 write_mchbar32(0x324 + (channel << 10), 0x0);
4457 write_mchbar32(0x368 + (channel << 10), 0x32003200);
4458 write_mchbar16(0x352 + (channel << 10), 0x505);
4459 write_mchbar16(0x354 + (channel << 10), 0x3c3c);
4460 write_mchbar16(0x356 + (channel << 10), 0x1040);
4461 write_mchbar16(0x39a + (channel << 10), 0x73e4);
4462 write_mchbar16(0x3de + (channel << 10), 0x77ed);
4463 write_mchbar16(0x422 + (channel << 10), 0x1040);
4464 }
4465
4466 write_1d0(0x4, 0x151, 4, 1);
4467 write_1d0(0, 0x142, 3, 1);
4468 rdmsr(0x1ac); // !!!!
4469 write_500(&info, 1, 1, 0x6b3, 4, 1);
4470 write_500(&info, 1, 1, 0x6cf, 4, 1);
4471
4472 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4473
4474 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4475 populated_ranks[0]
4476 [0][0]) << 0),
4477 0x1d1, 3, 1);
4478 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4479 write_mchbar16(0x38e + (channel << 10), 0x5f5f);
4480 write_mchbar16(0x3d2 + (channel << 10), 0x5f5f);
4481 }
4482
4483 set_334(0);
4484
4485 program_base_timings(&info);
4486
4487 write_mchbar8(0x5ff, read_mchbar8(0x5ff) | 0x80); /* OK */
4488
4489 write_1d0(0x2, 0x1d5, 2, 1);
4490 write_1d0(0x20, 0x166, 7, 1);
4491 write_1d0(0x0, 0xeb, 3, 1);
4492 write_1d0(0x0, 0xf3, 6, 1);
4493
4494 for (channel = 0; channel < NUM_CHANNELS; channel++)
4495 for (lane = 0; lane < 9; lane++) {
4496 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4497 u8 a;
4498 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4499 write_500(&info, channel, a, addr, 6, 1);
4500 }
4501
4502 udelay(1000);
4503
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004504 if (s3resume) {
4505 if (info.cached_training == NULL) {
4506 u32 reg32;
4507 printk(BIOS_ERR,
4508 "Couldn't find training data. Rebooting\n");
4509 reg32 = inl(DEFAULT_PMBASE + 0x04);
4510 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4511 outb(0xe, 0xcf9);
4512
4513#if REAL
Patrick Georgi546953c2014-11-29 10:38:17 +01004514 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004515#else
4516 printf("CP5\n");
4517 exit(0);
4518#endif
4519 }
4520 int tm;
4521 info.training = *info.cached_training;
4522 for (tm = 0; tm < 4; tm++)
4523 for (channel = 0; channel < NUM_CHANNELS; channel++)
4524 for (slot = 0; slot < NUM_SLOTS; slot++)
4525 for (rank = 0; rank < NUM_RANKS; rank++)
4526 for (lane = 0; lane < 9; lane++)
4527 write_500(&info,
4528 channel,
4529 info.training.
4530 lane_timings
4531 [tm][channel]
4532 [slot][rank]
4533 [lane],
4534 get_timing_register_addr
4535 (lane, tm,
4536 slot, rank),
4537 9, 0);
4538 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4539 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4540 }
4541
4542 read_mchbar32(0x1f4); // !!!!
4543 write_mchbar32(0x1f4, 0x20000);
4544 write_mchbar32(0x1f0, 0x1d000200);
4545 read_mchbar8(0x1f0); // !!!!
4546 write_mchbar8(0x1f0, 0x1);
4547 read_mchbar8(0x1f0); // !!!!
4548
4549 program_board_delay(&info);
4550
4551 write_mchbar8(0x5ff, 0x0); /* OK */
4552 write_mchbar8(0x5ff, 0x80); /* OK */
4553 write_mchbar8(0x5f4, 0x1); /* OK */
4554
4555 write_mchbar32(0x130, read_mchbar32(0x130) & 0xfffffffd); // | 2 when ?
Elyes HAOUAS7db506c2016-10-02 11:56:39 +02004556 while (read_mchbar32(0x130) & 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004557 gav(read_1d0(0x14b, 7)); // = 0x81023100
4558 write_1d0(0x30, 0x14b, 7, 1);
4559 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4560 write_1d0(7, 0xd6, 6, 1);
4561 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4562 write_1d0(7, 0x328, 6, 1);
4563
4564 for (channel = 0; channel < NUM_CHANNELS; channel++)
4565 set_4cf(&info, channel,
4566 info.populated_ranks[channel][0][0] ? 8 : 0);
4567
4568 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4569 write_1d0(2, 0x116, 4, 1);
4570 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4571 write_1d0(0, 0xae, 6, 1);
4572 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4573 write_1d0(0, 0x300, 6, 1);
4574 read_mchbar16(0x356); // !!!!
4575 write_mchbar16(0x356, 0x1040);
4576 read_mchbar16(0x756); // !!!!
4577 write_mchbar16(0x756, 0x1040);
4578 write_mchbar32(0x140, read_mchbar32(0x140) & ~0x07000000);
4579 write_mchbar32(0x138, read_mchbar32(0x138) & ~0x07000000);
4580 write_mchbar32(0x130, 0x31111301);
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004581 /* Wait until REG130b0 is 1. */
4582 while (read_mchbar32(0x130) & 1)
4583 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004584
4585 {
4586 u32 t;
4587 u8 val_a1;
4588 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4589 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4590 rmw_1d0(0x320, 0x07,
4591 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4592 rmw_1d0(0x14b, 0x78,
4593 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4594 4), 7,
4595 1);
4596 rmw_1d0(0xce, 0x38,
4597 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4598 4), 6,
4599 1);
4600 }
4601
4602 for (channel = 0; channel < NUM_CHANNELS; channel++)
4603 set_4cf(&info, channel,
4604 info.populated_ranks[channel][0][0] ? 9 : 1);
4605
4606 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
4607 read_mchbar32(0x144); // !!!!
4608 write_1d0(2, 0xae, 6, 1);
4609 write_1d0(2, 0x300, 6, 1);
4610 write_1d0(2, 0x121, 3, 1);
4611 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4612 write_1d0(4, 0xd6, 6, 1);
4613 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4614 write_1d0(4, 0x328, 6, 1);
4615
4616 for (channel = 0; channel < NUM_CHANNELS; channel++)
4617 set_4cf(&info, channel,
4618 info.populated_ranks[channel][0][0] ? 9 : 0);
4619
4620 write_mchbar32(0x130,
4621 0x11111301 | (info.
4622 populated_ranks[1][0][0] << 30) | (info.
4623 populated_ranks
4624 [0][0]
4625 [0] <<
4626 29));
Elyes HAOUAS7db506c2016-10-02 11:56:39 +02004627 while (read_mchbar8(0x130) & 1); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004628 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4629 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4630 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4631 write_1d0(0, 0x21c, 6, 1);
4632 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4633 write_1d0(0x35, 0x14b, 7, 1);
4634
4635 for (channel = 0; channel < NUM_CHANNELS; channel++)
4636 set_4cf(&info, channel,
4637 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4638
4639 set_334(1);
4640
4641 write_mchbar8(0x1e8, 0x4); /* OK */
4642
4643 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4644 write_500(&info, channel,
4645 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4646 1);
4647 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4648 }
4649 write_mchbar32(0x2d0, (read_mchbar32(0x2d0) & 0xff2c01ff) | 0x200000); /* OK */
4650 write_mchbar16(0x6c0, 0x14a0); /* OK */
4651 write_mchbar32(0x6d0, (read_mchbar32(0x6d0) & 0xff0080ff) | 0x8000); /* OK */
4652 write_mchbar16(0x232, 0x8);
4653 write_mchbar32(0x234, (read_mchbar32(0x234) & 0xfffbfffb) | 0x40004); /* 0x40004 or 0 depending on ? */
4654 write_mchbar32(0x34, (read_mchbar32(0x34) & 0xfffffffd) | 5); /* OK */
4655 write_mchbar32(0x128, 0x2150d05);
4656 write_mchbar8(0x12c, 0x1f); /* OK */
4657 write_mchbar8(0x12d, 0x56); /* OK */
4658 write_mchbar8(0x12e, 0x31);
4659 write_mchbar8(0x12f, 0x0); /* OK */
4660 write_mchbar8(0x271, 0x2); /* OK */
4661 write_mchbar8(0x671, 0x2); /* OK */
4662 write_mchbar8(0x1e8, 0x4); /* OK */
4663 for (channel = 0; channel < NUM_CHANNELS; channel++)
4664 write_mchbar32(0x294 + (channel << 10),
4665 (info.populated_ranks_mask[channel] & 3) << 16);
4666 write_mchbar32(0x134, (read_mchbar32(0x134) & 0xfc01ffff) | 0x10000); /* OK */
4667 write_mchbar32(0x134, (read_mchbar32(0x134) & 0xfc85ffff) | 0x850000); /* OK */
4668 for (channel = 0; channel < NUM_CHANNELS; channel++)
4669 write_mchbar32(0x260 + (channel << 10),
4670 (read_mchbar32(0x260 + (channel << 10)) &
4671 ~0xf00000) | 0x8000000 | ((info.
4672 populated_ranks_mask
4673 [channel] & 3) <<
4674 20));
4675
4676 if (!s3resume)
4677 jedec_init(&info);
4678
4679 int totalrank = 0;
4680 for (channel = 0; channel < NUM_CHANNELS; channel++)
4681 for (slot = 0; slot < NUM_SLOTS; slot++)
4682 for (rank = 0; rank < NUM_RANKS; rank++)
4683 if (info.populated_ranks[channel][slot][rank]) {
4684 jedec_read(&info, channel, slot, rank,
4685 totalrank, 0xa, 0x400);
4686 totalrank++;
4687 }
4688
4689 write_mchbar8(0x12c, 0x9f);
4690
4691 read_mchbar8(0x271); // 2 // !!!!
4692 write_mchbar8(0x271, 0xe);
4693 read_mchbar8(0x671); // !!!!
4694 write_mchbar8(0x671, 0xe);
4695
4696 if (!s3resume) {
4697 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4698 write_mchbar32(0x294 + (channel << 10),
4699 (info.
4700 populated_ranks_mask[channel] & 3) <<
4701 16);
4702 write_mchbar16(0x298 + (channel << 10),
4703 (info.
4704 populated_ranks[channel][0][0]) | (info.
4705 populated_ranks
4706 [channel]
4707 [0]
4708 [1]
4709 <<
4710 5));
4711 write_mchbar32(0x29c + (channel << 10), 0x77a);
4712 }
4713 read_mchbar32(0x2c0); /// !!!
4714 write_mchbar32(0x2c0, 0x6009cc00);
4715
4716 {
4717 u8 a, b;
4718 a = read_mchbar8(0x243); // !!!!
4719 b = read_mchbar8(0x643); // !!!!
4720 write_mchbar8(0x243, a | 2);
4721 write_mchbar8(0x643, b | 2);
4722 }
4723
4724 write_1d0(7, 0x19b, 3, 1);
4725 write_1d0(7, 0x1c0, 3, 1);
4726 write_1d0(4, 0x1c6, 4, 1);
4727 write_1d0(4, 0x1cc, 4, 1);
4728 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4729 write_1d0(4, 0x151, 4, 1);
4730 write_mchbar32(0x584, 0xfffff);
4731 write_mchbar32(0x984, 0xfffff);
4732
4733 for (channel = 0; channel < NUM_CHANNELS; channel++)
4734 for (slot = 0; slot < NUM_SLOTS; slot++)
4735 for (rank = 0; rank < NUM_RANKS; rank++)
4736 if (info.
4737 populated_ranks[channel][slot]
4738 [rank])
4739 config_rank(&info, s3resume,
4740 channel, slot,
4741 rank);
4742
4743 write_mchbar8(0x243, 0x1);
4744 write_mchbar8(0x643, 0x1);
4745 }
4746
4747 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004748 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004749 write_26c(0, 0x820);
4750 write_26c(1, 0x820);
4751 write_mchbar32(0x130, read_mchbar32(0x130) | 2);
4752 /* end */
4753
4754 if (s3resume) {
4755 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4756 write_mchbar32(0x294 + (channel << 10),
4757 (info.
4758 populated_ranks_mask[channel] & 3) <<
4759 16);
4760 write_mchbar16(0x298 + (channel << 10),
4761 (info.
4762 populated_ranks[channel][0][0]) | (info.
4763 populated_ranks
4764 [channel]
4765 [0]
4766 [1]
4767 <<
4768 5));
4769 write_mchbar32(0x29c + (channel << 10), 0x77a);
4770 }
4771 read_mchbar32(0x2c0); /// !!!
4772 write_mchbar32(0x2c0, 0x6009cc00);
4773 }
4774
4775 write_mchbar32(0xfa4, read_mchbar32(0xfa4) & ~0x01000002);
4776 write_mchbar32(0xfb0, 0x2000e019);
4777
4778#if !REAL
4779 printf("CP16\n");
4780#endif
4781
4782 /* Before training. */
4783 timestamp_add_now(103);
4784
4785 if (!s3resume)
4786 ram_training(&info);
4787
4788 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004789 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004790
4791 dump_timings(&info);
4792
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004793 program_modules_memory_map(&info, 0);
4794 program_total_memory_map(&info);
4795
4796 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
4797 write_mchbar8(0x111, 0x20 | (0 << 2) | (1 << 6) | (0 << 7));
4798 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
4799 write_mchbar8(0x111, 0x20 | (3 << 2) | (0 << 6) | (1 << 7));
4800 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
4801 write_mchbar8(0x111, 0x20 | (3 << 2) | (0 << 6) | (0 << 7));
4802 else
4803 write_mchbar8(0x111, 0x20 | (3 << 2) | (1 << 6) | (0 << 7));
4804
4805 write_mchbar32(0xfac, read_mchbar32(0xfac) & ~0x80000000); // OK
4806 write_mchbar32(0xfb4, 0x4800); // OK
4807 write_mchbar32(0xfb8, (info.revision < 8) ? 0x20 : 0x0); // OK
4808 write_mchbar32(0xe94, 0x7ffff); // OK
4809 write_mchbar32(0xfc0, 0x80002040); // OK
4810 write_mchbar32(0xfc4, 0x701246); // OK
4811 write_mchbar8(0xfc8, read_mchbar8(0xfc8) & ~0x70); // OK
4812 write_mchbar32(0xe5c, 0x1000000 | read_mchbar32(0xe5c)); // OK
4813 write_mchbar32(0x1a70, (read_mchbar32(0x1a70) | 0x00200000) & ~0x00100000); // OK
4814 write_mchbar32(0x50, 0x700b0); // OK
4815 write_mchbar32(0x3c, 0x10); // OK
4816 write_mchbar8(0x1aa8, (read_mchbar8(0x1aa8) & ~0x35) | 0xa); // OK
4817 write_mchbar8(0xff4, read_mchbar8(0xff4) | 0x2); // OK
4818 write_mchbar32(0xff8, (read_mchbar32(0xff8) & ~0xe008) | 0x1020); // OK
4819
4820#if REAL
4821 write_mchbar32(0xd00, IOMMU_BASE2 | 1);
4822 write_mchbar32(0xd40, IOMMU_BASE1 | 1);
4823 write_mchbar32(0xdc0, IOMMU_BASE4 | 1);
4824
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004825 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4826 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4827 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004828
4829#else
4830 {
4831 u32 eax;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004832 eax = read32p(0xffc + (read_mchbar32(0xd00) & ~1)) | 0x08000000; // = 0xe911714b// OK
4833 write32p(0xffc + (read_mchbar32(0xd00) & ~1), eax); // OK
4834 eax = read32p(0xffc + (read_mchbar32(0xdc0) & ~1)) | 0x40000000; // = 0xe911714b// OK
4835 write32p(0xffc + (read_mchbar32(0xdc0) & ~1), eax); // OK
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004836 }
4837#endif
4838
4839 {
4840 u32 eax;
4841
4842 eax = info.fsb_frequency / 9;
4843 write_mchbar32(0xfcc, (read_mchbar32(0xfcc) & 0xfffc0000) | (eax * 0x280) | (eax * 0x5000) | eax | 0x40000); // OK
4844 write_mchbar32(0x20, 0x33001); //OK
4845 }
4846
4847 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4848 write_mchbar32(0x220 + (channel << 10), read_mchbar32(0x220 + (channel << 10)) & ~0x7770); //OK
4849 if (info.max_slots_used_in_channel == 1)
4850 write_mchbar16(0x237 + (channel << 10), (read_mchbar16(0x237 + (channel << 10)) | 0x0201)); //OK
4851 else
4852 write_mchbar16(0x237 + (channel << 10), (read_mchbar16(0x237 + (channel << 10)) & ~0x0201)); //OK
4853
4854 write_mchbar8(0x241 + (channel << 10), read_mchbar8(0x241 + (channel << 10)) | 1); // OK
4855
4856 if (info.clock_speed_index <= 1
4857 && (info.silicon_revision == 2
4858 || info.silicon_revision == 3))
4859 write_mchbar32(0x248 + (channel << 10), (read_mchbar32(0x248 + (channel << 10)) | 0x00102000)); // OK
4860 else
4861 write_mchbar32(0x248 + (channel << 10), (read_mchbar32(0x248 + (channel << 10)) & ~0x00102000)); // OK
4862 }
4863
4864 write_mchbar32(0x115, read_mchbar32(0x115) | 0x1000000); // OK
4865
4866 {
4867 u8 al;
4868 al = 0xd;
4869 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4870 al += 2;
4871 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
4872 write_mchbar32(0x210, (al << 16) | 0x20); // OK
4873 }
4874
4875 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4876 write_mchbar32(0x288 + (channel << 10), 0x70605040); // OK
4877 write_mchbar32(0x28c + (channel << 10), 0xfffec080); // OK
4878 write_mchbar32(0x290 + (channel << 10), 0x282091c | ((info.max_slots_used_in_channel - 1) << 0x16)); // OK
4879 }
4880 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004881 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004882 reg1c = read32p(DEFAULT_EPBAR | 0x01c); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004883 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004884 write32p(DEFAULT_EPBAR | 0x01c, reg1c); // OK
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004885 read_mchbar8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004886 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004887 write_mchbar8(0x1210, read_mchbar8(0x1210) | 2); // OK
4888 write_mchbar32(0x1200, 0x8800440); // OK
4889 write_mchbar32(0x1204, 0x53ff0453); // OK
4890 write_mchbar32(0x1208, 0x19002043); // OK
4891 write_mchbar16(0x1214, 0x320); // OK
4892
4893 if (info.revision == 0x10 || info.revision == 0x11) {
4894 write_mchbar16(0x1214, 0x220); // OK
4895 write_mchbar8(0x1210, read_mchbar8(0x1210) | 0x40); // OK
4896 }
4897
4898 write_mchbar8(0x1214, read_mchbar8(0x1214) | 0x4); // OK
4899 write_mchbar8(0x120c, 0x1); // OK
4900 write_mchbar8(0x1218, 0x3); // OK
4901 write_mchbar8(0x121a, 0x3); // OK
4902 write_mchbar8(0x121c, 0x3); // OK
4903 write_mchbar16(0xc14, 0x0); // OK
4904 write_mchbar16(0xc20, 0x0); // OK
4905 write_mchbar32(0x1c, 0x0); // OK
4906
4907 /* revision dependent here. */
4908
4909 write_mchbar16(0x1230, read_mchbar16(0x1230) | 0x1f07); // OK
4910
4911 if (info.uma_enabled)
4912 write_mchbar32(0x11f4, read_mchbar32(0x11f4) | 0x10000000); // OK
4913
4914 write_mchbar16(0x1230, read_mchbar16(0x1230) | 0x8000); // OK
4915 write_mchbar8(0x1214, read_mchbar8(0x1214) | 1); // OK
4916
4917 u8 bl, ebpb;
4918 u16 reg_1020;
4919
4920 reg_1020 = read_mchbar32(0x1020); // = 0x6c733c // OK
4921 write_mchbar8(0x1070, 0x1); // OK
4922
4923 write_mchbar32(0x1000, 0x100); // OK
4924 write_mchbar8(0x1007, 0x0); // OK
4925
4926 if (reg_1020 != 0) {
4927 write_mchbar16(0x1018, 0x0); // OK
4928 bl = reg_1020 >> 8;
4929 ebpb = reg_1020 & 0xff;
4930 } else {
4931 ebpb = 0;
4932 bl = 8;
4933 }
4934
4935 rdmsr(0x1a2);
4936
4937 write_mchbar32(0x1014, 0xffffffff); // OK
4938
4939 write_mchbar32(0x1010, ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (! !reg_1020)); // OK
4940
4941 write_mchbar8(0x101c, 0xb8); // OK
4942
4943 write_mchbar8(0x123e, (read_mchbar8(0x123e) & 0xf) | 0x60); // OK
4944 if (reg_1020 != 0) {
4945 write_mchbar32(0x123c, (read_mchbar32(0x123c) & ~0x00900000) | 0x600000); // OK
4946 write_mchbar8(0x101c, 0xb8); // OK
4947 }
4948
4949 setup_heci_uma(&info);
4950
4951 if (info.uma_enabled) {
4952 u16 ax;
4953 write_mchbar32(0x11b0, read_mchbar32(0x11b0) | 0x4000); // OK
4954 write_mchbar32(0x11b4, read_mchbar32(0x11b4) | 0x4000); // OK
4955 write_mchbar16(0x1190, read_mchbar16(0x1190) | 0x4000); // OK
4956
4957 ax = read_mchbar16(0x1190) & 0xf00; // = 0x480a // OK
4958 write_mchbar16(0x1170, ax | (read_mchbar16(0x1170) & 0x107f) | 0x4080); // OK
4959 write_mchbar16(0x1170, read_mchbar16(0x1170) | 0x1000); // OK
4960#if REAL
4961 udelay(1000);
4962#endif
4963 u16 ecx;
Elyes HAOUAS7db506c2016-10-02 11:56:39 +02004964 for (ecx = 0xffff; ecx && (read_mchbar16(0x1170) & 0x1000); ecx--); // OK
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004965 write_mchbar16(0x1190, read_mchbar16(0x1190) & ~0x4000); // OK
4966 }
4967
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004968 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4969 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004970 udelay(10000);
Vladimir Serbinenkoc7db28c2014-02-19 22:09:33 +01004971 write_mchbar16(0x2ca8, 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004972
4973#if REAL
4974 udelay(1000);
4975 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004976 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4977
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004978 if (!s3resume)
4979 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004980 if (s3resume && cbmem_wasnot_inited) {
4981 u32 reg32;
4982 printk(BIOS_ERR, "Failed S3 resume.\n");
4983 ram_check(0x100000, 0x200000);
4984
4985 /* Clear SLP_TYPE. */
4986 reg32 = inl(DEFAULT_PMBASE + 0x04);
4987 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4988
4989 /* Failed S3 resume, reset to come up cleanly */
4990 outb(0xe, 0xcf9);
Patrick Georgi546953c2014-11-29 10:38:17 +01004991 halt();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004992 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004993#endif
4994}