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