blob: c730b5ef5f0a928456642e274a37d299be8d50b9 [file] [log] [blame]
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013 Vladimir Serbinenko.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010015 */
16
Kyösti Mälkki931c1dc2014-06-30 09:40:19 +030017#include <stdlib.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010018#include <console/console.h>
19#include <string.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010020#include <arch/io.h>
21#include <cpu/x86/msr.h>
22#include <cbmem.h>
23#include <arch/cbfs.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010024#include <ip_checksum.h>
25#include <pc80/mc146818rtc.h>
26#include <device/pci_def.h>
Patrick Rudolph266a1f72016-06-09 18:13:34 +020027#include <device/device.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010028#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010029#include <spd.h>
30#include "raminit.h"
Patrick Rudolph266a1f72016-06-09 18:13:34 +020031#include "chip.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010032#include <timestamp.h>
33#include <cpu/x86/mtrr.h>
34#include <cpu/intel/speedstep.h>
35#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010036#include <mrc_cache.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010037
38#include "nehalem.h"
39
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020040#include <southbridge/intel/ibexpeak/me.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010041#include <delay.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010042
43#define NORTHBRIDGE PCI_DEV(0, 0, 0)
44#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
45#define GMA PCI_DEV (0, 0x2, 0x0)
46#define HECIDEV PCI_DEV(0, 0x16, 0)
47#define HECIBAR 0x10
48
49#define FOR_ALL_RANKS \
50 for (channel = 0; channel < NUM_CHANNELS; channel++) \
51 for (slot = 0; slot < NUM_SLOTS; slot++) \
52 for (rank = 0; rank < NUM_RANKS; rank++)
53
54#define FOR_POPULATED_RANKS \
55 for (channel = 0; channel < NUM_CHANNELS; channel++) \
56 for (slot = 0; slot < NUM_SLOTS; slot++) \
57 for (rank = 0; rank < NUM_RANKS; rank++) \
58 if (info->populated_ranks[channel][slot][rank])
59
60#define FOR_POPULATED_RANKS_BACKWARDS \
61 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
62 for (slot = 0; slot < NUM_SLOTS; slot++) \
63 for (rank = 0; rank < NUM_RANKS; rank++) \
64 if (info->populated_ranks[channel][slot][rank])
65
66/* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */
67typedef struct {
68 u8 smallest;
69 u8 largest;
70} timing_bounds_t[2][2][2][9];
71
Arthur Heymansdc71e252018-01-29 10:14:48 +010072#define MRC_CACHE_VERSION 1
73
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010074struct ram_training {
75 /* [TM][CHANNEL][SLOT][RANK][LANE] */
76 u16 lane_timings[4][2][2][2][9];
77 u16 reg_178;
78 u16 reg_10b;
79
80 u8 reg178_center;
81 u8 reg178_smallest;
82 u8 reg178_largest;
83 timing_bounds_t timing_bounds[2];
84 u16 timing_offset[2][2][2][9];
85 u16 timing2_offset[2][2][2][9];
86 u16 timing2_bounds[2][2][2][9][2];
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +010087 u8 reg274265[2][3]; /* [CHANNEL][REGISTER] */
88 u8 reg2ca9_bit0;
89 u32 reg_6dc;
90 u32 reg_6e8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010091};
92
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010093#include <lib.h> /* Prototypes */
94
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010095
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010096static void clflush(u32 addr)
97{
98 asm volatile ("clflush (%0)"::"r" (addr));
99}
100
101typedef struct _u128 {
102 u64 lo;
103 u64 hi;
104} u128;
105
106static void read128(u32 addr, u64 * out)
107{
108 u128 ret;
109 u128 stor;
110 asm volatile ("movdqu %%xmm0, %0\n"
111 "movdqa (%2), %%xmm0\n"
112 "movdqu %%xmm0, %1\n"
113 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
114 out[0] = ret.lo;
115 out[1] = ret.hi;
116}
117
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100118/* OK */
119static void write_1d0(u32 val, u16 addr, int bits, int flag)
120{
Felix Held04be2dd2018-07-29 04:53:22 +0200121 MCHBAR32(0x1d0) = 0;
122 while (MCHBAR32(0x1d0) & 0x800000)
123 ;
124 MCHBAR32(0x1d4) =
125 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
126 MCHBAR32(0x1d0) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200127 while (MCHBAR32(0x1d0) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200128 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100129}
130
131/* OK */
132static u16 read_1d0(u16 addr, int split)
133{
134 u32 val;
Felix Held04be2dd2018-07-29 04:53:22 +0200135 MCHBAR32(0x1d0) = 0;
136 while (MCHBAR32(0x1d0) & 0x800000)
137 ;
138 MCHBAR32(0x1d0) =
139 0x80000000 | (((MCHBAR8(0x246) >> 2) & 3) + 0x361 - addr);
140 while (MCHBAR32(0x1d0) & 0x800000)
141 ;
142 val = MCHBAR32(0x1d8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100143 write_1d0(0, 0x33d, 0, 0);
144 write_1d0(0, 0x33d, 0, 0);
145 val &= ((1 << split) - 1);
146 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
147 return val;
148}
149
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800150static void write32p(uintptr_t addr, uint32_t val)
151{
152 write32((void *)addr, val);
153}
154
155static uint32_t read32p(uintptr_t addr)
156{
157 return read32((void *)addr);
158}
159
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100160static void sfence(void)
161{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100162 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100163}
164
165static inline u16 get_lane_offset(int slot, int rank, int lane)
166{
167 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
168 0x452 * (lane == 8);
169}
170
171static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
172{
173 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
174 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
175}
176
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100177static u32 gav_real(int line, u32 in)
178{
179 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
180 return in;
181}
182
183#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200184
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100185struct raminfo {
186 u16 clock_speed_index; /* clock_speed (REAL, not DDR) / 133.(3) - 3 */
187 u16 fsb_frequency; /* in 1.(1)/2 MHz. */
188 u8 is_x16_module[2][2]; /* [CHANNEL][SLOT] */
189 u8 density[2][2]; /* [CHANNEL][SLOT] */
190 u8 populated_ranks[2][2][2]; /* [CHANNEL][SLOT][RANK] */
191 int rank_start[2][2][2];
192 u8 cas_latency;
193 u8 board_lane_delay[9];
194 u8 use_ecc;
195 u8 revision;
196 u8 max_supported_clock_speed_index;
197 u8 uma_enabled;
198 u8 spd[2][2][151]; /* [CHANNEL][SLOT][BYTE] */
199 u8 silicon_revision;
200 u8 populated_ranks_mask[2];
201 u8 max_slots_used_in_channel;
202 u8 mode4030[2];
203 u16 avg4044[2];
204 u16 max4048[2];
205 unsigned total_memory_mb;
206 unsigned interleaved_part_mb;
207 unsigned non_interleaved_part_mb;
208
209 u32 heci_bar;
210 u64 heci_uma_addr;
211 unsigned memory_reserved_for_heci_mb;
212
213 struct ram_training training;
214 u32 last_500_command[2];
215
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100216 u32 delay46_ps[2];
217 u32 delay54_ps[2];
218 u8 revision_flag_1;
219 u8 some_delay_1_cycle_floor;
220 u8 some_delay_2_halfcycles_ceil;
221 u8 some_delay_3_ps_rounded;
222
223 const struct ram_training *cached_training;
224};
225
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200226/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100227timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200228
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100229static void
230write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
231 int flag);
232
233/* OK */
234static u16
235read_500(struct raminfo *info, int channel, u16 addr, int split)
236{
237 u32 val;
238 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200239 MCHBAR32(0x500 + (channel << 10)) = 0;
240 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
241 ;
242 MCHBAR32(0x500 + (channel << 10)) =
243 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
244 + 0xb88 - addr);
245 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
246 ;
247 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100248 return val & ((1 << split) - 1);
249}
250
251/* OK */
252static void
253write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
254 int flag)
255{
256 if (info->last_500_command[channel] == 0x80000000) {
257 info->last_500_command[channel] = 0x40000000;
258 write_500(info, channel, 0, 0xb61, 0, 0);
259 }
Felix Held04be2dd2018-07-29 04:53:22 +0200260 MCHBAR32(0x500 + (channel << 10)) = 0;
261 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
262 ;
263 MCHBAR32(0x504 + (channel << 10)) =
264 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
265 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200266 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200267 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100268}
269
270static int rw_test(int rank)
271{
272 const u32 mask = 0xf00fc33c;
273 int ok = 0xff;
274 int i;
275 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800276 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100277 sfence();
278 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800279 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100280 sfence();
281 for (i = 0; i < 32; i++) {
282 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800283 write32p((rank << 28) | (i << 3), pat);
284 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100285 }
286 sfence();
287 for (i = 0; i < 32; i++) {
288 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
289 int j;
290 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800291 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100292 for (j = 0; j < 4; j++)
293 if (((val >> (j * 8)) & 0xff) != pat)
294 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800295 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100296 for (j = 0; j < 4; j++)
297 if (((val >> (j * 8)) & 0xff) != pat)
298 ok &= ~(16 << j);
299 }
300 sfence();
301 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800302 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100303 sfence();
304 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800305 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100306
307 return ok;
308}
309
310static void
311program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
312{
313 int lane;
314 for (lane = 0; lane < 8; lane++) {
315 write_500(info, channel,
316 base +
317 info->training.
318 lane_timings[2][channel][slot][rank][lane],
319 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
320 write_500(info, channel,
321 base +
322 info->training.
323 lane_timings[3][channel][slot][rank][lane],
324 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
325 }
326}
327
328static void write_26c(int channel, u16 si)
329{
Felix Held04be2dd2018-07-29 04:53:22 +0200330 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
331 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
332 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100333}
334
335static u32 get_580(int channel, u8 addr)
336{
337 u32 ret;
338 gav(read_1d0(0x142, 3));
Felix Held04be2dd2018-07-29 04:53:22 +0200339 MCHBAR8(0x5ff) = 0x0;
340 MCHBAR8(0x5ff) = 0x80;
341 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
342 MCHBAR8_OR(0x580 + (channel << 10), 1);
343 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
344 ;
345 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100346 return ret;
347}
348
349const int cached_config = 0;
350
351#define NUM_CHANNELS 2
352#define NUM_SLOTS 2
353#define NUM_RANKS 2
354#define RANK_SHIFT 28
355#define CHANNEL_SHIFT 10
356
357#include "raminit_tables.c"
358
359static void seq9(struct raminfo *info, int channel, int slot, int rank)
360{
361 int i, lane;
362
363 for (i = 0; i < 2; i++)
364 for (lane = 0; lane < 8; lane++)
365 write_500(info, channel,
366 info->training.lane_timings[i +
367 1][channel][slot]
368 [rank][lane], get_timing_register_addr(lane,
369 i + 1,
370 slot,
371 rank),
372 9, 0);
373
374 write_1d0(1, 0x103, 6, 1);
375 for (lane = 0; lane < 8; lane++)
376 write_500(info, channel,
377 info->training.
378 lane_timings[0][channel][slot][rank][lane],
379 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
380
381 for (i = 0; i < 2; i++) {
382 for (lane = 0; lane < 8; lane++)
383 write_500(info, channel,
384 info->training.lane_timings[i +
385 1][channel][slot]
386 [rank][lane], get_timing_register_addr(lane,
387 i + 1,
388 slot,
389 rank),
390 9, 0);
391 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
392 }
393
394 gav(read_1d0(0x142, 3)); // = 0x10408118
Felix Held04be2dd2018-07-29 04:53:22 +0200395 MCHBAR8(0x5ff) = 0x0;
396 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100397 write_1d0(0x2, 0x142, 3, 1);
398 for (lane = 0; lane < 8; lane++) {
399 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
400 info->training.lane_timings[2][channel][slot][rank][lane] =
401 read_500(info, channel,
402 get_timing_register_addr(lane, 2, slot, rank), 9);
403 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
404 info->training.lane_timings[3][channel][slot][rank][lane] =
405 info->training.lane_timings[2][channel][slot][rank][lane] +
406 0x20;
407 }
408}
409
410static int count_ranks_in_channel(struct raminfo *info, int channel)
411{
412 int slot, rank;
413 int res = 0;
414 for (slot = 0; slot < NUM_SLOTS; slot++)
415 for (rank = 0; rank < NUM_SLOTS; rank++)
416 res += info->populated_ranks[channel][slot][rank];
417 return res;
418}
419
420static void
421config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
422{
423 int add;
424
425 write_1d0(0, 0x178, 7, 1);
426 seq9(info, channel, slot, rank);
427 program_timings(info, 0x80, channel, slot, rank);
428
429 if (channel == 0)
430 add = count_ranks_in_channel(info, 1);
431 else
432 add = 0;
433 if (!s3resume)
434 gav(rw_test(rank + add));
435 program_timings(info, 0x00, channel, slot, rank);
436 if (!s3resume)
437 gav(rw_test(rank + add));
438 if (!s3resume)
439 gav(rw_test(rank + add));
440 write_1d0(0, 0x142, 3, 1);
441 write_1d0(0, 0x103, 6, 1);
442
443 gav(get_580(channel, 0xc | (rank << 5)));
444 gav(read_1d0(0x142, 3));
445
Felix Held04be2dd2018-07-29 04:53:22 +0200446 MCHBAR8(0x5ff) = 0x0;
447 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100448}
449
450static void set_4cf(struct raminfo *info, int channel, u8 val)
451{
452 gav(read_500(info, channel, 0x4cf, 4)); // = 0xc2300cf9
453 write_500(info, channel, val, 0x4cf, 4, 1);
454 gav(read_500(info, channel, 0x659, 4)); // = 0x80300839
455 write_500(info, channel, val, 0x659, 4, 1);
456 gav(read_500(info, channel, 0x697, 4)); // = 0x80300839
457 write_500(info, channel, val, 0x697, 4, 1);
458}
459
460static void set_334(int zero)
461{
462 int j, k, channel;
463 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
464 u32 vd8[2][16];
465
466 for (channel = 0; channel < NUM_CHANNELS; channel++) {
467 for (j = 0; j < 4; j++) {
468 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
469 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
470 u16 c;
471 if ((j == 0 || j == 3) && zero)
472 c = 0;
473 else if (j == 3)
474 c = 0x5f;
475 else
476 c = 0x5f5f;
477
478 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200479 MCHBAR32(0x138 + 8 * k) =
480 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100481 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200482 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100483 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200484 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100485 }
486
Felix Held22ca8cb2018-07-29 05:09:44 +0200487 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
488 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200489 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
490 zero ? 0 : (0x18191819 & lmask);
491 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
492 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
493 zero ? 0 : (a & lmask);
494 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
495 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100496 }
497 }
498
Felix Held04be2dd2018-07-29 04:53:22 +0200499 MCHBAR32_OR(0x130, 1);
500 while (MCHBAR8(0x130) & 1)
501 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100502}
503
504static void rmw_1d0(u16 addr, u32 and, u32 or, int split, int flag)
505{
506 u32 v;
507 v = read_1d0(addr, split);
508 write_1d0((v & and) | or, addr, split, flag);
509}
510
511static int find_highest_bit_set(u16 val)
512{
513 int i;
514 for (i = 15; i >= 0; i--)
515 if (val & (1 << i))
516 return i;
517 return -1;
518}
519
520static int find_lowest_bit_set32(u32 val)
521{
522 int i;
523 for (i = 0; i < 32; i++)
524 if (val & (1 << i))
525 return i;
526 return -1;
527}
528
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100529enum {
530 DEVICE_TYPE = 2,
531 MODULE_TYPE = 3,
532 DENSITY = 4,
533 RANKS_AND_DQ = 7,
534 MEMORY_BUS_WIDTH = 8,
535 TIMEBASE_DIVIDEND = 10,
536 TIMEBASE_DIVISOR = 11,
537 CYCLETIME = 12,
538
539 CAS_LATENCIES_LSB = 14,
540 CAS_LATENCIES_MSB = 15,
541 CAS_LATENCY_TIME = 16,
542 THERMAL_AND_REFRESH = 31,
543 REFERENCE_RAW_CARD_USED = 62,
544 RANK1_ADDRESS_MAPPING = 63
545};
546
547static void calculate_timings(struct raminfo *info)
548{
549 unsigned cycletime;
550 unsigned cas_latency_time;
551 unsigned supported_cas_latencies;
552 unsigned channel, slot;
553 unsigned clock_speed_index;
554 unsigned min_cas_latency;
555 unsigned cas_latency;
556 unsigned max_clock_index;
557
558 /* Find common CAS latency */
559 supported_cas_latencies = 0x3fe;
560 for (channel = 0; channel < NUM_CHANNELS; channel++)
561 for (slot = 0; slot < NUM_SLOTS; slot++)
562 if (info->populated_ranks[channel][slot][0])
563 supported_cas_latencies &=
564 2 *
565 (info->
566 spd[channel][slot][CAS_LATENCIES_LSB] |
567 (info->
568 spd[channel][slot][CAS_LATENCIES_MSB] <<
569 8));
570
571 max_clock_index = min(3, info->max_supported_clock_speed_index);
572
573 cycletime = min_cycletime[max_clock_index];
574 cas_latency_time = min_cas_latency_time[max_clock_index];
575
576 for (channel = 0; channel < NUM_CHANNELS; channel++)
577 for (slot = 0; slot < NUM_SLOTS; slot++)
578 if (info->populated_ranks[channel][slot][0]) {
579 unsigned timebase;
580 timebase =
581 1000 *
582 info->
583 spd[channel][slot][TIMEBASE_DIVIDEND] /
584 info->spd[channel][slot][TIMEBASE_DIVISOR];
585 cycletime =
586 max(cycletime,
587 timebase *
588 info->spd[channel][slot][CYCLETIME]);
589 cas_latency_time =
590 max(cas_latency_time,
591 timebase *
592 info->
593 spd[channel][slot][CAS_LATENCY_TIME]);
594 }
595 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
596 if (cycletime == min_cycletime[clock_speed_index])
597 break;
598 if (cycletime > min_cycletime[clock_speed_index]) {
599 clock_speed_index--;
600 cycletime = min_cycletime[clock_speed_index];
601 break;
602 }
603 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100604 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100605 cas_latency = 0;
606 while (supported_cas_latencies) {
607 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
608 if (cas_latency <= min_cas_latency)
609 break;
610 supported_cas_latencies &=
611 ~(1 << find_highest_bit_set(supported_cas_latencies));
612 }
613
614 if (cas_latency != min_cas_latency && clock_speed_index)
615 clock_speed_index--;
616
617 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
618 die("Couldn't configure DRAM");
619 info->clock_speed_index = clock_speed_index;
620 info->cas_latency = cas_latency;
621}
622
623static void program_base_timings(struct raminfo *info)
624{
625 unsigned channel;
626 unsigned slot, rank, lane;
627 unsigned extended_silicon_revision;
628 int i;
629
630 extended_silicon_revision = info->silicon_revision;
631 if (info->silicon_revision == 0)
632 for (channel = 0; channel < NUM_CHANNELS; channel++)
633 for (slot = 0; slot < NUM_SLOTS; slot++)
634 if ((info->
635 spd[channel][slot][MODULE_TYPE] & 0xF) ==
636 3)
637 extended_silicon_revision = 4;
638
639 for (channel = 0; channel < NUM_CHANNELS; channel++) {
640 for (slot = 0; slot < NUM_SLOTS; slot++)
641 for (rank = 0; rank < NUM_SLOTS; rank++) {
642 int card_timing_2;
643 if (!info->populated_ranks[channel][slot][rank])
644 continue;
645
646 for (lane = 0; lane < 9; lane++) {
647 int tm_reg;
648 int card_timing;
649
650 card_timing = 0;
651 if ((info->
652 spd[channel][slot][MODULE_TYPE] &
653 0xF) == 3) {
654 int reference_card;
655 reference_card =
656 info->
657 spd[channel][slot]
658 [REFERENCE_RAW_CARD_USED] &
659 0x1f;
660 if (reference_card == 3)
661 card_timing =
662 u16_ffd1188[0][lane]
663 [info->
664 clock_speed_index];
665 if (reference_card == 5)
666 card_timing =
667 u16_ffd1188[1][lane]
668 [info->
669 clock_speed_index];
670 }
671
672 info->training.
673 lane_timings[0][channel][slot][rank]
674 [lane] =
675 u8_FFFD1218[info->
676 clock_speed_index];
677 info->training.
678 lane_timings[1][channel][slot][rank]
679 [lane] = 256;
680
681 for (tm_reg = 2; tm_reg < 4; tm_reg++)
682 info->training.
683 lane_timings[tm_reg]
684 [channel][slot][rank][lane]
685 =
686 u8_FFFD1240[channel]
687 [extended_silicon_revision]
688 [lane][2 * slot +
689 rank][info->
690 clock_speed_index]
691 + info->max4048[channel]
692 +
693 u8_FFFD0C78[channel]
694 [extended_silicon_revision]
695 [info->
696 mode4030[channel]][slot]
697 [rank][info->
698 clock_speed_index]
699 + card_timing;
700 for (tm_reg = 0; tm_reg < 4; tm_reg++)
701 write_500(info, channel,
702 info->training.
703 lane_timings[tm_reg]
704 [channel][slot][rank]
705 [lane],
706 get_timing_register_addr
707 (lane, tm_reg, slot,
708 rank), 9, 0);
709 }
710
711 card_timing_2 = 0;
712 if (!(extended_silicon_revision != 4
713 || (info->
714 populated_ranks_mask[channel] & 5) ==
715 5)) {
716 if ((info->
717 spd[channel][slot]
718 [REFERENCE_RAW_CARD_USED] & 0x1F)
719 == 3)
720 card_timing_2 =
721 u16_FFFE0EB8[0][info->
722 clock_speed_index];
723 if ((info->
724 spd[channel][slot]
725 [REFERENCE_RAW_CARD_USED] & 0x1F)
726 == 5)
727 card_timing_2 =
728 u16_FFFE0EB8[1][info->
729 clock_speed_index];
730 }
731
732 for (i = 0; i < 3; i++)
733 write_500(info, channel,
734 (card_timing_2 +
735 info->max4048[channel]
736 +
737 u8_FFFD0EF8[channel]
738 [extended_silicon_revision]
739 [info->
740 mode4030[channel]][info->
741 clock_speed_index]),
742 u16_fffd0c50[i][slot][rank],
743 8, 1);
744 write_500(info, channel,
745 (info->max4048[channel] +
746 u8_FFFD0C78[channel]
747 [extended_silicon_revision][info->
748 mode4030
749 [channel]]
750 [slot][rank][info->
751 clock_speed_index]),
752 u16_fffd0c70[slot][rank], 7, 1);
753 }
754 if (!info->populated_ranks_mask[channel])
755 continue;
756 for (i = 0; i < 3; i++)
757 write_500(info, channel,
758 (info->max4048[channel] +
759 info->avg4044[channel]
760 +
761 u8_FFFD17E0[channel]
762 [extended_silicon_revision][info->
763 mode4030
764 [channel]][info->
765 clock_speed_index]),
766 u16_fffd0c68[i], 8, 1);
767 }
768}
769
770static unsigned int fsbcycle_ps(struct raminfo *info)
771{
772 return 900000 / info->fsb_frequency;
773}
774
775/* The time of DDR transfer in ps. */
776static unsigned int halfcycle_ps(struct raminfo *info)
777{
778 return 3750 / (info->clock_speed_index + 3);
779}
780
781/* The time of clock cycle in ps. */
782static unsigned int cycle_ps(struct raminfo *info)
783{
784 return 2 * halfcycle_ps(info);
785}
786
787/* Frequency in 1.(1)=10/9 MHz units. */
788static unsigned frequency_11(struct raminfo *info)
789{
790 return (info->clock_speed_index + 3) * 120;
791}
792
793/* Frequency in 0.1 MHz units. */
794static unsigned frequency_01(struct raminfo *info)
795{
796 return 100 * frequency_11(info) / 9;
797}
798
799static unsigned ps_to_halfcycles(struct raminfo *info, unsigned int ps)
800{
801 return (frequency_11(info) * 2) * ps / 900000;
802}
803
804static unsigned ns_to_cycles(struct raminfo *info, unsigned int ns)
805{
806 return (frequency_11(info)) * ns / 900;
807}
808
809static void compute_derived_timings(struct raminfo *info)
810{
811 unsigned channel, slot, rank;
812 int extended_silicon_revision;
813 int some_delay_1_ps;
814 int some_delay_2_ps;
815 int some_delay_2_halfcycles_ceil;
816 int some_delay_2_halfcycles_floor;
817 int some_delay_3_ps;
818 int some_delay_3_halfcycles;
819 int some_delay_3_ps_rounded;
820 int some_delay_1_cycle_ceil;
821 int some_delay_1_cycle_floor;
822
823 some_delay_3_halfcycles = 0;
824 some_delay_3_ps_rounded = 0;
825 extended_silicon_revision = info->silicon_revision;
826 if (!info->silicon_revision)
827 for (channel = 0; channel < NUM_CHANNELS; channel++)
828 for (slot = 0; slot < NUM_SLOTS; slot++)
829 if ((info->
830 spd[channel][slot][MODULE_TYPE] & 0xF) ==
831 3)
832 extended_silicon_revision = 4;
833 if (info->board_lane_delay[7] < 5)
834 info->board_lane_delay[7] = 5;
835 info->revision_flag_1 = 2;
836 if (info->silicon_revision == 2 || info->silicon_revision == 3)
837 info->revision_flag_1 = 0;
838 if (info->revision < 16)
839 info->revision_flag_1 = 0;
840
841 if (info->revision < 8)
842 info->revision_flag_1 = 0;
843 if (info->revision >= 8 && (info->silicon_revision == 0
844 || info->silicon_revision == 1))
845 some_delay_2_ps = 735;
846 else
847 some_delay_2_ps = 750;
848
849 if (info->revision >= 0x10 && (info->silicon_revision == 0
850 || info->silicon_revision == 1))
851 some_delay_1_ps = 3929;
852 else
853 some_delay_1_ps = 3490;
854
855 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
856 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
857 if (some_delay_1_ps % cycle_ps(info))
858 some_delay_1_cycle_ceil++;
859 else
860 some_delay_1_cycle_floor--;
861 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
862 if (info->revision_flag_1)
863 some_delay_2_ps = halfcycle_ps(info) >> 6;
864 some_delay_2_ps +=
865 max(some_delay_1_ps - 30,
866 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
867 375;
868 some_delay_3_ps =
869 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
870 if (info->revision_flag_1) {
871 if (some_delay_3_ps < 150)
872 some_delay_3_halfcycles = 0;
873 else
874 some_delay_3_halfcycles =
875 (some_delay_3_ps << 6) / halfcycle_ps(info);
876 some_delay_3_ps_rounded =
877 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
878 }
879 some_delay_2_halfcycles_ceil =
880 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
881 2 * (some_delay_1_cycle_ceil - 1);
882 if (info->revision_flag_1 && some_delay_3_ps < 150)
883 some_delay_2_halfcycles_ceil++;
884 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
885 if (info->revision < 0x10)
886 some_delay_2_halfcycles_floor =
887 some_delay_2_halfcycles_ceil - 1;
888 if (!info->revision_flag_1)
889 some_delay_2_halfcycles_floor++;
890 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
891 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
892 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
893 || (info->populated_ranks[1][0][0]
894 && info->populated_ranks[1][1][0]))
895 info->max_slots_used_in_channel = 2;
896 else
897 info->max_slots_used_in_channel = 1;
898 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200899 MCHBAR32(0x244 + (channel << 10)) =
900 ((info->revision < 8) ? 1 : 0x200) |
901 ((2 - info->max_slots_used_in_channel) << 17) |
902 (channel << 21) |
903 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100904 if (info->max_slots_used_in_channel == 1) {
905 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
906 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
907 } else {
908 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 */
909 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
910 || (count_ranks_in_channel(info, 1) ==
911 2)) ? 2 : 3;
912 }
913 for (channel = 0; channel < NUM_CHANNELS; channel++) {
914 int max_of_unk;
915 int min_of_unk_2;
916
917 int i, count;
918 int sum;
919
920 if (!info->populated_ranks_mask[channel])
921 continue;
922
923 max_of_unk = 0;
924 min_of_unk_2 = 32767;
925
926 sum = 0;
927 count = 0;
928 for (i = 0; i < 3; i++) {
929 int unk1;
930 if (info->revision < 8)
931 unk1 =
932 u8_FFFD1891[0][channel][info->
933 clock_speed_index]
934 [i];
935 else if (!
936 (info->revision >= 0x10
937 || info->revision_flag_1))
938 unk1 =
939 u8_FFFD1891[1][channel][info->
940 clock_speed_index]
941 [i];
942 else
943 unk1 = 0;
944 for (slot = 0; slot < NUM_SLOTS; slot++)
945 for (rank = 0; rank < NUM_RANKS; rank++) {
946 int a = 0;
947 int b = 0;
948
949 if (!info->
950 populated_ranks[channel][slot]
951 [rank])
952 continue;
953 if (extended_silicon_revision == 4
954 && (info->
955 populated_ranks_mask[channel] &
956 5) != 5) {
957 if ((info->
958 spd[channel][slot]
959 [REFERENCE_RAW_CARD_USED] &
960 0x1F) == 3) {
961 a = u16_ffd1178[0]
962 [info->
963 clock_speed_index];
964 b = u16_fe0eb8[0][info->
965 clock_speed_index];
966 } else
967 if ((info->
968 spd[channel][slot]
969 [REFERENCE_RAW_CARD_USED]
970 & 0x1F) == 5) {
971 a = u16_ffd1178[1]
972 [info->
973 clock_speed_index];
974 b = u16_fe0eb8[1][info->
975 clock_speed_index];
976 }
977 }
978 min_of_unk_2 = min(min_of_unk_2, a);
979 min_of_unk_2 = min(min_of_unk_2, b);
980 if (rank == 0) {
981 sum += a;
982 count++;
983 }
984 {
985 int t;
986 t = b +
987 u8_FFFD0EF8[channel]
988 [extended_silicon_revision]
989 [info->
990 mode4030[channel]][info->
991 clock_speed_index];
992 if (unk1 >= t)
993 max_of_unk =
994 max(max_of_unk,
995 unk1 - t);
996 }
997 }
998 {
999 int t =
1000 u8_FFFD17E0[channel]
1001 [extended_silicon_revision][info->
1002 mode4030
1003 [channel]]
1004 [info->clock_speed_index] + min_of_unk_2;
1005 if (unk1 >= t)
1006 max_of_unk = max(max_of_unk, unk1 - t);
1007 }
1008 }
1009
1010 info->avg4044[channel] = sum / count;
1011 info->max4048[channel] = max_of_unk;
1012 }
1013}
1014
1015static void jedec_read(struct raminfo *info,
1016 int channel, int slot, int rank,
1017 int total_rank, u8 addr3, unsigned int value)
1018{
1019 /* Handle mirrored mapping. */
1020 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001021 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1022 ((addr3 >> 1) & 0x10);
1023 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1024 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001025
1026 /* Handle mirrored mapping. */
1027 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1028 value =
1029 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1030 << 1);
1031
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001032 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001033
Felix Held04be2dd2018-07-29 04:53:22 +02001034 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1035 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001036
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001037 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001038}
1039
1040enum {
1041 MR1_RZQ12 = 512,
1042 MR1_RZQ2 = 64,
1043 MR1_RZQ4 = 4,
1044 MR1_ODS34OHM = 2
1045};
1046
1047enum {
1048 MR0_BT_INTERLEAVED = 8,
1049 MR0_DLL_RESET_ON = 256
1050};
1051
1052enum {
1053 MR2_RTT_WR_DISABLED = 0,
1054 MR2_RZQ2 = 1 << 10
1055};
1056
1057static void jedec_init(struct raminfo *info)
1058{
1059 int write_recovery;
1060 int channel, slot, rank;
1061 int total_rank;
1062 int dll_on;
1063 int self_refresh_temperature;
1064 int auto_self_refresh;
1065
1066 auto_self_refresh = 1;
1067 self_refresh_temperature = 1;
1068 if (info->board_lane_delay[3] <= 10) {
1069 if (info->board_lane_delay[3] <= 8)
1070 write_recovery = info->board_lane_delay[3] - 4;
1071 else
1072 write_recovery = 5;
1073 } else {
1074 write_recovery = 6;
1075 }
1076 FOR_POPULATED_RANKS {
1077 auto_self_refresh &=
1078 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1079 self_refresh_temperature &=
1080 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1081 }
1082 if (auto_self_refresh == 1)
1083 self_refresh_temperature = 0;
1084
1085 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1086 || (info->populated_ranks[0][0][0]
1087 && info->populated_ranks[0][1][0])
1088 || (info->populated_ranks[1][0][0]
1089 && info->populated_ranks[1][1][0]));
1090
1091 total_rank = 0;
1092
1093 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1094 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1095 int rzq_reg58e;
1096
1097 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1098 rzq_reg58e = 64;
1099 rtt = MR1_RZQ2;
1100 if (info->clock_speed_index != 0) {
1101 rzq_reg58e = 4;
1102 if (info->populated_ranks_mask[channel] == 3)
1103 rtt = MR1_RZQ4;
1104 }
1105 } else {
1106 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1107 rtt = MR1_RZQ12;
1108 rzq_reg58e = 64;
1109 rtt_wr = MR2_RZQ2;
1110 } else {
1111 rzq_reg58e = 4;
1112 rtt = MR1_RZQ4;
1113 }
1114 }
1115
Felix Held04be2dd2018-07-29 04:53:22 +02001116 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1117 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1118 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1119 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1120 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001121
1122 for (slot = 0; slot < NUM_SLOTS; slot++)
1123 for (rank = 0; rank < NUM_RANKS; rank++)
1124 if (info->populated_ranks[channel][slot][rank]) {
1125 jedec_read(info, channel, slot, rank,
1126 total_rank, 0x28,
1127 rtt_wr | (info->
1128 clock_speed_index
1129 << 3)
1130 | (auto_self_refresh << 6) |
1131 (self_refresh_temperature <<
1132 7));
1133 jedec_read(info, channel, slot, rank,
1134 total_rank, 0x38, 0);
1135 jedec_read(info, channel, slot, rank,
1136 total_rank, 0x18,
1137 rtt | MR1_ODS34OHM);
1138 jedec_read(info, channel, slot, rank,
1139 total_rank, 6,
1140 (dll_on << 12) |
1141 (write_recovery << 9)
1142 | ((info->cas_latency - 4) <<
1143 4) | MR0_BT_INTERLEAVED |
1144 MR0_DLL_RESET_ON);
1145 total_rank++;
1146 }
1147 }
1148}
1149
1150static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1151{
1152 unsigned channel, slot, rank;
1153 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1154 unsigned int channel_0_non_interleaved;
1155
1156 FOR_ALL_RANKS {
1157 if (info->populated_ranks[channel][slot][rank]) {
1158 total_mb[channel] +=
1159 pre_jedec ? 256 : (256 << info->
1160 density[channel][slot] >> info->
1161 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001162 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1163 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1164 (info->is_x16_module[channel][slot] |
1165 ((info->density[channel][slot] + 1) << 1))) |
1166 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001167 }
Felix Held04be2dd2018-07-29 04:53:22 +02001168 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1169 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001170 }
1171
1172 info->total_memory_mb = total_mb[0] + total_mb[1];
1173
1174 info->interleaved_part_mb =
1175 pre_jedec ? 0 : 2 * min(total_mb[0], total_mb[1]);
1176 info->non_interleaved_part_mb =
1177 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1178 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001179 MCHBAR32(0x100) = channel_0_non_interleaved |
1180 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001181 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001182 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001183}
1184
1185static void program_board_delay(struct raminfo *info)
1186{
1187 int cas_latency_shift;
1188 int some_delay_ns;
1189 int some_delay_3_half_cycles;
1190
1191 unsigned channel, i;
1192 int high_multiplier;
1193 int lane_3_delay;
1194 int cas_latency_derived;
1195
1196 high_multiplier = 0;
1197 some_delay_ns = 200;
1198 some_delay_3_half_cycles = 4;
1199 cas_latency_shift = info->silicon_revision == 0
1200 || info->silicon_revision == 1 ? 1 : 0;
1201 if (info->revision < 8) {
1202 some_delay_ns = 600;
1203 cas_latency_shift = 0;
1204 }
1205 {
1206 int speed_bit;
1207 speed_bit =
1208 ((info->clock_speed_index > 1
1209 || (info->silicon_revision != 2
1210 && info->silicon_revision != 3))) ^ (info->revision >=
1211 0x10);
1212 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1213 3, 1);
1214 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1215 3, 1);
1216 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1217 && (info->silicon_revision == 2
1218 || info->silicon_revision == 3))
1219 rmw_1d0(0x116, 5, 2, 4, 1);
1220 }
Felix Held04be2dd2018-07-29 04:53:22 +02001221 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1222 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001223
Felix Held04be2dd2018-07-29 04:53:22 +02001224 MCHBAR8(0x124) = info->board_lane_delay[4] +
1225 ((frequency_01(info) + 999) / 1000);
1226 MCHBAR16(0x125) = 0x1360;
1227 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001228 if (info->fsb_frequency < frequency_11(info) / 2) {
1229 unsigned some_delay_2_half_cycles;
1230 high_multiplier = 1;
1231 some_delay_2_half_cycles = ps_to_halfcycles(info,
1232 ((3 *
1233 fsbcycle_ps(info))
1234 >> 1) +
1235 (halfcycle_ps(info)
1236 *
1237 reg178_min[info->
1238 clock_speed_index]
1239 >> 6)
1240 +
1241 4 *
1242 halfcycle_ps(info)
1243 + 2230);
1244 some_delay_3_half_cycles =
1245 min((some_delay_2_half_cycles +
1246 (frequency_11(info) * 2) * (28 -
1247 some_delay_2_half_cycles) /
1248 (frequency_11(info) * 2 -
1249 4 * (info->fsb_frequency))) >> 3, 7);
1250 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001251 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001252 some_delay_3_half_cycles = 3;
1253 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001254 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1255 MCHBAR32(0x224 + (channel << 10)) =
1256 (info->max_slots_used_in_channel - 1) |
1257 ((info->cas_latency - 5 - info->clock_speed_index)
1258 << 21) | ((info->max_slots_used_in_channel +
1259 info->cas_latency - cas_latency_shift - 4) << 16) |
1260 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1261 ((info->cas_latency - info->clock_speed_index +
1262 info->max_slots_used_in_channel - 6) << 8);
1263 MCHBAR32(0x228 + (channel << 10)) =
1264 info->max_slots_used_in_channel;
1265 MCHBAR8(0x239 + (channel << 10)) = 32;
1266 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1267 (some_delay_3_half_cycles << 25) | 0x840000;
1268 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1269 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1270 MCHBAR32(0x24c + (channel << 10)) =
1271 ((!!info->clock_speed_index) << 17) |
1272 (((2 + info->clock_speed_index -
1273 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001274
Felix Held04be2dd2018-07-29 04:53:22 +02001275 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1276 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1277 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001278
1279 write_500(info, channel,
1280 ((!info->populated_ranks[channel][1][1])
1281 | (!info->populated_ranks[channel][1][0] << 1)
1282 | (!info->populated_ranks[channel][0][1] << 2)
1283 | (!info->populated_ranks[channel][0][0] << 3)),
1284 0x4c9, 4, 1);
1285 }
1286
Felix Held22ca8cb2018-07-29 05:09:44 +02001287 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001288 {
1289 u8 freq_divisor = 2;
1290 if (info->fsb_frequency == frequency_11(info))
1291 freq_divisor = 3;
1292 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1293 freq_divisor = 1;
1294 else
1295 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001296 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001297 }
1298
1299 if (info->board_lane_delay[3] <= 10) {
1300 if (info->board_lane_delay[3] <= 8)
1301 lane_3_delay = info->board_lane_delay[3];
1302 else
1303 lane_3_delay = 10;
1304 } else {
1305 lane_3_delay = 12;
1306 }
1307 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1308 if (info->clock_speed_index > 1)
1309 cas_latency_derived++;
1310 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001311 MCHBAR32(0x240 + (channel << 10)) =
1312 ((info->clock_speed_index == 0) * 0x11000) |
1313 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1314 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001315 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1316 0x609, 6, 1);
1317 write_500(info, channel,
1318 info->clock_speed_index + 2 * info->cas_latency - 7,
1319 0x601, 6, 1);
1320
Felix Held04be2dd2018-07-29 04:53:22 +02001321 MCHBAR32(0x250 + (channel << 10)) =
1322 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1323 (info->board_lane_delay[7] << 2) |
1324 (info->board_lane_delay[4] << 16) |
1325 (info->board_lane_delay[1] << 25) |
1326 (info->board_lane_delay[1] << 29) | 1;
1327 MCHBAR32(0x254 + (channel << 10)) =
1328 (info->board_lane_delay[1] >> 3) |
1329 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1330 0x80 | (info->board_lane_delay[6] << 1) |
1331 (info->board_lane_delay[2] << 28) |
1332 (cas_latency_derived << 16) | 0x4700000;
1333 MCHBAR32(0x258 + (channel << 10)) =
1334 ((info->board_lane_delay[5] + info->clock_speed_index +
1335 9) << 12) | ((info->clock_speed_index -
1336 info->cas_latency + 12) << 8) |
1337 (info->board_lane_delay[2] << 17) |
1338 (info->board_lane_delay[4] << 24) | 0x47;
1339 MCHBAR32(0x25c + (channel << 10)) =
1340 (info->board_lane_delay[1] << 1) |
1341 (info->board_lane_delay[0] << 8) | 0x1da50000;
1342 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1343 MCHBAR8(0x5f8 + (channel << 10)) =
1344 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001345 }
1346
1347 program_modules_memory_map(info, 1);
1348
Felix Held04be2dd2018-07-29 04:53:22 +02001349 MCHBAR16(0x610) = (min(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
1350 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1351 MCHBAR16_OR(0x612, 0x100);
1352 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001353 for (i = 0; i < 8; i++) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001354 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0x80 + 4 * i,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001355 (info->total_memory_mb - 64) | !i | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001356 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0xc0 + 4 * i, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001357 }
1358}
1359
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001360#define DEFAULT_PCI_MMIO_SIZE 2048
1361#define HOST_BRIDGE PCI_DEVFN(0, 0)
1362
1363static unsigned int get_mmio_size(void)
1364{
1365 const struct device *dev;
1366 const struct northbridge_intel_nehalem_config *cfg = NULL;
1367
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001368 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001369 if (dev)
1370 cfg = dev->chip_info;
1371
1372 /* If this is zero, it just means devicetree.cb didn't set it */
1373 if (!cfg || cfg->pci_mmio_size == 0)
1374 return DEFAULT_PCI_MMIO_SIZE;
1375 else
1376 return cfg->pci_mmio_size;
1377}
1378
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001379#define BETTER_MEMORY_MAP 0
1380
1381static void program_total_memory_map(struct raminfo *info)
1382{
1383 unsigned int TOM, TOLUD, TOUUD;
1384 unsigned int quickpath_reserved;
1385 unsigned int REMAPbase;
1386 unsigned int uma_base_igd;
1387 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001388 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001389 int memory_remap;
1390 unsigned int memory_map[8];
1391 int i;
1392 unsigned int current_limit;
1393 unsigned int tseg_base;
1394 int uma_size_igd = 0, uma_size_gtt = 0;
1395
1396 memset(memory_map, 0, sizeof(memory_map));
1397
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001398 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001399 u16 t = pci_read_config16(NORTHBRIDGE, D0F0_GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001400 gav(t);
1401 const int uma_sizes_gtt[16] =
1402 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1403 /* Igd memory */
1404 const int uma_sizes_igd[16] = {
1405 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1406 256, 512
1407 };
1408
1409 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1410 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1411 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001412
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001413 mmio_size = get_mmio_size();
1414
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001415 TOM = info->total_memory_mb;
1416 if (TOM == 4096)
1417 TOM = 4032;
1418 TOUUD = ALIGN_DOWN(TOM - info->memory_reserved_for_heci_mb, 64);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001419 TOLUD = ALIGN_DOWN(min(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
Elyes HAOUASa342f392018-10-17 10:56:26 +02001420 , TOUUD), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001421 memory_remap = 0;
1422 if (TOUUD - TOLUD > 64) {
1423 memory_remap = 1;
1424 REMAPbase = max(4096, TOUUD);
1425 TOUUD = TOUUD - TOLUD + 4096;
1426 }
1427 if (TOUUD > 4096)
1428 memory_map[2] = TOUUD | 1;
1429 quickpath_reserved = 0;
1430
1431 {
1432 u32 t;
1433
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001434 gav(t = pci_read_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 0x68));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001435 if (t & 0x800)
1436 quickpath_reserved =
1437 (1 << find_lowest_bit_set32(t >> 20));
1438 }
1439 if (memory_remap)
1440 TOUUD -= quickpath_reserved;
1441
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001442 uma_base_igd = TOLUD - uma_size_igd;
1443 uma_base_gtt = uma_base_igd - uma_size_gtt;
1444 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1445 if (!memory_remap)
1446 tseg_base -= quickpath_reserved;
1447 tseg_base = ALIGN_DOWN(tseg_base, 8);
1448
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001449 pci_write_config16(NORTHBRIDGE, D0F0_TOLUD, TOLUD << 4);
1450 pci_write_config16(NORTHBRIDGE, D0F0_TOM, TOM >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001451 if (memory_remap) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001452 pci_write_config16(NORTHBRIDGE, D0F0_REMAPBASE, REMAPbase >> 6);
1453 pci_write_config16(NORTHBRIDGE, D0F0_REMAPLIMIT, (TOUUD - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001454 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001455 pci_write_config16(NORTHBRIDGE, D0F0_TOUUD, TOUUD);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001456
1457 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001458 pci_write_config32(NORTHBRIDGE, D0F0_IGD_BASE, uma_base_igd << 20);
1459 pci_write_config32(NORTHBRIDGE, D0F0_GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001460 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001461 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001462
1463 current_limit = 0;
1464 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1465 memory_map[1] = 4096;
1466 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
1467 current_limit = max(current_limit, memory_map[i] & ~1);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001468 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0x80,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001469 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1470 1, 64) | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001471 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0xc0, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001472 }
1473}
1474
1475static void collect_system_info(struct raminfo *info)
1476{
1477 u32 capid0[3];
1478 int i;
1479 unsigned channel;
1480
1481 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001482 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1483 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001484
1485 if (!info->heci_bar)
1486 gav(info->heci_bar =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001487 pci_read_config32(HECIDEV, HECIBAR) & 0xFFFFFFF8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001488 if (!info->memory_reserved_for_heci_mb) {
1489 /* Wait for ME to be ready */
1490 intel_early_me_init();
1491 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1492 }
1493
1494 for (i = 0; i < 3; i++)
1495 gav(capid0[i] =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001496 pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 | (i << 2)));
1497 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001498 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1499
1500 if ((capid0[1] >> 11) & 1)
1501 info->uma_enabled = 0;
1502 else
1503 gav(info->uma_enabled =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001504 pci_read_config8(NORTHBRIDGE, D0F0_DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001505 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1506 info->silicon_revision = 0;
1507
1508 if (capid0[2] & 2) {
1509 info->silicon_revision = 0;
1510 info->max_supported_clock_speed_index = 2;
1511 for (channel = 0; channel < NUM_CHANNELS; channel++)
1512 if (info->populated_ranks[channel][0][0]
1513 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1514 3) {
1515 info->silicon_revision = 2;
1516 info->max_supported_clock_speed_index = 1;
1517 }
1518 } else {
1519 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1520 case 1:
1521 case 2:
1522 info->silicon_revision = 3;
1523 break;
1524 case 3:
1525 info->silicon_revision = 0;
1526 break;
1527 case 0:
1528 info->silicon_revision = 2;
1529 break;
1530 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001531 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001532 case 0x40:
1533 info->silicon_revision = 0;
1534 break;
1535 case 0x48:
1536 info->silicon_revision = 1;
1537 break;
1538 }
1539 }
1540}
1541
1542static void write_training_data(struct raminfo *info)
1543{
1544 int tm, channel, slot, rank, lane;
1545 if (info->revision < 8)
1546 return;
1547
1548 for (tm = 0; tm < 4; tm++)
1549 for (channel = 0; channel < NUM_CHANNELS; channel++)
1550 for (slot = 0; slot < NUM_SLOTS; slot++)
1551 for (rank = 0; rank < NUM_RANKS; rank++)
1552 for (lane = 0; lane < 9; lane++)
1553 write_500(info, channel,
1554 info->
1555 cached_training->
1556 lane_timings[tm]
1557 [channel][slot][rank]
1558 [lane],
1559 get_timing_register_addr
1560 (lane, tm, slot,
1561 rank), 9, 0);
1562 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1563 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1564}
1565
1566static void dump_timings(struct raminfo *info)
1567{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001568 int channel, slot, rank, lane, i;
1569 printk(BIOS_DEBUG, "Timings:\n");
1570 FOR_POPULATED_RANKS {
1571 printk(BIOS_DEBUG, "channel %d, slot %d, rank %d\n", channel,
1572 slot, rank);
1573 for (lane = 0; lane < 9; lane++) {
1574 printk(BIOS_DEBUG, "lane %d: ", lane);
1575 for (i = 0; i < 4; i++) {
1576 printk(BIOS_DEBUG, "%x (%x) ",
1577 read_500(info, channel,
1578 get_timing_register_addr
1579 (lane, i, slot, rank),
1580 9),
1581 info->training.
1582 lane_timings[i][channel][slot][rank]
1583 [lane]);
1584 }
1585 printk(BIOS_DEBUG, "\n");
1586 }
1587 }
1588 printk(BIOS_DEBUG, "[178] = %x (%x)\n", read_1d0(0x178, 7),
1589 info->training.reg_178);
1590 printk(BIOS_DEBUG, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
1591 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001592}
1593
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001594/* Read timings and other registers that need to be restored verbatim and
1595 put them to CBMEM.
1596 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001597static void save_timings(struct raminfo *info)
1598{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001599 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001600 int channel, slot, rank, lane, i;
1601
1602 train = info->training;
1603 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1604 for (i = 0; i < 4; i++)
1605 train.lane_timings[i][channel][slot][rank][lane] =
1606 read_500(info, channel,
1607 get_timing_register_addr(lane, i, slot,
1608 rank), 9);
1609 train.reg_178 = read_1d0(0x178, 7);
1610 train.reg_10b = read_1d0(0x10b, 6);
1611
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001612 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1613 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001614 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001615 train.reg274265[channel][0] = reg32 >> 16;
1616 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001617 train.reg274265[channel][2] =
1618 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001619 }
Felix Held04be2dd2018-07-29 04:53:22 +02001620 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1621 train.reg_6dc = MCHBAR32(0x6dc);
1622 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001623
1624 printk (BIOS_SPEW, "[6dc] = %x\n", train.reg_6dc);
1625 printk (BIOS_SPEW, "[6e8] = %x\n", train.reg_6e8);
1626
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001627 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001628 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1629 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001630}
1631
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001632static const struct ram_training *get_cached_training(void)
1633{
Arthur Heymansdc71e252018-01-29 10:14:48 +01001634 struct region_device rdev;
1635 if (mrc_cache_get_current(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1636 &rdev))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001637 return 0;
Arthur Heymansdc71e252018-01-29 10:14:48 +01001638 return (void *)rdev_mmap_full(&rdev);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001639}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001640
1641/* FIXME: add timeout. */
1642static void wait_heci_ready(void)
1643{
Felix Held04be2dd2018-07-29 04:53:22 +02001644 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1645 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001646 write32((DEFAULT_HECIBAR + 0x4),
1647 (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001648}
1649
1650/* FIXME: add timeout. */
1651static void wait_heci_cb_avail(int len)
1652{
1653 union {
1654 struct mei_csr csr;
1655 u32 raw;
1656 } csr;
1657
Felix Held22ca8cb2018-07-29 05:09:44 +02001658 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1659 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001660
1661 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001662 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001663 while (len >
1664 csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
Felix Held22ca8cb2018-07-29 05:09:44 +02001665 csr.csr.buffer_read_ptr))
1666 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001667}
1668
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001669static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001670{
1671 int len = (head->length + 3) / 4;
1672 int i;
1673
1674 wait_heci_cb_avail(len + 1);
1675
1676 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001677 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001678 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001679 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001680
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001681 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1682 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001683}
1684
1685static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001686send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001687{
1688 struct mei_header head;
1689 int maxlen;
1690
1691 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001692 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001693
1694 while (len) {
1695 int cur = len;
1696 if (cur > maxlen) {
1697 cur = maxlen;
1698 head.is_complete = 0;
1699 } else
1700 head.is_complete = 1;
1701 head.length = cur;
1702 head.reserved = 0;
1703 head.client_address = clientaddress;
1704 head.host_address = hostaddress;
1705 send_heci_packet(&head, (u32 *) msg);
1706 len -= cur;
1707 msg += cur;
1708 }
1709}
1710
1711/* FIXME: Add timeout. */
1712static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001713recv_heci_packet(struct raminfo *info, struct mei_header *head, u32 *packet,
1714 u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001715{
1716 union {
1717 struct mei_csr csr;
1718 u32 raw;
1719 } csr;
1720 int i = 0;
1721
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001722 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001723 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001724 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001725 }
Felix Held04be2dd2018-07-29 04:53:22 +02001726 while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr)
1727 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001728 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001729 if (!head->length) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001730 write32(DEFAULT_HECIBAR + 0x4,
1731 read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001732 *packet_size = 0;
1733 return 0;
1734 }
1735 if (head->length + 4 > 4 * csr.csr.buffer_depth
1736 || head->length > *packet_size) {
1737 *packet_size = 0;
1738 return -1;
1739 }
1740
1741 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001742 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Felix Held22ca8cb2018-07-29 05:09:44 +02001743 while (((head->length + 3) >> 2) >
1744 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr))
1745 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001746
1747 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001748 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001749 *packet_size = head->length;
1750 if (!csr.csr.ready)
1751 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001752 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001753 return 0;
1754}
1755
1756/* FIXME: Add timeout. */
1757static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001758recv_heci_message(struct raminfo *info, u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001759{
1760 struct mei_header head;
1761 int current_position;
1762
1763 current_position = 0;
1764 while (1) {
1765 u32 current_size;
1766 current_size = *message_size - current_position;
1767 if (recv_heci_packet
1768 (info, &head, message + (current_position >> 2),
1769 &current_size) == -1)
1770 break;
1771 if (!current_size)
1772 break;
1773 current_position += current_size;
1774 if (head.is_complete) {
1775 *message_size = current_position;
1776 return 0;
1777 }
1778
1779 if (current_position >= *message_size)
1780 break;
1781 }
1782 *message_size = 0;
1783 return -1;
1784}
1785
1786static void send_heci_uma_message(struct raminfo *info)
1787{
1788 struct uma_reply {
1789 u8 group_id;
1790 u8 command;
1791 u8 reserved;
1792 u8 result;
1793 u8 field2;
1794 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001795 } __packed reply;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001796 struct uma_message {
1797 u8 group_id;
1798 u8 cmd;
1799 u8 reserved;
1800 u8 result;
1801 u32 c2;
1802 u64 heci_uma_addr;
1803 u32 memory_reserved_for_heci_mb;
1804 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001805 } __packed msg = {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001806 0, MKHI_SET_UMA, 0, 0,
1807 0x82,
1808 info->heci_uma_addr, info->memory_reserved_for_heci_mb, 0};
1809 u32 reply_size;
1810
1811 send_heci_message((u8 *) & msg, sizeof(msg), 0, 7);
1812
1813 reply_size = sizeof(reply);
1814 if (recv_heci_message(info, (u32 *) & reply, &reply_size) == -1)
1815 return;
1816
1817 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1818 die("HECI init failed\n");
1819}
1820
1821static void setup_heci_uma(struct raminfo *info)
1822{
1823 u32 reg44;
1824
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001825 reg44 = pci_read_config32(HECIDEV, 0x44); // = 0x80010020
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001826 info->memory_reserved_for_heci_mb = 0;
1827 info->heci_uma_addr = 0;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001828 if (!((reg44 & 0x10000) && !(pci_read_config32(HECIDEV, 0x40) & 0x20)))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001829 return;
1830
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001831 info->heci_bar = pci_read_config32(HECIDEV, 0x10) & 0xFFFFFFF0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001832 info->memory_reserved_for_heci_mb = reg44 & 0x3f;
1833 info->heci_uma_addr =
1834 ((u64)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001835 ((((u64) pci_read_config16(NORTHBRIDGE, D0F0_TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001836 info->memory_reserved_for_heci_mb)) << 20;
1837
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001838 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001839 if (info->memory_reserved_for_heci_mb) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001840 write32(DEFAULT_DMIBAR + 0x14,
1841 read32(DEFAULT_DMIBAR + 0x14) & ~0x80);
1842 write32(DEFAULT_RCBA + 0x14,
1843 read32(DEFAULT_RCBA + 0x14) & ~0x80);
1844 write32(DEFAULT_DMIBAR + 0x20,
1845 read32(DEFAULT_DMIBAR + 0x20) & ~0x80);
1846 write32(DEFAULT_RCBA + 0x20,
1847 read32(DEFAULT_RCBA + 0x20) & ~0x80);
1848 write32(DEFAULT_DMIBAR + 0x2c,
1849 read32(DEFAULT_DMIBAR + 0x2c) & ~0x80);
1850 write32(DEFAULT_RCBA + 0x30,
1851 read32(DEFAULT_RCBA + 0x30) & ~0x80);
1852 write32(DEFAULT_DMIBAR + 0x38,
1853 read32(DEFAULT_DMIBAR + 0x38) & ~0x80);
1854 write32(DEFAULT_RCBA + 0x40,
1855 read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001856
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001857 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
1858 write32(DEFAULT_DMIBAR + 0x38, 0x87000080); // OK
Felix Held04be2dd2018-07-29 04:53:22 +02001859 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
1860 read16(DEFAULT_DMIBAR + 0x3e) & 2)
1861 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001862 }
1863
Felix Held04be2dd2018-07-29 04:53:22 +02001864 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001865
1866 send_heci_uma_message(info);
1867
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001868 pci_write_config32(HECIDEV, 0x10, 0x0);
1869 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001870
1871}
1872
1873static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1874{
1875 int ranks_in_channel;
1876 ranks_in_channel = info->populated_ranks[channel][0][0]
1877 + info->populated_ranks[channel][0][1]
1878 + info->populated_ranks[channel][1][0]
1879 + info->populated_ranks[channel][1][1];
1880
1881 /* empty channel */
1882 if (ranks_in_channel == 0)
1883 return 1;
1884
1885 if (ranks_in_channel != ranks)
1886 return 0;
1887 /* single slot */
1888 if (info->populated_ranks[channel][0][0] !=
1889 info->populated_ranks[channel][1][0])
1890 return 1;
1891 if (info->populated_ranks[channel][0][1] !=
1892 info->populated_ranks[channel][1][1])
1893 return 1;
1894 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1895 return 0;
1896 if (info->density[channel][0] != info->density[channel][1])
1897 return 0;
1898 return 1;
1899}
1900
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001901static void read_4090(struct raminfo *info)
1902{
1903 int i, channel, slot, rank, lane;
1904 for (i = 0; i < 2; i++)
1905 for (slot = 0; slot < NUM_SLOTS; slot++)
1906 for (rank = 0; rank < NUM_RANKS; rank++)
1907 for (lane = 0; lane < 9; lane++)
1908 info->training.
1909 lane_timings[0][i][slot][rank][lane]
1910 = 32;
1911
1912 for (i = 1; i < 4; i++)
1913 for (channel = 0; channel < NUM_CHANNELS; channel++)
1914 for (slot = 0; slot < NUM_SLOTS; slot++)
1915 for (rank = 0; rank < NUM_RANKS; rank++)
1916 for (lane = 0; lane < 9; lane++) {
1917 info->training.
1918 lane_timings[i][channel]
1919 [slot][rank][lane] =
1920 read_500(info, channel,
1921 get_timing_register_addr
1922 (lane, i, slot,
1923 rank), 9)
1924 + (i == 1) * 11; // !!!!
1925 }
1926
1927}
1928
1929static u32 get_etalon2(int flip, u32 addr)
1930{
1931 const u16 invmask[] = {
1932 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1933 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1934 };
1935 u32 ret;
1936 u32 comp4 = addr / 480;
1937 addr %= 480;
1938 u32 comp1 = addr & 0xf;
1939 u32 comp2 = (addr >> 4) & 1;
1940 u32 comp3 = addr >> 5;
1941
1942 if (comp4)
1943 ret = 0x1010101 << (comp4 - 1);
1944 else
1945 ret = 0;
1946 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1947 ret = ~ret;
1948
1949 return ret;
1950}
1951
1952static void disable_cache(void)
1953{
1954 msr_t msr = {.lo = 0, .hi = 0 };
1955
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001956 wrmsr(MTRR_PHYS_BASE(3), msr);
1957 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001958}
1959
1960static void enable_cache(unsigned int base, unsigned int size)
1961{
1962 msr_t msr;
1963 msr.lo = base | MTRR_TYPE_WRPROT;
1964 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001965 wrmsr(MTRR_PHYS_BASE(3), msr);
1966 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001967 & 0xffffffff);
1968 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001969 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001970}
1971
1972static void flush_cache(u32 start, u32 size)
1973{
1974 u32 end;
1975 u32 addr;
1976
1977 end = start + (ALIGN_DOWN(size + 4096, 4096));
1978 for (addr = start; addr < end; addr += 64)
1979 clflush(addr);
1980}
1981
1982static void clear_errors(void)
1983{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001984 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001985}
1986
1987static void write_testing(struct raminfo *info, int totalrank, int flip)
1988{
1989 int nwrites = 0;
1990 /* in 8-byte units. */
1991 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001992 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001993
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001994 base = (u8 *)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001995 for (offset = 0; offset < 9 * 480; offset += 2) {
1996 write32(base + offset * 8, get_etalon2(flip, offset));
1997 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
1998 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
1999 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
2000 nwrites += 4;
2001 if (nwrites >= 320) {
2002 clear_errors();
2003 nwrites = 0;
2004 }
2005 }
2006}
2007
2008static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
2009{
2010 u8 failmask = 0;
2011 int i;
2012 int comp1, comp2, comp3;
2013 u32 failxor[2] = { 0, 0 };
2014
2015 enable_cache((total_rank << 28), 1728 * 5 * 4);
2016
2017 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
2018 for (comp1 = 0; comp1 < 4; comp1++)
2019 for (comp2 = 0; comp2 < 60; comp2++) {
2020 u32 re[4];
2021 u32 curroffset =
2022 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
2023 read128((total_rank << 28) | (curroffset << 3),
2024 (u64 *) re);
2025 failxor[0] |=
2026 get_etalon2(flip, curroffset) ^ re[0];
2027 failxor[1] |=
2028 get_etalon2(flip, curroffset) ^ re[1];
2029 failxor[0] |=
2030 get_etalon2(flip, curroffset | 1) ^ re[2];
2031 failxor[1] |=
2032 get_etalon2(flip, curroffset | 1) ^ re[3];
2033 }
2034 for (i = 0; i < 8; i++)
2035 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2036 failmask |= 1 << i;
2037 }
2038 disable_cache();
2039 flush_cache((total_rank << 28), 1728 * 5 * 4);
2040 return failmask;
2041}
2042
2043const u32 seed1[0x18] = {
2044 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2045 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2046 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2047 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2048 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2049 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2050};
2051
2052static u32 get_seed2(int a, int b)
2053{
2054 const u32 seed2[5] = {
2055 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2056 0x5b6db6db,
2057 };
2058 u32 r;
2059 r = seed2[(a + (a >= 10)) / 5];
2060 return b ? ~r : r;
2061}
2062
2063static int make_shift(int comp2, int comp5, int x)
2064{
2065 const u8 seed3[32] = {
2066 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2067 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2068 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2069 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2070 };
2071
2072 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2073}
2074
2075static u32 get_etalon(int flip, u32 addr)
2076{
2077 u32 mask_byte = 0;
2078 int comp1 = (addr >> 1) & 1;
2079 int comp2 = (addr >> 3) & 0x1f;
2080 int comp3 = (addr >> 8) & 0xf;
2081 int comp4 = (addr >> 12) & 0xf;
2082 int comp5 = (addr >> 16) & 0x1f;
2083 u32 mask_bit = ~(0x10001 << comp3);
2084 u32 part1;
2085 u32 part2;
2086 int byte;
2087
2088 part2 =
2089 ((seed1[comp5] >>
2090 make_shift(comp2, comp5,
2091 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2092 part1 =
2093 ((seed1[comp5] >>
2094 make_shift(comp2, comp5,
2095 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2096
2097 for (byte = 0; byte < 4; byte++)
2098 if ((get_seed2(comp5, comp4) >>
2099 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2100 mask_byte |= 0xff << (8 * byte);
2101
2102 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2103 (comp3 + 16));
2104}
2105
2106static void
2107write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2108 char flip)
2109{
2110 int i;
2111 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002112 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2113 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002114}
2115
2116static u8
2117check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2118 char flip)
2119{
2120 u8 failmask = 0;
2121 u32 failxor[2];
2122 int i;
2123 int comp1, comp2, comp3;
2124
2125 failxor[0] = 0;
2126 failxor[1] = 0;
2127
2128 enable_cache(totalrank << 28, 134217728);
2129 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2130 for (comp1 = 0; comp1 < 16; comp1++)
2131 for (comp2 = 0; comp2 < 64; comp2++) {
2132 u32 addr =
2133 (totalrank << 28) | (region << 25) | (block
2134 << 16)
2135 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2136 2);
2137 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002138 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002139 }
2140 for (i = 0; i < 8; i++)
2141 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2142 failmask |= 1 << i;
2143 }
2144 disable_cache();
2145 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2146 return failmask;
2147}
2148
2149static int check_bounded(unsigned short *vals, u16 bound)
2150{
2151 int i;
2152
2153 for (i = 0; i < 8; i++)
2154 if (vals[i] < bound)
2155 return 0;
2156 return 1;
2157}
2158
2159enum state {
2160 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2161};
2162
2163static int validate_state(enum state *in)
2164{
2165 int i;
2166 for (i = 0; i < 8; i++)
2167 if (in[i] != COMPLETE)
2168 return 0;
2169 return 1;
2170}
2171
2172static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002173do_fsm(enum state *state, u16 *counter,
2174 u8 fail_mask, int margin, int uplimit,
2175 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002176{
2177 int lane;
2178
2179 for (lane = 0; lane < 8; lane++) {
2180 int is_fail = (fail_mask >> lane) & 1;
2181 switch (state[lane]) {
2182 case BEFORE_USABLE:
2183 if (!is_fail) {
2184 counter[lane] = 1;
2185 state[lane] = AT_USABLE;
2186 break;
2187 }
2188 counter[lane] = 0;
2189 state[lane] = BEFORE_USABLE;
2190 break;
2191 case AT_USABLE:
2192 if (!is_fail) {
2193 ++counter[lane];
2194 if (counter[lane] >= margin) {
2195 state[lane] = AT_MARGIN;
2196 res_low[lane] = val - margin + 1;
2197 break;
2198 }
2199 state[lane] = 1;
2200 break;
2201 }
2202 counter[lane] = 0;
2203 state[lane] = BEFORE_USABLE;
2204 break;
2205 case AT_MARGIN:
2206 if (is_fail) {
2207 state[lane] = COMPLETE;
2208 res_high[lane] = val - 1;
2209 } else {
2210 counter[lane]++;
2211 state[lane] = AT_MARGIN;
2212 if (val == uplimit) {
2213 state[lane] = COMPLETE;
2214 res_high[lane] = uplimit;
2215 }
2216 }
2217 break;
2218 case COMPLETE:
2219 break;
2220 }
2221 }
2222}
2223
2224static void
2225train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2226 u8 total_rank, u8 reg_178, int first_run, int niter,
2227 timing_bounds_t * timings)
2228{
2229 int lane;
2230 enum state state[8];
2231 u16 count[8];
2232 u8 lower_usable[8];
2233 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002234 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002235 u8 secondary_total_rank;
2236 u8 reg1b3;
2237
2238 if (info->populated_ranks_mask[1]) {
2239 if (channel == 1)
2240 secondary_total_rank =
2241 info->populated_ranks[1][0][0] +
2242 info->populated_ranks[1][0][1]
2243 + info->populated_ranks[1][1][0] +
2244 info->populated_ranks[1][1][1];
2245 else
2246 secondary_total_rank = 0;
2247 } else
2248 secondary_total_rank = total_rank;
2249
2250 {
2251 int i;
2252 for (i = 0; i < 8; i++)
2253 state[i] = BEFORE_USABLE;
2254 }
2255
2256 if (!first_run) {
2257 int is_all_ok = 1;
2258 for (lane = 0; lane < 8; lane++)
2259 if (timings[reg_178][channel][slot][rank][lane].
2260 smallest ==
2261 timings[reg_178][channel][slot][rank][lane].
2262 largest) {
2263 timings[reg_178][channel][slot][rank][lane].
2264 smallest = 0;
2265 timings[reg_178][channel][slot][rank][lane].
2266 largest = 0;
2267 is_all_ok = 0;
2268 }
2269 if (is_all_ok) {
2270 int i;
2271 for (i = 0; i < 8; i++)
2272 state[i] = COMPLETE;
2273 }
2274 }
2275
2276 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2277 u8 failmask = 0;
2278 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2279 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2280 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002281 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002282 do_fsm(state, count, failmask, 5, 47, lower_usable,
2283 upper_usable, reg1b3);
2284 }
2285
2286 if (reg1b3) {
2287 write_1d0(0, 0x1b3, 6, 1);
2288 write_1d0(0, 0x1a3, 6, 1);
2289 for (lane = 0; lane < 8; lane++) {
2290 if (state[lane] == COMPLETE) {
2291 timings[reg_178][channel][slot][rank][lane].
2292 smallest =
2293 lower_usable[lane] +
2294 (info->training.
2295 lane_timings[0][channel][slot][rank][lane]
2296 & 0x3F) - 32;
2297 timings[reg_178][channel][slot][rank][lane].
2298 largest =
2299 upper_usable[lane] +
2300 (info->training.
2301 lane_timings[0][channel][slot][rank][lane]
2302 & 0x3F) - 32;
2303 }
2304 }
2305 }
2306
2307 if (!first_run) {
2308 for (lane = 0; lane < 8; lane++)
2309 if (state[lane] == COMPLETE) {
2310 write_500(info, channel,
2311 timings[reg_178][channel][slot][rank]
2312 [lane].smallest,
2313 get_timing_register_addr(lane, 0,
2314 slot, rank),
2315 9, 1);
2316 write_500(info, channel,
2317 timings[reg_178][channel][slot][rank]
2318 [lane].smallest +
2319 info->training.
2320 lane_timings[1][channel][slot][rank]
2321 [lane]
2322 -
2323 info->training.
2324 lane_timings[0][channel][slot][rank]
2325 [lane], get_timing_register_addr(lane,
2326 1,
2327 slot,
2328 rank),
2329 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002330 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002331 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002332 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002333
2334 do {
2335 u8 failmask = 0;
2336 int i;
2337 for (i = 0; i < niter; i++) {
2338 if (failmask == 0xFF)
2339 break;
2340 failmask |=
2341 check_testing_type2(info, total_rank, 2, i,
2342 0);
2343 failmask |=
2344 check_testing_type2(info, total_rank, 3, i,
2345 1);
2346 }
Felix Held04be2dd2018-07-29 04:53:22 +02002347 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002348 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002349 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002350 if ((1 << lane) & failmask) {
2351 if (timings[reg_178][channel]
2352 [slot][rank][lane].
2353 largest <=
2354 timings[reg_178][channel]
2355 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002356 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002357 [lane] = -1;
2358 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002359 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002360 [lane] = 0;
2361 timings[reg_178]
2362 [channel][slot]
2363 [rank][lane].
2364 smallest++;
2365 write_500(info, channel,
2366 timings
2367 [reg_178]
2368 [channel]
2369 [slot][rank]
2370 [lane].
2371 smallest,
2372 get_timing_register_addr
2373 (lane, 0,
2374 slot, rank),
2375 9, 1);
2376 write_500(info, channel,
2377 timings
2378 [reg_178]
2379 [channel]
2380 [slot][rank]
2381 [lane].
2382 smallest +
2383 info->
2384 training.
2385 lane_timings
2386 [1][channel]
2387 [slot][rank]
2388 [lane]
2389 -
2390 info->
2391 training.
2392 lane_timings
2393 [0][channel]
2394 [slot][rank]
2395 [lane],
2396 get_timing_register_addr
2397 (lane, 1,
2398 slot, rank),
2399 9, 1);
2400 }
2401 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002402 num_successfully_checked[lane]
2403 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002404 }
2405 }
Felix Held04be2dd2018-07-29 04:53:22 +02002406 while (!check_bounded(num_successfully_checked, 2))
2407 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002408
2409 for (lane = 0; lane < 8; lane++)
2410 if (state[lane] == COMPLETE) {
2411 write_500(info, channel,
2412 timings[reg_178][channel][slot][rank]
2413 [lane].largest,
2414 get_timing_register_addr(lane, 0,
2415 slot, rank),
2416 9, 1);
2417 write_500(info, channel,
2418 timings[reg_178][channel][slot][rank]
2419 [lane].largest +
2420 info->training.
2421 lane_timings[1][channel][slot][rank]
2422 [lane]
2423 -
2424 info->training.
2425 lane_timings[0][channel][slot][rank]
2426 [lane], get_timing_register_addr(lane,
2427 1,
2428 slot,
2429 rank),
2430 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002431 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002432 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002433 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002434
2435 do {
2436 int failmask = 0;
2437 int i;
2438 for (i = 0; i < niter; i++) {
2439 if (failmask == 0xFF)
2440 break;
2441 failmask |=
2442 check_testing_type2(info, total_rank, 2, i,
2443 0);
2444 failmask |=
2445 check_testing_type2(info, total_rank, 3, i,
2446 1);
2447 }
2448
Felix Held04be2dd2018-07-29 04:53:22 +02002449 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002450 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002451 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002452 if ((1 << lane) & failmask) {
2453 if (timings[reg_178][channel]
2454 [slot][rank][lane].
2455 largest <=
2456 timings[reg_178][channel]
2457 [slot][rank][lane].
2458 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002459 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002460 [lane] = -1;
2461 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002462 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002463 [lane] = 0;
2464 timings[reg_178]
2465 [channel][slot]
2466 [rank][lane].
2467 largest--;
2468 write_500(info, channel,
2469 timings
2470 [reg_178]
2471 [channel]
2472 [slot][rank]
2473 [lane].
2474 largest,
2475 get_timing_register_addr
2476 (lane, 0,
2477 slot, rank),
2478 9, 1);
2479 write_500(info, channel,
2480 timings
2481 [reg_178]
2482 [channel]
2483 [slot][rank]
2484 [lane].
2485 largest +
2486 info->
2487 training.
2488 lane_timings
2489 [1][channel]
2490 [slot][rank]
2491 [lane]
2492 -
2493 info->
2494 training.
2495 lane_timings
2496 [0][channel]
2497 [slot][rank]
2498 [lane],
2499 get_timing_register_addr
2500 (lane, 1,
2501 slot, rank),
2502 9, 1);
2503 }
2504 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002505 num_successfully_checked[lane]
2506 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002507 }
2508 }
2509 }
Felix Held04be2dd2018-07-29 04:53:22 +02002510 while (!check_bounded(num_successfully_checked, 3))
2511 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002512
2513 for (lane = 0; lane < 8; lane++) {
2514 write_500(info, channel,
2515 info->training.
2516 lane_timings[0][channel][slot][rank][lane],
2517 get_timing_register_addr(lane, 0, slot, rank),
2518 9, 1);
2519 write_500(info, channel,
2520 info->training.
2521 lane_timings[1][channel][slot][rank][lane],
2522 get_timing_register_addr(lane, 1, slot, rank),
2523 9, 1);
2524 if (timings[reg_178][channel][slot][rank][lane].
2525 largest <=
2526 timings[reg_178][channel][slot][rank][lane].
2527 smallest) {
2528 timings[reg_178][channel][slot][rank][lane].
2529 largest = 0;
2530 timings[reg_178][channel][slot][rank][lane].
2531 smallest = 0;
2532 }
2533 }
2534 }
2535}
2536
2537static void set_10b(struct raminfo *info, u8 val)
2538{
2539 int channel;
2540 int slot, rank;
2541 int lane;
2542
2543 if (read_1d0(0x10b, 6) == val)
2544 return;
2545
2546 write_1d0(val, 0x10b, 6, 1);
2547
2548 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2549 u16 reg_500;
2550 reg_500 = read_500(info, channel,
2551 get_timing_register_addr(lane, 0, slot,
2552 rank), 9);
2553 if (val == 1) {
2554 if (lut16[info->clock_speed_index] <= reg_500)
2555 reg_500 -= lut16[info->clock_speed_index];
2556 else
2557 reg_500 = 0;
2558 } else {
2559 reg_500 += lut16[info->clock_speed_index];
2560 }
2561 write_500(info, channel, reg_500,
2562 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2563 }
2564}
2565
2566static void set_ecc(int onoff)
2567{
2568 int channel;
2569 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2570 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002571 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002572 if (onoff)
2573 t |= 1;
2574 else
2575 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002576 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002577 }
2578}
2579
2580static void set_178(u8 val)
2581{
2582 if (val >= 31)
2583 val = val - 31;
2584 else
2585 val = 63 - val;
2586
2587 write_1d0(2 * val, 0x178, 7, 1);
2588}
2589
2590static void
2591write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2592 int type)
2593{
2594 int lane;
2595
2596 for (lane = 0; lane < 8; lane++)
2597 write_500(info, channel,
2598 info->training.
2599 lane_timings[type][channel][slot][rank][lane],
2600 get_timing_register_addr(lane, type, slot, rank), 9,
2601 0);
2602}
2603
2604static void
2605try_timing_offsets(struct raminfo *info, int channel,
2606 int slot, int rank, int totalrank)
2607{
2608 u16 count[8];
2609 enum state state[8];
2610 u8 lower_usable[8], upper_usable[8];
2611 int lane;
2612 int i;
2613 int flip = 1;
2614 int timing_offset;
2615
2616 for (i = 0; i < 8; i++)
2617 state[i] = BEFORE_USABLE;
2618
2619 memset(count, 0, sizeof(count));
2620
2621 for (lane = 0; lane < 8; lane++)
2622 write_500(info, channel,
2623 info->training.
2624 lane_timings[2][channel][slot][rank][lane] + 32,
2625 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2626
2627 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2628 timing_offset++) {
2629 u8 failmask;
2630 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2631 failmask = 0;
2632 for (i = 0; i < 2 && failmask != 0xff; i++) {
2633 flip = !flip;
2634 write_testing(info, totalrank, flip);
2635 failmask |= check_testing(info, totalrank, flip);
2636 }
2637 do_fsm(state, count, failmask, 10, 63, lower_usable,
2638 upper_usable, timing_offset);
2639 }
2640 write_1d0(0, 0x1bb, 6, 1);
2641 dump_timings(info);
2642 if (!validate_state(state))
2643 die("Couldn't discover DRAM timings (1)\n");
2644
2645 for (lane = 0; lane < 8; lane++) {
2646 u8 bias = 0;
2647
2648 if (info->silicon_revision) {
2649 int usable_length;
2650
2651 usable_length = upper_usable[lane] - lower_usable[lane];
2652 if (usable_length >= 20) {
2653 bias = usable_length / 2 - 10;
2654 if (bias >= 2)
2655 bias = 2;
2656 }
2657 }
2658 write_500(info, channel,
2659 info->training.
2660 lane_timings[2][channel][slot][rank][lane] +
2661 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2662 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2663 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2664 info->training.lane_timings[2][channel][slot][rank][lane] +
2665 lower_usable[lane];
2666 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2667 info->training.lane_timings[2][channel][slot][rank][lane] +
2668 upper_usable[lane];
2669 info->training.timing2_offset[channel][slot][rank][lane] =
2670 info->training.lane_timings[2][channel][slot][rank][lane];
2671 }
2672}
2673
2674static u8
2675choose_training(struct raminfo *info, int channel, int slot, int rank,
2676 int lane, timing_bounds_t * timings, u8 center_178)
2677{
2678 u16 central_weight;
2679 u16 side_weight;
2680 unsigned int sum = 0, count = 0;
2681 u8 span;
2682 u8 lower_margin, upper_margin;
2683 u8 reg_178;
2684 u8 result;
2685
2686 span = 12;
2687 central_weight = 20;
2688 side_weight = 20;
2689 if (info->silicon_revision == 1 && channel == 1) {
2690 central_weight = 5;
2691 side_weight = 20;
2692 if ((info->
2693 populated_ranks_mask[1] ^ (info->
2694 populated_ranks_mask[1] >> 2)) &
2695 1)
2696 span = 18;
2697 }
2698 if ((info->populated_ranks_mask[0] & 5) == 5) {
2699 central_weight = 20;
2700 side_weight = 20;
2701 }
2702 if (info->clock_speed_index >= 2
2703 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2704 if (info->silicon_revision == 1) {
2705 switch (channel) {
2706 case 0:
2707 if (lane == 1) {
2708 central_weight = 10;
2709 side_weight = 20;
2710 }
2711 break;
2712 case 1:
2713 if (lane == 6) {
2714 side_weight = 5;
2715 central_weight = 20;
2716 }
2717 break;
2718 }
2719 }
2720 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2721 side_weight = 5;
2722 central_weight = 20;
2723 }
2724 }
2725 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2726 reg_178 += span) {
2727 u8 smallest;
2728 u8 largest;
2729 largest = timings[reg_178][channel][slot][rank][lane].largest;
2730 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2731 if (largest - smallest + 1 >= 5) {
2732 unsigned int weight;
2733 if (reg_178 == center_178)
2734 weight = central_weight;
2735 else
2736 weight = side_weight;
2737 sum += weight * (largest + smallest);
2738 count += weight;
2739 }
2740 }
2741 dump_timings(info);
2742 if (count == 0)
2743 die("Couldn't discover DRAM timings (2)\n");
2744 result = sum / (2 * count);
2745 lower_margin =
2746 result - timings[center_178][channel][slot][rank][lane].smallest;
2747 upper_margin =
2748 timings[center_178][channel][slot][rank][lane].largest - result;
2749 if (upper_margin < 10 && lower_margin > 10)
2750 result -= min(lower_margin - 10, 10 - upper_margin);
2751 if (upper_margin > 10 && lower_margin < 10)
2752 result += min(upper_margin - 10, 10 - lower_margin);
2753 return result;
2754}
2755
2756#define STANDARD_MIN_MARGIN 5
2757
2758static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2759{
2760 u16 margin[64];
2761 int lane, rank, slot, channel;
2762 u8 reg178;
2763 int count = 0, sum = 0;
2764
2765 for (reg178 = reg178_min[info->clock_speed_index];
2766 reg178 < reg178_max[info->clock_speed_index];
2767 reg178 += reg178_step[info->clock_speed_index]) {
2768 margin[reg178] = -1;
2769 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2770 int curmargin =
2771 timings[reg178][channel][slot][rank][lane].largest -
2772 timings[reg178][channel][slot][rank][lane].
2773 smallest + 1;
2774 if (curmargin < margin[reg178])
2775 margin[reg178] = curmargin;
2776 }
2777 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2778 u16 weight;
2779 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2780 sum += weight * reg178;
2781 count += weight;
2782 }
2783 }
2784 dump_timings(info);
2785 if (count == 0)
2786 die("Couldn't discover DRAM timings (3)\n");
2787
2788 u8 threshold;
2789
2790 for (threshold = 30; threshold >= 5; threshold--) {
2791 int usable_length = 0;
2792 int smallest_fount = 0;
2793 for (reg178 = reg178_min[info->clock_speed_index];
2794 reg178 < reg178_max[info->clock_speed_index];
2795 reg178 += reg178_step[info->clock_speed_index])
2796 if (margin[reg178] >= threshold) {
2797 usable_length +=
2798 reg178_step[info->clock_speed_index];
2799 info->training.reg178_largest =
2800 reg178 -
2801 2 * reg178_step[info->clock_speed_index];
2802
2803 if (!smallest_fount) {
2804 smallest_fount = 1;
2805 info->training.reg178_smallest =
2806 reg178 +
2807 reg178_step[info->
2808 clock_speed_index];
2809 }
2810 }
2811 if (usable_length >= 0x21)
2812 break;
2813 }
2814
2815 return sum / count;
2816}
2817
2818static int check_cached_sanity(struct raminfo *info)
2819{
2820 int lane;
2821 int slot, rank;
2822 int channel;
2823
2824 if (!info->cached_training)
2825 return 0;
2826
2827 for (channel = 0; channel < NUM_CHANNELS; channel++)
2828 for (slot = 0; slot < NUM_SLOTS; slot++)
2829 for (rank = 0; rank < NUM_RANKS; rank++)
2830 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2831 u16 cached_value, estimation_value;
2832 cached_value =
2833 info->cached_training->
2834 lane_timings[1][channel][slot][rank]
2835 [lane];
2836 if (cached_value >= 0x18
2837 && cached_value <= 0x1E7) {
2838 estimation_value =
2839 info->training.
2840 lane_timings[1][channel]
2841 [slot][rank][lane];
2842 if (estimation_value <
2843 cached_value - 24)
2844 return 0;
2845 if (estimation_value >
2846 cached_value + 24)
2847 return 0;
2848 }
2849 }
2850 return 1;
2851}
2852
2853static int try_cached_training(struct raminfo *info)
2854{
2855 u8 saved_243[2];
2856 u8 tm;
2857
2858 int channel, slot, rank, lane;
2859 int flip = 1;
2860 int i, j;
2861
2862 if (!check_cached_sanity(info))
2863 return 0;
2864
2865 info->training.reg178_center = info->cached_training->reg178_center;
2866 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2867 info->training.reg178_largest = info->cached_training->reg178_largest;
2868 memcpy(&info->training.timing_bounds,
2869 &info->cached_training->timing_bounds,
2870 sizeof(info->training.timing_bounds));
2871 memcpy(&info->training.timing_offset,
2872 &info->cached_training->timing_offset,
2873 sizeof(info->training.timing_offset));
2874
2875 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002876 saved_243[0] = MCHBAR8(0x243);
2877 saved_243[1] = MCHBAR8(0x643);
2878 MCHBAR8(0x243) = saved_243[0] | 2;
2879 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002880 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002881 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002882 if (read_1d0(0x10b, 6) & 1)
2883 set_10b(info, 0);
2884 for (tm = 0; tm < 2; tm++) {
2885 int totalrank;
2886
2887 set_178(tm ? info->cached_training->reg178_largest : info->
2888 cached_training->reg178_smallest);
2889
2890 totalrank = 0;
2891 /* Check timing ranges. With i == 0 we check smallest one and with
2892 i == 1 the largest bound. With j == 0 we check that on the bound
2893 it still works whereas with j == 1 we check that just outside of
2894 bound we fail.
2895 */
2896 FOR_POPULATED_RANKS_BACKWARDS {
2897 for (i = 0; i < 2; i++) {
2898 for (lane = 0; lane < 8; lane++) {
2899 write_500(info, channel,
2900 info->cached_training->
2901 timing2_bounds[channel][slot]
2902 [rank][lane][i],
2903 get_timing_register_addr(lane,
2904 3,
2905 slot,
2906 rank),
2907 9, 1);
2908
2909 if (!i)
2910 write_500(info, channel,
2911 info->
2912 cached_training->
2913 timing2_offset
2914 [channel][slot][rank]
2915 [lane],
2916 get_timing_register_addr
2917 (lane, 2, slot, rank),
2918 9, 1);
2919 write_500(info, channel,
2920 i ? info->cached_training->
2921 timing_bounds[tm][channel]
2922 [slot][rank][lane].
2923 largest : info->
2924 cached_training->
2925 timing_bounds[tm][channel]
2926 [slot][rank][lane].smallest,
2927 get_timing_register_addr(lane,
2928 0,
2929 slot,
2930 rank),
2931 9, 1);
2932 write_500(info, channel,
2933 info->cached_training->
2934 timing_offset[channel][slot]
2935 [rank][lane] +
2936 (i ? info->cached_training->
2937 timing_bounds[tm][channel]
2938 [slot][rank][lane].
2939 largest : info->
2940 cached_training->
2941 timing_bounds[tm][channel]
2942 [slot][rank][lane].
2943 smallest) - 64,
2944 get_timing_register_addr(lane,
2945 1,
2946 slot,
2947 rank),
2948 9, 1);
2949 }
2950 for (j = 0; j < 2; j++) {
2951 u8 failmask;
2952 u8 expected_failmask;
2953 char reg1b3;
2954
2955 reg1b3 = (j == 1) + 4;
2956 reg1b3 =
2957 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2958 write_1d0(reg1b3, 0x1bb, 6, 1);
2959 write_1d0(reg1b3, 0x1b3, 6, 1);
2960 write_1d0(reg1b3, 0x1a3, 6, 1);
2961
2962 flip = !flip;
2963 write_testing(info, totalrank, flip);
2964 failmask =
2965 check_testing(info, totalrank,
2966 flip);
2967 expected_failmask =
2968 j == 0 ? 0x00 : 0xff;
2969 if (failmask != expected_failmask)
2970 goto fail;
2971 }
2972 }
2973 totalrank++;
2974 }
2975 }
2976
2977 set_178(info->cached_training->reg178_center);
2978 if (info->use_ecc)
2979 set_ecc(1);
2980 write_training_data(info);
2981 write_1d0(0, 322, 3, 1);
2982 info->training = *info->cached_training;
2983
2984 write_1d0(0, 0x1bb, 6, 1);
2985 write_1d0(0, 0x1b3, 6, 1);
2986 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002987 MCHBAR8(0x243) = saved_243[0];
2988 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002989
2990 return 1;
2991
2992fail:
2993 FOR_POPULATED_RANKS {
2994 write_500_timings_type(info, channel, slot, rank, 1);
2995 write_500_timings_type(info, channel, slot, rank, 2);
2996 write_500_timings_type(info, channel, slot, rank, 3);
2997 }
2998
2999 write_1d0(0, 0x1bb, 6, 1);
3000 write_1d0(0, 0x1b3, 6, 1);
3001 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003002 MCHBAR8(0x243) = saved_243[0];
3003 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003004
3005 return 0;
3006}
3007
3008static void do_ram_training(struct raminfo *info)
3009{
3010 u8 saved_243[2];
3011 int totalrank = 0;
3012 u8 reg_178;
3013 int niter;
3014
Matthias Gazzaridfa51252018-05-19 00:44:20 +02003015 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003016 int lane, rank, slot, channel;
3017 u8 reg178_center;
3018
3019 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003020 saved_243[0] = MCHBAR8(0x243);
3021 saved_243[1] = MCHBAR8(0x643);
3022 MCHBAR8(0x243) = saved_243[0] | 2;
3023 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003024 switch (info->clock_speed_index) {
3025 case 0:
3026 niter = 5;
3027 break;
3028 case 1:
3029 niter = 10;
3030 break;
3031 default:
3032 niter = 19;
3033 break;
3034 }
3035 set_ecc(0);
3036
3037 FOR_POPULATED_RANKS_BACKWARDS {
3038 int i;
3039
3040 write_500_timings_type(info, channel, slot, rank, 0);
3041
3042 write_testing(info, totalrank, 0);
3043 for (i = 0; i < niter; i++) {
3044 write_testing_type2(info, totalrank, 2, i, 0);
3045 write_testing_type2(info, totalrank, 3, i, 1);
3046 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003047 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003048 totalrank++;
3049 }
3050
3051 if (reg178_min[info->clock_speed_index] <
3052 reg178_max[info->clock_speed_index])
3053 memset(timings[reg178_min[info->clock_speed_index]], 0,
3054 sizeof(timings[0]) *
3055 (reg178_max[info->clock_speed_index] -
3056 reg178_min[info->clock_speed_index]));
3057 for (reg_178 = reg178_min[info->clock_speed_index];
3058 reg_178 < reg178_max[info->clock_speed_index];
3059 reg_178 += reg178_step[info->clock_speed_index]) {
3060 totalrank = 0;
3061 set_178(reg_178);
3062 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3063 for (slot = 0; slot < NUM_SLOTS; slot++)
3064 for (rank = 0; rank < NUM_RANKS; rank++) {
3065 memset(&timings[reg_178][channel][slot]
3066 [rank][0].smallest, 0, 16);
3067 if (info->
3068 populated_ranks[channel][slot]
3069 [rank]) {
3070 train_ram_at_178(info, channel,
3071 slot, rank,
3072 totalrank,
3073 reg_178, 1,
3074 niter,
3075 timings);
3076 totalrank++;
3077 }
3078 }
3079 }
3080
3081 reg178_center = choose_reg178(info, timings);
3082
3083 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3084 info->training.timing_bounds[0][channel][slot][rank][lane].
3085 smallest =
3086 timings[info->training.
3087 reg178_smallest][channel][slot][rank][lane].
3088 smallest;
3089 info->training.timing_bounds[0][channel][slot][rank][lane].
3090 largest =
3091 timings[info->training.
3092 reg178_smallest][channel][slot][rank][lane].largest;
3093 info->training.timing_bounds[1][channel][slot][rank][lane].
3094 smallest =
3095 timings[info->training.
3096 reg178_largest][channel][slot][rank][lane].smallest;
3097 info->training.timing_bounds[1][channel][slot][rank][lane].
3098 largest =
3099 timings[info->training.
3100 reg178_largest][channel][slot][rank][lane].largest;
3101 info->training.timing_offset[channel][slot][rank][lane] =
3102 info->training.lane_timings[1][channel][slot][rank][lane]
3103 -
3104 info->training.lane_timings[0][channel][slot][rank][lane] +
3105 64;
3106 }
3107
3108 if (info->silicon_revision == 1
3109 && (info->
3110 populated_ranks_mask[1] ^ (info->
3111 populated_ranks_mask[1] >> 2)) & 1) {
3112 int ranks_after_channel1;
3113
3114 totalrank = 0;
3115 for (reg_178 = reg178_center - 18;
3116 reg_178 <= reg178_center + 18; reg_178 += 18) {
3117 totalrank = 0;
3118 set_178(reg_178);
3119 for (slot = 0; slot < NUM_SLOTS; slot++)
3120 for (rank = 0; rank < NUM_RANKS; rank++) {
3121 if (info->
3122 populated_ranks[1][slot][rank]) {
3123 train_ram_at_178(info, 1, slot,
3124 rank,
3125 totalrank,
3126 reg_178, 0,
3127 niter,
3128 timings);
3129 totalrank++;
3130 }
3131 }
3132 }
3133 ranks_after_channel1 = totalrank;
3134
3135 for (reg_178 = reg178_center - 12;
3136 reg_178 <= reg178_center + 12; reg_178 += 12) {
3137 totalrank = ranks_after_channel1;
3138 set_178(reg_178);
3139 for (slot = 0; slot < NUM_SLOTS; slot++)
3140 for (rank = 0; rank < NUM_RANKS; rank++)
3141 if (info->
3142 populated_ranks[0][slot][rank]) {
3143 train_ram_at_178(info, 0, slot,
3144 rank,
3145 totalrank,
3146 reg_178, 0,
3147 niter,
3148 timings);
3149 totalrank++;
3150 }
3151
3152 }
3153 } else {
3154 for (reg_178 = reg178_center - 12;
3155 reg_178 <= reg178_center + 12; reg_178 += 12) {
3156 totalrank = 0;
3157 set_178(reg_178);
3158 FOR_POPULATED_RANKS_BACKWARDS {
3159 train_ram_at_178(info, channel, slot, rank,
3160 totalrank, reg_178, 0, niter,
3161 timings);
3162 totalrank++;
3163 }
3164 }
3165 }
3166
3167 set_178(reg178_center);
3168 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3169 u16 tm0;
3170
3171 tm0 =
3172 choose_training(info, channel, slot, rank, lane, timings,
3173 reg178_center);
3174 write_500(info, channel, tm0,
3175 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3176 write_500(info, channel,
3177 tm0 +
3178 info->training.
3179 lane_timings[1][channel][slot][rank][lane] -
3180 info->training.
3181 lane_timings[0][channel][slot][rank][lane],
3182 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3183 }
3184
3185 totalrank = 0;
3186 FOR_POPULATED_RANKS_BACKWARDS {
3187 try_timing_offsets(info, channel, slot, rank, totalrank);
3188 totalrank++;
3189 }
Felix Held04be2dd2018-07-29 04:53:22 +02003190 MCHBAR8(0x243) = saved_243[0];
3191 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003192 write_1d0(0, 0x142, 3, 1);
3193 info->training.reg178_center = reg178_center;
3194}
3195
3196static void ram_training(struct raminfo *info)
3197{
3198 u16 saved_fc4;
3199
Felix Held04be2dd2018-07-29 04:53:22 +02003200 saved_fc4 = MCHBAR16(0xfc4);
3201 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003202
3203 if (info->revision >= 8)
3204 read_4090(info);
3205
3206 if (!try_cached_training(info))
3207 do_ram_training(info);
3208 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3209 && info->clock_speed_index < 2)
3210 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003211 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003212}
3213
3214static unsigned gcd(unsigned a, unsigned b)
3215{
3216 unsigned t;
3217 if (a > b) {
3218 t = a;
3219 a = b;
3220 b = t;
3221 }
3222 /* invariant a < b. */
3223 while (a) {
3224 t = b % a;
3225 b = a;
3226 a = t;
3227 }
3228 return b;
3229}
3230
3231static inline int div_roundup(int a, int b)
3232{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003233 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003234}
3235
3236static unsigned lcm(unsigned a, unsigned b)
3237{
3238 return (a * b) / gcd(a, b);
3239}
3240
3241struct stru1 {
3242 u8 freqs_reversed;
3243 u8 freq_diff_reduced;
3244 u8 freq_min_reduced;
3245 u8 divisor_f4_to_fmax;
3246 u8 divisor_f3_to_fmax;
3247 u8 freq4_to_max_remainder;
3248 u8 freq3_to_2_remainder;
3249 u8 freq3_to_2_remaindera;
3250 u8 freq4_to_2_remainder;
3251 int divisor_f3_to_f1, divisor_f4_to_f2;
3252 int common_time_unit_ps;
3253 int freq_max_reduced;
3254};
3255
3256static void
3257compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3258 int num_cycles_2, int num_cycles_1, int round_it,
3259 int add_freqs, struct stru1 *result)
3260{
3261 int g;
3262 int common_time_unit_ps;
3263 int freq1_reduced, freq2_reduced;
3264 int freq_min_reduced;
3265 int freq_max_reduced;
3266 int freq3, freq4;
3267
3268 g = gcd(freq1, freq2);
3269 freq1_reduced = freq1 / g;
3270 freq2_reduced = freq2 / g;
3271 freq_min_reduced = min(freq1_reduced, freq2_reduced);
3272 freq_max_reduced = max(freq1_reduced, freq2_reduced);
3273
3274 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3275 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3276 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3277 if (add_freqs) {
3278 freq3 += freq2_reduced;
3279 freq4 += freq1_reduced;
3280 }
3281
3282 if (round_it) {
3283 result->freq3_to_2_remainder = 0;
3284 result->freq3_to_2_remaindera = 0;
3285 result->freq4_to_max_remainder = 0;
3286 result->divisor_f4_to_f2 = 0;
3287 result->divisor_f3_to_f1 = 0;
3288 } else {
3289 if (freq2_reduced < freq1_reduced) {
3290 result->freq3_to_2_remainder =
3291 result->freq3_to_2_remaindera =
3292 freq3 % freq1_reduced - freq1_reduced + 1;
3293 result->freq4_to_max_remainder =
3294 -(freq4 % freq1_reduced);
3295 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3296 result->divisor_f4_to_f2 =
3297 (freq4 -
3298 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3299 result->freq4_to_2_remainder =
3300 -(char)((freq1_reduced - freq2_reduced) +
3301 ((u8) freq4 -
3302 (freq1_reduced -
3303 freq2_reduced)) % (u8) freq2_reduced);
3304 } else {
3305 if (freq2_reduced > freq1_reduced) {
3306 result->freq4_to_max_remainder =
3307 (freq4 % freq2_reduced) - freq2_reduced + 1;
3308 result->freq4_to_2_remainder =
3309 freq4 % freq_max_reduced -
3310 freq_max_reduced + 1;
3311 } else {
3312 result->freq4_to_max_remainder =
3313 -(freq4 % freq2_reduced);
3314 result->freq4_to_2_remainder =
3315 -(char)(freq4 % freq_max_reduced);
3316 }
3317 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3318 result->divisor_f3_to_f1 =
3319 (freq3 -
3320 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3321 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3322 result->freq3_to_2_remaindera =
3323 -(char)((freq_max_reduced - freq_min_reduced) +
3324 (freq3 -
3325 (freq_max_reduced -
3326 freq_min_reduced)) % freq1_reduced);
3327 }
3328 }
3329 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3330 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3331 if (round_it) {
3332 if (freq2_reduced > freq1_reduced) {
3333 if (freq3 % freq_max_reduced)
3334 result->divisor_f3_to_fmax++;
3335 }
3336 if (freq2_reduced < freq1_reduced) {
3337 if (freq4 % freq_max_reduced)
3338 result->divisor_f4_to_fmax++;
3339 }
3340 }
3341 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3342 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3343 result->freq_min_reduced = freq_min_reduced;
3344 result->common_time_unit_ps = common_time_unit_ps;
3345 result->freq_max_reduced = freq_max_reduced;
3346}
3347
3348static void
3349set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3350 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3351 int num_cycles_4, int reverse)
3352{
3353 struct stru1 vv;
3354 char multiplier;
3355
3356 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3357 0, 1, &vv);
3358
3359 multiplier =
3360 div_roundup(max
3361 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3362 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3363 div_roundup(num_cycles_1,
3364 vv.common_time_unit_ps) +
3365 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3366 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3367
3368 u32 y =
3369 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3370 vv.freq_max_reduced * multiplier)
3371 | (vv.
3372 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3373 multiplier) << 16) | ((u8) (vv.
3374 freq_min_reduced
3375 *
3376 multiplier)
3377 << 24);
3378 u32 x =
3379 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3380 divisor_f3_to_f1
3381 << 16)
3382 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3383 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003384 MCHBAR32(reg) = y;
3385 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003386 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003387 MCHBAR32(reg + 4) = y;
3388 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003389 }
3390}
3391
3392static void
3393set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3394 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3395 int num_cycles_4)
3396{
3397 struct stru1 ratios1;
3398 struct stru1 ratios2;
3399
3400 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3401 0, 1, &ratios2);
3402 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3403 0, 1, &ratios1);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003404 printk (BIOS_SPEW, "[%x] <= %x\n", reg,
3405 ratios1.freq4_to_max_remainder | (ratios2.
3406 freq4_to_max_remainder
3407 << 8)
3408 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3409 divisor_f4_to_fmax
3410 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003411 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3412 (ratios2.freq4_to_max_remainder << 8) |
3413 (ratios1.divisor_f4_to_fmax << 16) |
3414 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003415}
3416
3417static void
3418set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3419 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3420{
3421 struct stru1 ratios;
3422
3423 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3424 round_it, add_freqs, &ratios);
3425 switch (mode) {
3426 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003427 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3428 (ratios.freqs_reversed << 8);
3429 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3430 (ratios.freq4_to_max_remainder << 8) |
3431 (ratios.divisor_f3_to_fmax << 16) |
3432 (ratios.divisor_f4_to_fmax << 20) |
3433 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003434 break;
3435
3436 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003437 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3438 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003439 break;
3440
3441 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003442 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3443 (ratios.freq4_to_max_remainder << 8) |
3444 (ratios.divisor_f3_to_fmax << 16) |
3445 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003446 break;
3447
3448 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003449 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3450 (ratios.divisor_f4_to_fmax << 8) |
3451 (ratios.freqs_reversed << 12) |
3452 (ratios.freq_min_reduced << 16) |
3453 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003454 break;
3455 }
3456}
3457
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003458static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003459{
3460 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3461 0, 1);
3462 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3463 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3464 1);
3465 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3466 frequency_11(info), 1231, 1524, 0, 1);
3467 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3468 frequency_11(info) / 2, 1278, 2008, 0, 1);
3469 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3470 1167, 1539, 0, 1);
3471 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3472 frequency_11(info) / 2, 1403, 1318, 0, 1);
3473 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3474 1);
3475 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3476 1);
3477 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3478 1, 1);
3479 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3480 1);
3481 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3482 frequency_11(info) / 2, 4000, 0, 0, 0);
3483 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3484 frequency_11(info) / 2, 4000, 4000, 0, 0);
3485
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003486 if (s3resume) {
3487 printk (BIOS_SPEW, "[6dc] <= %x\n", info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003488 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003489 } else
3490 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3491 info->delay46_ps[0], 0,
3492 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003493 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3494 frequency_11(info), 2500, 0, 0, 0);
3495 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3496 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003497 if (s3resume) {
3498 printk (BIOS_SPEW, "[6e8] <= %x\n", info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003499 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003500 } else
3501 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3502 info->delay46_ps[1], 0,
3503 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003504 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3505 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3506 470, 0);
3507 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3508 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3509 454, 459, 0);
3510 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3511 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3512 2588, 0);
3513 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3514 2405, 0);
3515 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3516 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3517 480, 0);
3518 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003519 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3520 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003521}
3522
3523static u16 get_max_timing(struct raminfo *info, int channel)
3524{
3525 int slot, rank, lane;
3526 u16 ret = 0;
3527
Felix Held04be2dd2018-07-29 04:53:22 +02003528 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003529 return 384;
3530
3531 if (info->revision < 8)
3532 return 256;
3533
3534 for (slot = 0; slot < NUM_SLOTS; slot++)
3535 for (rank = 0; rank < NUM_RANKS; rank++)
3536 if (info->populated_ranks[channel][slot][rank])
3537 for (lane = 0; lane < 8 + info->use_ecc; lane++)
3538 ret = max(ret, read_500(info, channel,
3539 get_timing_register_addr
3540 (lane, 0, slot,
3541 rank), 9));
3542 return ret;
3543}
3544
3545static void set_274265(struct raminfo *info)
3546{
3547 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3548 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3549 int delay_e_over_cycle_ps;
3550 int cycletime_ps;
3551 int channel;
3552
3553 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003554 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003555 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3556 cycletime_ps =
3557 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3558 delay_d_ps =
3559 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3560 - info->some_delay_3_ps_rounded + 200;
3561 if (!
3562 ((info->silicon_revision == 0
3563 || info->silicon_revision == 1)
3564 && (info->revision >= 8)))
3565 delay_d_ps += halfcycle_ps(info) * 2;
3566 delay_d_ps +=
3567 halfcycle_ps(info) * (!info->revision_flag_1 +
3568 info->some_delay_2_halfcycles_ceil +
3569 2 * info->some_delay_1_cycle_floor +
3570 info->clock_speed_index +
3571 2 * info->cas_latency - 7 + 11);
3572 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3573
Felix Held04be2dd2018-07-29 04:53:22 +02003574 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3575 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3576 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003577 delay_d_ps += 650;
3578 delay_c_ps = delay_d_ps + 1800;
3579 if (delay_c_ps <= delay_a_ps)
3580 delay_e_ps = 0;
3581 else
3582 delay_e_ps =
3583 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3584 cycletime_ps);
3585
3586 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3587 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3588 delay_f_cycles =
3589 div_roundup(2500 - delay_e_over_cycle_ps,
3590 2 * halfcycle_ps(info));
3591 if (delay_f_cycles > delay_e_cycles) {
3592 info->delay46_ps[channel] = delay_e_ps;
3593 delay_e_cycles = 0;
3594 } else {
3595 info->delay46_ps[channel] =
3596 delay_e_over_cycle_ps +
3597 2 * halfcycle_ps(info) * delay_f_cycles;
3598 delay_e_cycles -= delay_f_cycles;
3599 }
3600
3601 if (info->delay46_ps[channel] < 2500) {
3602 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003603 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003604 }
3605 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3606 if (delay_b_ps <= delay_a_ps)
3607 delay_b_ps = 0;
3608 else
3609 delay_b_ps -= delay_a_ps;
3610 info->delay54_ps[channel] =
3611 cycletime_ps * div_roundup(delay_b_ps,
3612 cycletime_ps) -
3613 2 * halfcycle_ps(info) * delay_e_cycles;
3614 if (info->delay54_ps[channel] < 2500)
3615 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003616 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003617 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3618 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003619 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003620 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003621 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003622 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3623 4 * halfcycle_ps(info)) - 6;
3624 MCHBAR32((channel << 10) + 0x274) =
3625 info->training.reg274265[channel][1] |
3626 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003627 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003628 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3629 4 * halfcycle_ps(info)) + 1;
3630 MCHBAR16((channel << 10) + 0x265) =
3631 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003632 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003633 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003634 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003635 else
Felix Held04be2dd2018-07-29 04:53:22 +02003636 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003637}
3638
3639static void restore_274265(struct raminfo *info)
3640{
3641 int channel;
3642
3643 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003644 MCHBAR32((channel << 10) + 0x274) =
3645 (info->cached_training->reg274265[channel][0] << 16) |
3646 info->cached_training->reg274265[channel][1];
3647 MCHBAR16((channel << 10) + 0x265) =
3648 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003649 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003650 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003651 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003652 else
Felix Held04be2dd2018-07-29 04:53:22 +02003653 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003654}
3655
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003656static void dmi_setup(void)
3657{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003658 gav(read8(DEFAULT_DMIBAR + 0x254));
3659 write8(DEFAULT_DMIBAR + 0x254, 0x1);
3660 write16(DEFAULT_DMIBAR + 0x1b8, 0x18f2);
Felix Heldf83d80b2018-07-29 05:30:30 +02003661 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003662
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003663 write32(DEFAULT_DMIBAR + 0xd68, read32(DEFAULT_DMIBAR + 0xd68) | 0x08000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003664
3665 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3666 DEFAULT_GPIOBASE | 0x38);
3667 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3668}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003669
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003670void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003671{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003672 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003673 u16 ggc;
3674 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003675
Felix Held04be2dd2018-07-29 04:53:22 +02003676 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003677 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3678 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003679 MCHBAR8(0x2ca8) = 0;
Vladimir Serbinenkoe1eef692014-02-19 22:08:51 +01003680 outb(0x6, 0xcf9);
Patrick Georgi546953c2014-11-29 10:38:17 +01003681 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003682 }
Felix Held29a9c072018-07-29 01:34:45 +02003683#if 0
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003684 if (!s3resume) {
3685 pre_raminit_3(x2ca8);
3686 }
Vladimir Serbinenkof62669c2014-01-09 10:59:38 +01003687 pre_raminit_4a(x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003688#endif
3689
3690 dmi_setup();
3691
Felix Held04be2dd2018-07-29 04:53:22 +02003692 MCHBAR16(0x1170) = 0xa880;
3693 MCHBAR8(0x11c1) = 0x1;
3694 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003695 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003696
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003697 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3698 /* 0 for 32MB */
3699 gfxsize = 0;
3700 }
3701
3702 ggc = 0xb00 | ((gfxsize + 5) << 4);
3703
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003704 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003705
3706 u16 deven;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003707 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003708
3709 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003710 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003711 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003712 MCHBAR16_OR(0x2c30, 0x200);
3713 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003714 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003715 pci_read_config8(GMA, 0x62); // = 0x2
3716 pci_write_config8(GMA, 0x62, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003717 read8(DEFAULT_RCBA + 0x2318);
3718 write8(DEFAULT_RCBA + 0x2318, 0x47);
3719 read8(DEFAULT_RCBA + 0x2320);
3720 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003721 }
3722
Felix Heldf83d80b2018-07-29 05:30:30 +02003723 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003724
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003725 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003726 gav(read32(DEFAULT_RCBA + 0x3428));
3727 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003728}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003729
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003730void raminit(const int s3resume, const u8 *spd_addrmap)
3731{
3732 unsigned channel, slot, lane, rank;
3733 int i;
3734 struct raminfo info;
3735 u8 x2ca8;
3736 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003737 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003738
Felix Heldf83d80b2018-07-29 05:30:30 +02003739 /* only used for dummy reads */
3740 volatile u8 tmp8;
3741 volatile u16 tmp16;
3742 volatile u32 tmp32;
3743
Felix Held04be2dd2018-07-29 04:53:22 +02003744 x2ca8 = MCHBAR8(0x2ca8);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003745 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003746
3747 memset(&info, 0x5a, sizeof(info));
3748
3749 info.last_500_command[0] = 0;
3750 info.last_500_command[1] = 0;
3751
3752 info.fsb_frequency = 135 * 2;
3753 info.board_lane_delay[0] = 0x14;
3754 info.board_lane_delay[1] = 0x07;
3755 info.board_lane_delay[2] = 0x07;
3756 info.board_lane_delay[3] = 0x08;
3757 info.board_lane_delay[4] = 0x56;
3758 info.board_lane_delay[5] = 0x04;
3759 info.board_lane_delay[6] = 0x04;
3760 info.board_lane_delay[7] = 0x05;
3761 info.board_lane_delay[8] = 0x10;
3762
3763 info.training.reg_178 = 0;
3764 info.training.reg_10b = 0;
3765
3766 info.heci_bar = 0;
3767 info.memory_reserved_for_heci_mb = 0;
3768
3769 /* before SPD */
3770 timestamp_add_now(101);
3771
Felix Held29a9c072018-07-29 01:34:45 +02003772 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003773 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003774
3775 collect_system_info(&info);
3776
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003777 /* Enable SMBUS. */
3778 enable_smbus();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003779
3780 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3781
3782 info.use_ecc = 1;
3783 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003784 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003785 int v;
3786 int try;
3787 int addr;
3788 const u8 useful_addresses[] = {
3789 DEVICE_TYPE,
3790 MODULE_TYPE,
3791 DENSITY,
3792 RANKS_AND_DQ,
3793 MEMORY_BUS_WIDTH,
3794 TIMEBASE_DIVIDEND,
3795 TIMEBASE_DIVISOR,
3796 CYCLETIME,
3797 CAS_LATENCIES_LSB,
3798 CAS_LATENCIES_MSB,
3799 CAS_LATENCY_TIME,
3800 0x11, 0x12, 0x13, 0x14, 0x15,
3801 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3802 0x1c, 0x1d,
3803 THERMAL_AND_REFRESH,
3804 0x20,
3805 REFERENCE_RAW_CARD_USED,
3806 RANK1_ADDRESS_MAPPING,
3807 0x75, 0x76, 0x77, 0x78,
3808 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3809 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3810 0x85, 0x86, 0x87, 0x88,
3811 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3812 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3813 0x95
3814 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003815 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003816 continue;
3817 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003818 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003819 DEVICE_TYPE);
3820 if (v >= 0)
3821 break;
3822 }
3823 if (v < 0)
3824 continue;
3825 for (addr = 0;
3826 addr <
3827 sizeof(useful_addresses) /
3828 sizeof(useful_addresses[0]); addr++)
3829 gav(info.
3830 spd[channel][0][useful_addresses
3831 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003832 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003833 useful_addresses
3834 [addr]));
3835 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3836 die("Only DDR3 is supported");
3837
3838 v = info.spd[channel][0][RANKS_AND_DQ];
3839 info.populated_ranks[channel][0][0] = 1;
3840 info.populated_ranks[channel][0][1] =
3841 ((v >> 3) & 7);
3842 if (((v >> 3) & 7) > 1)
3843 die("At most 2 ranks are supported");
3844 if ((v & 7) == 0 || (v & 7) > 2)
3845 die("Only x8 and x16 modules are supported");
3846 if ((info.
3847 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3848 && (info.
3849 spd[channel][slot][MODULE_TYPE] & 0xF)
3850 != 3)
3851 die("Registered memory is not supported");
3852 info.is_x16_module[channel][0] = (v & 7) - 1;
3853 info.density[channel][slot] =
3854 info.spd[channel][slot][DENSITY] & 0xF;
3855 if (!
3856 (info.
3857 spd[channel][slot][MEMORY_BUS_WIDTH] &
3858 0x18))
3859 info.use_ecc = 0;
3860 }
3861
3862 gav(0x55);
3863
3864 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3865 int v = 0;
3866 for (slot = 0; slot < NUM_SLOTS; slot++)
3867 for (rank = 0; rank < NUM_RANKS; rank++)
3868 v |= info.
3869 populated_ranks[channel][slot][rank]
3870 << (2 * slot + rank);
3871 info.populated_ranks_mask[channel] = v;
3872 }
3873
3874 gav(0x55);
3875
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003876 gav(pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003877 }
3878
3879 /* after SPD */
3880 timestamp_add_now(102);
3881
Felix Held04be2dd2018-07-29 04:53:22 +02003882 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003883
3884 collect_system_info(&info);
3885 calculate_timings(&info);
3886
Felix Held29a9c072018-07-29 01:34:45 +02003887#if 0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003888 pci_write_config8(NORTHBRIDGE, 0xdf, 0x82);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003889#endif
3890
3891 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003892 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003893 if (x2ca8 == 0 && (reg8 & 0x80)) {
3894 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3895 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3896 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3897 */
3898
3899 /* Clear bit7. */
3900
3901 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3902 (reg8 & ~(1 << 7)));
3903
3904 printk(BIOS_INFO,
3905 "Interrupted RAM init, reset required.\n");
3906 outb(0x6, 0xcf9);
Patrick Georgi546953c2014-11-29 10:38:17 +01003907 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003908 }
3909 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003910
3911 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003912 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3913 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003914
3915 compute_derived_timings(&info);
3916
3917 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003918 gav(MCHBAR8(0x164));
3919 MCHBAR8(0x164) = 0x26;
3920 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003921 }
3922
Felix Held04be2dd2018-07-29 04:53:22 +02003923 MCHBAR32_OR(0x18b4, 0x210000);
3924 MCHBAR32_OR(0x1890, 0x2000000);
3925 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003926
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003927 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x50)); // !!!!
3928 pci_write_config8(PCI_DEV(0xff, 2, 1), 0x54, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003929
Felix Held04be2dd2018-07-29 04:53:22 +02003930 gav(MCHBAR16(0x2c10));
3931 MCHBAR16(0x2c10) = 0x412;
3932 gav(MCHBAR16(0x2c10));
3933 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003934
Felix Held04be2dd2018-07-29 04:53:22 +02003935 gav(MCHBAR8(0x2ca8)); // !!!!
3936 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003937
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003938 pci_read_config32(PCI_DEV(0xff, 2, 1), 0x6c); // !!!!
3939 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x6c, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003940 gav(MCHBAR32(0x1c04)); // !!!!
3941 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003942
3943 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003944 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003945 }
3946
Felix Held04be2dd2018-07-29 04:53:22 +02003947 MCHBAR32(0x18d8) = 0x120000;
3948 MCHBAR32(0x18dc) = 0x30a484a;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003949 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x0);
3950 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003951 MCHBAR32(0x18d8) = 0x40000;
3952 MCHBAR32(0x18dc) = 0xb000000;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003953 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x60000);
3954 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003955 MCHBAR32(0x18d8) = 0x180000;
3956 MCHBAR32(0x18dc) = 0xc0000142;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003957 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x20000);
3958 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003959 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003960
Felix Held04be2dd2018-07-29 04:53:22 +02003961 gav(MCHBAR32(0x18dc)); // !!!!
3962 MCHBAR32(0x18dc) = 0x3;
3963 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003964
3965 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003966 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003967 }
3968
Felix Held04be2dd2018-07-29 04:53:22 +02003969 MCHBAR32(0x188c) = 0x20bc09;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003970 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xd0, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003971 MCHBAR32(0x1a10) = 0x4200010e;
3972 MCHBAR32_OR(0x18b8, 0x200);
3973 gav(MCHBAR32(0x1918)); // !!!!
3974 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003975
Felix Held04be2dd2018-07-29 04:53:22 +02003976 gav(MCHBAR32(0x18b8)); // !!!!
3977 MCHBAR32(0x18b8) = 0xe00;
3978 gav(MCHBAR32(0x182c)); // !!!!
3979 MCHBAR32(0x182c) = 0x10202;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003980 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x94)); // !!!!
3981 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x94, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003982 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3983 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003984
Felix Held04be2dd2018-07-29 04:53:22 +02003985 MCHBAR32_AND(0x18b4, 0xffff7fff);
3986 gav(MCHBAR32(0x1a68)); // !!!!
3987 MCHBAR32(0x1a68) = 0x343800;
3988 gav(MCHBAR32(0x1e68)); // !!!!
3989 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003990
3991 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003992 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003993 }
3994
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003995 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x048); // !!!!
3996 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x048, 0x140000);
3997 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3998 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x058, 0x64555);
3999 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
4000 pci_read_config32(PCI_DEV (0xff, 0, 0), 0xd0); // !!!!
4001 pci_write_config32(PCI_DEV (0xff, 0, 0), 0xd0, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02004002 gav(MCHBAR32(0x1af0)); // !!!!
4003 gav(MCHBAR32(0x1af0)); // !!!!
4004 MCHBAR32(0x1af0) = 0x1f020003;
4005 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004006
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10004007 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004008 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004009 }
4010
Felix Held04be2dd2018-07-29 04:53:22 +02004011 gav(MCHBAR32(0x1890)); // !!!!
4012 MCHBAR32(0x1890) = 0x80102;
4013 gav(MCHBAR32(0x18b4)); // !!!!
4014 MCHBAR32(0x18b4) = 0x216000;
4015 MCHBAR32(0x18a4) = 0x22222222;
4016 MCHBAR32(0x18a8) = 0x22222222;
4017 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004018
4019 udelay(1000);
4020
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004021 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004022
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004023 if (x2ca8 == 0) {
4024 int j;
4025 if (s3resume && info.cached_training) {
4026 restore_274265(&info);
4027 printk(BIOS_DEBUG, "reg2ca9_bit0 = %x\n",
4028 info.cached_training->reg2ca9_bit0);
4029 for (i = 0; i < 2; i++)
4030 for (j = 0; j < 3; j++)
4031 printk(BIOS_DEBUG, "reg274265[%d][%d] = %x\n",
4032 i, j, info.cached_training->reg274265[i][j]);
4033 } else {
4034 set_274265(&info);
4035 printk(BIOS_DEBUG, "reg2ca9_bit0 = %x\n",
4036 info.training.reg2ca9_bit0);
4037 for (i = 0; i < 2; i++)
4038 for (j = 0; j < 3; j++)
4039 printk(BIOS_DEBUG, "reg274265[%d][%d] = %x\n",
4040 i, j, info.training.reg274265[i][j]);
4041 }
4042
4043 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004044
4045 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02004046 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004047 }
4048
4049 udelay(1000);
4050
4051 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02004052 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02004053 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004054 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4055 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4056 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004057
Felix Heldf83d80b2018-07-29 05:30:30 +02004058 tmp8 = MCHBAR8(0x1150);
4059 tmp8 = MCHBAR8(0x1151);
4060 tmp8 = MCHBAR8(0x1022);
4061 tmp8 = MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004062 MCHBAR32(0x1300) = 0x60606060;
4063 MCHBAR32(0x1304) = 0x60606060;
4064 MCHBAR32(0x1308) = 0x78797a7b;
4065 MCHBAR32(0x130c) = 0x7c7d7e7f;
4066 MCHBAR32(0x1310) = 0x60606060;
4067 MCHBAR32(0x1314) = 0x60606060;
4068 MCHBAR32(0x1318) = 0x60606060;
4069 MCHBAR32(0x131c) = 0x60606060;
4070 MCHBAR32(0x1320) = 0x50515253;
4071 MCHBAR32(0x1324) = 0x54555657;
4072 MCHBAR32(0x1328) = 0x58595a5b;
4073 MCHBAR32(0x132c) = 0x5c5d5e5f;
4074 MCHBAR32(0x1330) = 0x40414243;
4075 MCHBAR32(0x1334) = 0x44454647;
4076 MCHBAR32(0x1338) = 0x48494a4b;
4077 MCHBAR32(0x133c) = 0x4c4d4e4f;
4078 MCHBAR32(0x1340) = 0x30313233;
4079 MCHBAR32(0x1344) = 0x34353637;
4080 MCHBAR32(0x1348) = 0x38393a3b;
4081 MCHBAR32(0x134c) = 0x3c3d3e3f;
4082 MCHBAR32(0x1350) = 0x20212223;
4083 MCHBAR32(0x1354) = 0x24252627;
4084 MCHBAR32(0x1358) = 0x28292a2b;
4085 MCHBAR32(0x135c) = 0x2c2d2e2f;
4086 MCHBAR32(0x1360) = 0x10111213;
4087 MCHBAR32(0x1364) = 0x14151617;
4088 MCHBAR32(0x1368) = 0x18191a1b;
4089 MCHBAR32(0x136c) = 0x1c1d1e1f;
4090 MCHBAR32(0x1370) = 0x10203;
4091 MCHBAR32(0x1374) = 0x4050607;
4092 MCHBAR32(0x1378) = 0x8090a0b;
4093 MCHBAR32(0x137c) = 0xc0d0e0f;
4094 MCHBAR8(0x11cc) = 0x4e;
4095 MCHBAR32(0x1110) = 0x73970404;
4096 MCHBAR32(0x1114) = 0x72960404;
4097 MCHBAR32(0x1118) = 0x6f950404;
4098 MCHBAR32(0x111c) = 0x6d940404;
4099 MCHBAR32(0x1120) = 0x6a930404;
4100 MCHBAR32(0x1124) = 0x68a41404;
4101 MCHBAR32(0x1128) = 0x66a21404;
4102 MCHBAR32(0x112c) = 0x63a01404;
4103 MCHBAR32(0x1130) = 0x609e1404;
4104 MCHBAR32(0x1134) = 0x5f9c1404;
4105 MCHBAR32(0x1138) = 0x5c961404;
4106 MCHBAR32(0x113c) = 0x58a02404;
4107 MCHBAR32(0x1140) = 0x54942404;
4108 MCHBAR32(0x1190) = 0x900080a;
4109 MCHBAR16(0x11c0) = 0xc40b;
4110 MCHBAR16(0x11c2) = 0x303;
4111 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004112 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004113 MCHBAR32(0x11b8) = 0x70c3000;
4114 MCHBAR8(0x11ec) = 0xa;
4115 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004116 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004117 MCHBAR16(0x11ca) = 0xfa;
4118 MCHBAR32(0x11e4) = 0x4e20;
4119 MCHBAR8(0x11bc) = 0xf;
4120 MCHBAR16(0x11da) = 0x19;
4121 MCHBAR16(0x11ba) = 0x470c;
4122 MCHBAR32(0x1680) = 0xe6ffe4ff;
4123 MCHBAR32(0x1684) = 0xdeffdaff;
4124 MCHBAR32(0x1688) = 0xd4ffd0ff;
4125 MCHBAR32(0x168c) = 0xccffc6ff;
4126 MCHBAR32(0x1690) = 0xc0ffbeff;
4127 MCHBAR32(0x1694) = 0xb8ffb0ff;
4128 MCHBAR32(0x1698) = 0xa8ff0000;
4129 MCHBAR32(0x169c) = 0xc00;
4130 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004131 }
4132
Felix Held04be2dd2018-07-29 04:53:22 +02004133 MCHBAR32(0x124c) = 0x15040d00;
4134 MCHBAR32(0x1250) = 0x7f0000;
4135 MCHBAR32(0x1254) = 0x1e220004;
4136 MCHBAR32(0x1258) = 0x4000004;
4137 MCHBAR32(0x1278) = 0x0;
4138 MCHBAR32(0x125c) = 0x0;
4139 MCHBAR32(0x1260) = 0x0;
4140 MCHBAR32(0x1264) = 0x0;
4141 MCHBAR32(0x1268) = 0x0;
4142 MCHBAR32(0x126c) = 0x0;
4143 MCHBAR32(0x1270) = 0x0;
4144 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004145 }
4146
4147 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004148 MCHBAR16(0x1214) = 0x320;
4149 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004150 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4151 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004152 MCHBAR32(0x1400) = 0x13040020;
4153 MCHBAR32(0x1404) = 0xe090120;
4154 MCHBAR32(0x1408) = 0x5120220;
4155 MCHBAR32(0x140c) = 0x5120330;
4156 MCHBAR32(0x1410) = 0xe090220;
4157 MCHBAR32(0x1414) = 0x1010001;
4158 MCHBAR32(0x1418) = 0x1110000;
4159 MCHBAR32(0x141c) = 0x9020020;
4160 MCHBAR32(0x1420) = 0xd090220;
4161 MCHBAR32(0x1424) = 0x2090220;
4162 MCHBAR32(0x1428) = 0x2090330;
4163 MCHBAR32(0x142c) = 0xd090220;
4164 MCHBAR32(0x1430) = 0x1010001;
4165 MCHBAR32(0x1434) = 0x1110000;
4166 MCHBAR32(0x1438) = 0x11040020;
4167 MCHBAR32(0x143c) = 0x4030220;
4168 MCHBAR32(0x1440) = 0x1060220;
4169 MCHBAR32(0x1444) = 0x1060330;
4170 MCHBAR32(0x1448) = 0x4030220;
4171 MCHBAR32(0x144c) = 0x1010001;
4172 MCHBAR32(0x1450) = 0x1110000;
4173 MCHBAR32(0x1454) = 0x4010020;
4174 MCHBAR32(0x1458) = 0xb090220;
4175 MCHBAR32(0x145c) = 0x1090220;
4176 MCHBAR32(0x1460) = 0x1090330;
4177 MCHBAR32(0x1464) = 0xb090220;
4178 MCHBAR32(0x1468) = 0x1010001;
4179 MCHBAR32(0x146c) = 0x1110000;
4180 MCHBAR32(0x1470) = 0xf040020;
4181 MCHBAR32(0x1474) = 0xa090220;
4182 MCHBAR32(0x1478) = 0x1120220;
4183 MCHBAR32(0x147c) = 0x1120330;
4184 MCHBAR32(0x1480) = 0xa090220;
4185 MCHBAR32(0x1484) = 0x1010001;
4186 MCHBAR32(0x1488) = 0x1110000;
4187 MCHBAR32(0x148c) = 0x7020020;
4188 MCHBAR32(0x1490) = 0x1010220;
4189 MCHBAR32(0x1494) = 0x10210;
4190 MCHBAR32(0x1498) = 0x10320;
4191 MCHBAR32(0x149c) = 0x1010220;
4192 MCHBAR32(0x14a0) = 0x1010001;
4193 MCHBAR32(0x14a4) = 0x1110000;
4194 MCHBAR32(0x14a8) = 0xd040020;
4195 MCHBAR32(0x14ac) = 0x8090220;
4196 MCHBAR32(0x14b0) = 0x1111310;
4197 MCHBAR32(0x14b4) = 0x1111420;
4198 MCHBAR32(0x14b8) = 0x8090220;
4199 MCHBAR32(0x14bc) = 0x1010001;
4200 MCHBAR32(0x14c0) = 0x1110000;
4201 MCHBAR32(0x14c4) = 0x3010020;
4202 MCHBAR32(0x14c8) = 0x7090220;
4203 MCHBAR32(0x14cc) = 0x1081310;
4204 MCHBAR32(0x14d0) = 0x1081420;
4205 MCHBAR32(0x14d4) = 0x7090220;
4206 MCHBAR32(0x14d8) = 0x1010001;
4207 MCHBAR32(0x14dc) = 0x1110000;
4208 MCHBAR32(0x14e0) = 0xb040020;
4209 MCHBAR32(0x14e4) = 0x2030220;
4210 MCHBAR32(0x14e8) = 0x1051310;
4211 MCHBAR32(0x14ec) = 0x1051420;
4212 MCHBAR32(0x14f0) = 0x2030220;
4213 MCHBAR32(0x14f4) = 0x1010001;
4214 MCHBAR32(0x14f8) = 0x1110000;
4215 MCHBAR32(0x14fc) = 0x5020020;
4216 MCHBAR32(0x1500) = 0x5090220;
4217 MCHBAR32(0x1504) = 0x2071310;
4218 MCHBAR32(0x1508) = 0x2071420;
4219 MCHBAR32(0x150c) = 0x5090220;
4220 MCHBAR32(0x1510) = 0x1010001;
4221 MCHBAR32(0x1514) = 0x1110000;
4222 MCHBAR32(0x1518) = 0x7040120;
4223 MCHBAR32(0x151c) = 0x2090220;
4224 MCHBAR32(0x1520) = 0x70b1210;
4225 MCHBAR32(0x1524) = 0x70b1310;
4226 MCHBAR32(0x1528) = 0x2090220;
4227 MCHBAR32(0x152c) = 0x1010001;
4228 MCHBAR32(0x1530) = 0x1110000;
4229 MCHBAR32(0x1534) = 0x1010110;
4230 MCHBAR32(0x1538) = 0x1081310;
4231 MCHBAR32(0x153c) = 0x5041200;
4232 MCHBAR32(0x1540) = 0x5041310;
4233 MCHBAR32(0x1544) = 0x1081310;
4234 MCHBAR32(0x1548) = 0x1010001;
4235 MCHBAR32(0x154c) = 0x1110000;
4236 MCHBAR32(0x1550) = 0x1040120;
4237 MCHBAR32(0x1554) = 0x4051210;
4238 MCHBAR32(0x1558) = 0xd051200;
4239 MCHBAR32(0x155c) = 0xd051200;
4240 MCHBAR32(0x1560) = 0x4051210;
4241 MCHBAR32(0x1564) = 0x1010001;
4242 MCHBAR32(0x1568) = 0x1110000;
4243 MCHBAR16(0x1222) = 0x220a;
4244 MCHBAR16(0x123c) = 0x1fc0;
4245 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004246 }
4247
Felix Heldf83d80b2018-07-29 05:30:30 +02004248 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
4249 tmp32 = MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004250 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004251
Felix Heldf83d80b2018-07-29 05:30:30 +02004252 tmp8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004253
4254 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004255 MCHBAR8_AND(0x2ca8, ~3);
4256 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
4257 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004258 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004259 }
4260
Felix Held04be2dd2018-07-29 04:53:22 +02004261 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004262 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004263 pci_write_config32(PCI_DEV (0xff, 0, 0), 0x60, 0x20220);
Felix Heldf83d80b2018-07-29 05:30:30 +02004264 tmp16 = MCHBAR16(0x2c20); // !!!!
4265 tmp16 = MCHBAR16(0x2c10); // !!!!
4266 tmp16 = MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004267 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004268 udelay(1000);
4269 write_1d0(0, 0x33d, 0, 0);
4270 write_500(&info, 0, 0, 0xb61, 0, 0);
4271 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004272 MCHBAR32(0x1a30) = 0x0;
4273 MCHBAR32(0x1a34) = 0x0;
4274 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4275 (info.populated_ranks[0][0][0] * 0xa0);
4276 MCHBAR16(0x616) = 0x26a;
4277 MCHBAR32(0x134) = 0x856000;
4278 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004279 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4280 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004281 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004282 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4283 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004284 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004285 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004286 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4287 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004288 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4289 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4290 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4291 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4292 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4293 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4294 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4295 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4296 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4297 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004298 }
4299
4300 write_1d0(0x4, 0x151, 4, 1);
4301 write_1d0(0, 0x142, 3, 1);
4302 rdmsr(0x1ac); // !!!!
4303 write_500(&info, 1, 1, 0x6b3, 4, 1);
4304 write_500(&info, 1, 1, 0x6cf, 4, 1);
4305
4306 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4307
4308 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4309 populated_ranks[0]
4310 [0][0]) << 0),
4311 0x1d1, 3, 1);
4312 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004313 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4314 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004315 }
4316
4317 set_334(0);
4318
4319 program_base_timings(&info);
4320
Felix Held04be2dd2018-07-29 04:53:22 +02004321 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004322
4323 write_1d0(0x2, 0x1d5, 2, 1);
4324 write_1d0(0x20, 0x166, 7, 1);
4325 write_1d0(0x0, 0xeb, 3, 1);
4326 write_1d0(0x0, 0xf3, 6, 1);
4327
4328 for (channel = 0; channel < NUM_CHANNELS; channel++)
4329 for (lane = 0; lane < 9; lane++) {
4330 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4331 u8 a;
4332 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4333 write_500(&info, channel, a, addr, 6, 1);
4334 }
4335
4336 udelay(1000);
4337
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004338 if (s3resume) {
4339 if (info.cached_training == NULL) {
4340 u32 reg32;
4341 printk(BIOS_ERR,
4342 "Couldn't find training data. Rebooting\n");
4343 reg32 = inl(DEFAULT_PMBASE + 0x04);
4344 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4345 outb(0xe, 0xcf9);
Patrick Georgi546953c2014-11-29 10:38:17 +01004346 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004347 }
4348 int tm;
4349 info.training = *info.cached_training;
4350 for (tm = 0; tm < 4; tm++)
4351 for (channel = 0; channel < NUM_CHANNELS; channel++)
4352 for (slot = 0; slot < NUM_SLOTS; slot++)
4353 for (rank = 0; rank < NUM_RANKS; rank++)
4354 for (lane = 0; lane < 9; lane++)
4355 write_500(&info,
4356 channel,
4357 info.training.
4358 lane_timings
4359 [tm][channel]
4360 [slot][rank]
4361 [lane],
4362 get_timing_register_addr
4363 (lane, tm,
4364 slot, rank),
4365 9, 0);
4366 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4367 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4368 }
4369
Felix Heldf83d80b2018-07-29 05:30:30 +02004370 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004371 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004372 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
4373 tmp8 = MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004374
4375 program_board_delay(&info);
4376
Felix Held04be2dd2018-07-29 04:53:22 +02004377 MCHBAR8(0x5ff) = 0x0;
4378 MCHBAR8(0x5ff) = 0x80;
4379 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004380
Felix Held04be2dd2018-07-29 04:53:22 +02004381 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004382 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004383 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004384 gav(read_1d0(0x14b, 7)); // = 0x81023100
4385 write_1d0(0x30, 0x14b, 7, 1);
4386 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4387 write_1d0(7, 0xd6, 6, 1);
4388 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4389 write_1d0(7, 0x328, 6, 1);
4390
4391 for (channel = 0; channel < NUM_CHANNELS; channel++)
4392 set_4cf(&info, channel,
4393 info.populated_ranks[channel][0][0] ? 8 : 0);
4394
4395 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4396 write_1d0(2, 0x116, 4, 1);
4397 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4398 write_1d0(0, 0xae, 6, 1);
4399 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4400 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004401 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4402 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004403 MCHBAR32_AND(0x140, ~0x07000000);
4404 MCHBAR32_AND(0x138, ~0x07000000);
4405 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004406 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004407 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004408 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004409
4410 {
4411 u32 t;
4412 u8 val_a1;
4413 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4414 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4415 rmw_1d0(0x320, 0x07,
4416 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4417 rmw_1d0(0x14b, 0x78,
4418 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4419 4), 7,
4420 1);
4421 rmw_1d0(0xce, 0x38,
4422 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4423 4), 6,
4424 1);
4425 }
4426
4427 for (channel = 0; channel < NUM_CHANNELS; channel++)
4428 set_4cf(&info, channel,
4429 info.populated_ranks[channel][0][0] ? 9 : 1);
4430
4431 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Felix Heldf83d80b2018-07-29 05:30:30 +02004432 tmp32 = MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004433 write_1d0(2, 0xae, 6, 1);
4434 write_1d0(2, 0x300, 6, 1);
4435 write_1d0(2, 0x121, 3, 1);
4436 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4437 write_1d0(4, 0xd6, 6, 1);
4438 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4439 write_1d0(4, 0x328, 6, 1);
4440
4441 for (channel = 0; channel < NUM_CHANNELS; channel++)
4442 set_4cf(&info, channel,
4443 info.populated_ranks[channel][0][0] ? 9 : 0);
4444
Felix Held04be2dd2018-07-29 04:53:22 +02004445 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4446 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004447 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004448 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004449 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4450 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4451 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4452 write_1d0(0, 0x21c, 6, 1);
4453 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4454 write_1d0(0x35, 0x14b, 7, 1);
4455
4456 for (channel = 0; channel < NUM_CHANNELS; channel++)
4457 set_4cf(&info, channel,
4458 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4459
4460 set_334(1);
4461
Felix Held04be2dd2018-07-29 04:53:22 +02004462 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004463
4464 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4465 write_500(&info, channel,
4466 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4467 1);
4468 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4469 }
Felix Held04be2dd2018-07-29 04:53:22 +02004470 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4471 MCHBAR16(0x6c0) = 0x14a0;
4472 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4473 MCHBAR16(0x232) = 0x8;
4474 /* 0x40004 or 0 depending on ? */
4475 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4476 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4477 MCHBAR32(0x128) = 0x2150d05;
4478 MCHBAR8(0x12c) = 0x1f;
4479 MCHBAR8(0x12d) = 0x56;
4480 MCHBAR8(0x12e) = 0x31;
4481 MCHBAR8(0x12f) = 0x0;
4482 MCHBAR8(0x271) = 0x2;
4483 MCHBAR8(0x671) = 0x2;
4484 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004485 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004486 MCHBAR32(0x294 + (channel << 10)) =
4487 (info.populated_ranks_mask[channel] & 3) << 16;
4488 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4489 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004490 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004491 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4492 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004493
4494 if (!s3resume)
4495 jedec_init(&info);
4496
4497 int totalrank = 0;
4498 for (channel = 0; channel < NUM_CHANNELS; channel++)
4499 for (slot = 0; slot < NUM_SLOTS; slot++)
4500 for (rank = 0; rank < NUM_RANKS; rank++)
4501 if (info.populated_ranks[channel][slot][rank]) {
4502 jedec_read(&info, channel, slot, rank,
4503 totalrank, 0xa, 0x400);
4504 totalrank++;
4505 }
4506
Felix Held04be2dd2018-07-29 04:53:22 +02004507 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004508
Felix Heldf83d80b2018-07-29 05:30:30 +02004509 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4510 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004511
4512 if (!s3resume) {
4513 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004514 MCHBAR32(0x294 + (channel << 10)) =
4515 (info.populated_ranks_mask[channel] & 3) << 16;
4516 MCHBAR16(0x298 + (channel << 10)) =
4517 info.populated_ranks[channel][0][0] |
4518 (info.populated_ranks[channel][0][1] << 5);
4519 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004520 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004521 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004522
4523 {
4524 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004525 a = MCHBAR8(0x243);
4526 b = MCHBAR8(0x643);
4527 MCHBAR8(0x243) = a | 2;
4528 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004529 }
4530
4531 write_1d0(7, 0x19b, 3, 1);
4532 write_1d0(7, 0x1c0, 3, 1);
4533 write_1d0(4, 0x1c6, 4, 1);
4534 write_1d0(4, 0x1cc, 4, 1);
4535 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4536 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004537 MCHBAR32(0x584) = 0xfffff;
4538 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004539
4540 for (channel = 0; channel < NUM_CHANNELS; channel++)
4541 for (slot = 0; slot < NUM_SLOTS; slot++)
4542 for (rank = 0; rank < NUM_RANKS; rank++)
4543 if (info.
4544 populated_ranks[channel][slot]
4545 [rank])
4546 config_rank(&info, s3resume,
4547 channel, slot,
4548 rank);
4549
Felix Held04be2dd2018-07-29 04:53:22 +02004550 MCHBAR8(0x243) = 0x1;
4551 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004552 }
4553
4554 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004555 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004556 write_26c(0, 0x820);
4557 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004558 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004559 /* end */
4560
4561 if (s3resume) {
4562 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004563 MCHBAR32(0x294 + (channel << 10)) =
4564 (info.populated_ranks_mask[channel] & 3) << 16;
4565 MCHBAR16(0x298 + (channel << 10)) =
4566 info.populated_ranks[channel][0][0] |
4567 (info.populated_ranks[channel][0][1] << 5);
4568 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004569 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004570 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004571 }
4572
Felix Held04be2dd2018-07-29 04:53:22 +02004573 MCHBAR32_AND(0xfa4, ~0x01000002);
4574 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004575
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004576 /* Before training. */
4577 timestamp_add_now(103);
4578
4579 if (!s3resume)
4580 ram_training(&info);
4581
4582 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004583 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004584
4585 dump_timings(&info);
4586
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004587 program_modules_memory_map(&info, 0);
4588 program_total_memory_map(&info);
4589
4590 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004591 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004592 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004593 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004594 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004595 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004596 else
Felix Held04be2dd2018-07-29 04:53:22 +02004597 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004598
Felix Held04be2dd2018-07-29 04:53:22 +02004599 MCHBAR32_AND(0xfac, ~0x80000000);
4600 MCHBAR32(0xfb4) = 0x4800;
4601 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4602 MCHBAR32(0xe94) = 0x7ffff;
4603 MCHBAR32(0xfc0) = 0x80002040;
4604 MCHBAR32(0xfc4) = 0x701246;
4605 MCHBAR8_AND(0xfc8, ~0x70);
4606 MCHBAR32_OR(0xe5c, 0x1000000);
4607 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4608 MCHBAR32(0x50) = 0x700b0;
4609 MCHBAR32(0x3c) = 0x10;
4610 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4611 MCHBAR8_OR(0xff4, 0x2);
4612 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004613
Felix Held29a9c072018-07-29 01:34:45 +02004614#if 1
Felix Held04be2dd2018-07-29 04:53:22 +02004615 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4616 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4617 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004618
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004619 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4620 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4621 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004622
4623#else
4624 {
4625 u32 eax;
Felix Held04be2dd2018-07-29 04:53:22 +02004626 // = 0xe911714b
4627 eax = read32p(0xffc + (MCHBAR32(0xd00) & ~1)) | 0x08000000;
4628 write32p(0xffc + (MCHBAR32(0xd00) & ~1), eax);
4629 // = 0xe911714b
4630 eax = read32p(0xffc + (MCHBAR32(0xdc0) & ~1)) | 0x40000000;
4631 write32p(0xffc + (MCHBAR32(0xdc0) & ~1), eax);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004632 }
4633#endif
4634
4635 {
4636 u32 eax;
4637
4638 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004639 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4640 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4641 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004642 }
4643
4644 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004645 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004646 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004647 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004648 else
Felix Held04be2dd2018-07-29 04:53:22 +02004649 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004650
Felix Held04be2dd2018-07-29 04:53:22 +02004651 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004652
Felix Held04be2dd2018-07-29 04:53:22 +02004653 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004654 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004655 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004656 else
Felix Held04be2dd2018-07-29 04:53:22 +02004657 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004658 }
4659
Felix Held04be2dd2018-07-29 04:53:22 +02004660 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004661
4662 {
4663 u8 al;
4664 al = 0xd;
4665 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4666 al += 2;
4667 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004668 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004669 }
4670
4671 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004672 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4673 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4674 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4675 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004676 }
4677 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004678 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004679 reg1c = read32p(DEFAULT_EPBAR | 0x01c); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004680 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004681 write32p(DEFAULT_EPBAR | 0x01c, reg1c); // OK
Felix Heldf83d80b2018-07-29 05:30:30 +02004682 tmp8 = MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004683 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004684 MCHBAR8_OR(0x1210, 2);
4685 MCHBAR32(0x1200) = 0x8800440;
4686 MCHBAR32(0x1204) = 0x53ff0453;
4687 MCHBAR32(0x1208) = 0x19002043;
4688 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004689
4690 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004691 MCHBAR16(0x1214) = 0x220;
4692 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004693 }
4694
Felix Held04be2dd2018-07-29 04:53:22 +02004695 MCHBAR8_OR(0x1214, 0x4);
4696 MCHBAR8(0x120c) = 0x1;
4697 MCHBAR8(0x1218) = 0x3;
4698 MCHBAR8(0x121a) = 0x3;
4699 MCHBAR8(0x121c) = 0x3;
4700 MCHBAR16(0xc14) = 0x0;
4701 MCHBAR16(0xc20) = 0x0;
4702 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004703
4704 /* revision dependent here. */
4705
Felix Held04be2dd2018-07-29 04:53:22 +02004706 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004707
4708 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004709 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004710
Felix Held04be2dd2018-07-29 04:53:22 +02004711 MCHBAR16_OR(0x1230, 0x8000);
4712 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004713
4714 u8 bl, ebpb;
4715 u16 reg_1020;
4716
Felix Held04be2dd2018-07-29 04:53:22 +02004717 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4718 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004719
Felix Held04be2dd2018-07-29 04:53:22 +02004720 MCHBAR32(0x1000) = 0x100;
4721 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004722
4723 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004724 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004725 bl = reg_1020 >> 8;
4726 ebpb = reg_1020 & 0xff;
4727 } else {
4728 ebpb = 0;
4729 bl = 8;
4730 }
4731
4732 rdmsr(0x1a2);
4733
Felix Held04be2dd2018-07-29 04:53:22 +02004734 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004735
Felix Held04be2dd2018-07-29 04:53:22 +02004736 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004737
Felix Held04be2dd2018-07-29 04:53:22 +02004738 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004739
Felix Held04be2dd2018-07-29 04:53:22 +02004740 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004741 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004742 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4743 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004744 }
4745
4746 setup_heci_uma(&info);
4747
4748 if (info.uma_enabled) {
4749 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004750 MCHBAR32_OR(0x11b0, 0x4000);
4751 MCHBAR32_OR(0x11b4, 0x4000);
4752 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004753
Felix Held04be2dd2018-07-29 04:53:22 +02004754 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4755 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4756 MCHBAR16_OR(0x1170, 0x1000);
4757
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004758 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004759
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004760 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004761 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004762 ;
4763 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004764 }
4765
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004766 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4767 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004768 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004769 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004770
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004771 udelay(1000);
4772 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004773 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4774
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004775 if (!s3resume)
4776 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004777 if (s3resume && cbmem_wasnot_inited) {
4778 u32 reg32;
4779 printk(BIOS_ERR, "Failed S3 resume.\n");
4780 ram_check(0x100000, 0x200000);
4781
4782 /* Clear SLP_TYPE. */
4783 reg32 = inl(DEFAULT_PMBASE + 0x04);
4784 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4785
4786 /* Failed S3 resume, reset to come up cleanly */
4787 outb(0xe, 0xcf9);
Patrick Georgi546953c2014-11-29 10:38:17 +01004788 halt();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004789 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004790}