blob: b4ff85cdd40b9a0a5faa94accba2e9dc6d4d357b [file] [log] [blame]
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013 Vladimir Serbinenko.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010015 */
16
Kyösti Mälkki931c1dc2014-06-30 09:40:19 +030017#include <stdlib.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010018#include <console/console.h>
19#include <string.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010020#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020021#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020022#include <device/pci_ops.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010023#include <cpu/x86/msr.h>
24#include <cbmem.h>
Elyes HAOUASd45f3382019-04-28 18:04:35 +020025#include <cf9_reset.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010026#include <arch/cbfs.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010027#include <ip_checksum.h>
28#include <pc80/mc146818rtc.h>
29#include <device/pci_def.h>
Patrick Rudolph266a1f72016-06-09 18:13:34 +020030#include <device/device.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010031#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010032#include <spd.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010033#include <timestamp.h>
34#include <cpu/x86/mtrr.h>
35#include <cpu/intel/speedstep.h>
36#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010037#include <mrc_cache.h>
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020038#include <southbridge/intel/ibexpeak/me.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010039#include <delay.h>
Elyes HAOUAS51401c32019-05-15 21:09:30 +020040#include <types.h>
41
42#include "chip.h"
43#include "nehalem.h"
44#include "raminit.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010045
46#define NORTHBRIDGE PCI_DEV(0, 0, 0)
47#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
48#define GMA PCI_DEV (0, 0x2, 0x0)
49#define HECIDEV PCI_DEV(0, 0x16, 0)
50#define HECIBAR 0x10
51
52#define FOR_ALL_RANKS \
53 for (channel = 0; channel < NUM_CHANNELS; channel++) \
54 for (slot = 0; slot < NUM_SLOTS; slot++) \
55 for (rank = 0; rank < NUM_RANKS; rank++)
56
57#define FOR_POPULATED_RANKS \
58 for (channel = 0; channel < NUM_CHANNELS; channel++) \
59 for (slot = 0; slot < NUM_SLOTS; slot++) \
60 for (rank = 0; rank < NUM_RANKS; rank++) \
61 if (info->populated_ranks[channel][slot][rank])
62
63#define FOR_POPULATED_RANKS_BACKWARDS \
64 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
65 for (slot = 0; slot < NUM_SLOTS; slot++) \
66 for (rank = 0; rank < NUM_RANKS; rank++) \
67 if (info->populated_ranks[channel][slot][rank])
68
69/* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */
70typedef struct {
71 u8 smallest;
72 u8 largest;
73} timing_bounds_t[2][2][2][9];
74
Arthur Heymansdc71e252018-01-29 10:14:48 +010075#define MRC_CACHE_VERSION 1
76
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010077struct ram_training {
78 /* [TM][CHANNEL][SLOT][RANK][LANE] */
79 u16 lane_timings[4][2][2][2][9];
80 u16 reg_178;
81 u16 reg_10b;
82
83 u8 reg178_center;
84 u8 reg178_smallest;
85 u8 reg178_largest;
86 timing_bounds_t timing_bounds[2];
87 u16 timing_offset[2][2][2][9];
88 u16 timing2_offset[2][2][2][9];
89 u16 timing2_bounds[2][2][2][9][2];
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +010090 u8 reg274265[2][3]; /* [CHANNEL][REGISTER] */
91 u8 reg2ca9_bit0;
92 u32 reg_6dc;
93 u32 reg_6e8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010094};
95
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010096#include <lib.h> /* Prototypes */
97
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010098
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010099static void clflush(u32 addr)
100{
101 asm volatile ("clflush (%0)"::"r" (addr));
102}
103
104typedef struct _u128 {
105 u64 lo;
106 u64 hi;
107} u128;
108
109static void read128(u32 addr, u64 * out)
110{
111 u128 ret;
112 u128 stor;
113 asm volatile ("movdqu %%xmm0, %0\n"
114 "movdqa (%2), %%xmm0\n"
115 "movdqu %%xmm0, %1\n"
116 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
117 out[0] = ret.lo;
118 out[1] = ret.hi;
119}
120
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100121/* OK */
122static void write_1d0(u32 val, u16 addr, int bits, int flag)
123{
Felix Held04be2dd2018-07-29 04:53:22 +0200124 MCHBAR32(0x1d0) = 0;
125 while (MCHBAR32(0x1d0) & 0x800000)
126 ;
127 MCHBAR32(0x1d4) =
128 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
129 MCHBAR32(0x1d0) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200130 while (MCHBAR32(0x1d0) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200131 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100132}
133
134/* OK */
135static u16 read_1d0(u16 addr, int split)
136{
137 u32 val;
Felix Held04be2dd2018-07-29 04:53:22 +0200138 MCHBAR32(0x1d0) = 0;
139 while (MCHBAR32(0x1d0) & 0x800000)
140 ;
141 MCHBAR32(0x1d0) =
142 0x80000000 | (((MCHBAR8(0x246) >> 2) & 3) + 0x361 - addr);
143 while (MCHBAR32(0x1d0) & 0x800000)
144 ;
145 val = MCHBAR32(0x1d8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100146 write_1d0(0, 0x33d, 0, 0);
147 write_1d0(0, 0x33d, 0, 0);
148 val &= ((1 << split) - 1);
149 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
150 return val;
151}
152
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800153static void write32p(uintptr_t addr, uint32_t val)
154{
155 write32((void *)addr, val);
156}
157
158static uint32_t read32p(uintptr_t addr)
159{
160 return read32((void *)addr);
161}
162
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100163static void sfence(void)
164{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100165 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100166}
167
168static inline u16 get_lane_offset(int slot, int rank, int lane)
169{
170 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
171 0x452 * (lane == 8);
172}
173
174static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
175{
176 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
177 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
178}
179
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100180static u32 gav_real(int line, u32 in)
181{
182 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
183 return in;
184}
185
186#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200187
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100188struct raminfo {
189 u16 clock_speed_index; /* clock_speed (REAL, not DDR) / 133.(3) - 3 */
190 u16 fsb_frequency; /* in 1.(1)/2 MHz. */
191 u8 is_x16_module[2][2]; /* [CHANNEL][SLOT] */
192 u8 density[2][2]; /* [CHANNEL][SLOT] */
193 u8 populated_ranks[2][2][2]; /* [CHANNEL][SLOT][RANK] */
194 int rank_start[2][2][2];
195 u8 cas_latency;
196 u8 board_lane_delay[9];
197 u8 use_ecc;
198 u8 revision;
199 u8 max_supported_clock_speed_index;
200 u8 uma_enabled;
201 u8 spd[2][2][151]; /* [CHANNEL][SLOT][BYTE] */
202 u8 silicon_revision;
203 u8 populated_ranks_mask[2];
204 u8 max_slots_used_in_channel;
205 u8 mode4030[2];
206 u16 avg4044[2];
207 u16 max4048[2];
208 unsigned total_memory_mb;
209 unsigned interleaved_part_mb;
210 unsigned non_interleaved_part_mb;
211
212 u32 heci_bar;
213 u64 heci_uma_addr;
214 unsigned memory_reserved_for_heci_mb;
215
216 struct ram_training training;
217 u32 last_500_command[2];
218
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100219 u32 delay46_ps[2];
220 u32 delay54_ps[2];
221 u8 revision_flag_1;
222 u8 some_delay_1_cycle_floor;
223 u8 some_delay_2_halfcycles_ceil;
224 u8 some_delay_3_ps_rounded;
225
226 const struct ram_training *cached_training;
227};
228
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200229/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100230timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200231
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100232static void
233write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
234 int flag);
235
236/* OK */
237static u16
238read_500(struct raminfo *info, int channel, u16 addr, int split)
239{
240 u32 val;
241 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200242 MCHBAR32(0x500 + (channel << 10)) = 0;
243 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
244 ;
245 MCHBAR32(0x500 + (channel << 10)) =
246 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
247 + 0xb88 - addr);
248 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
249 ;
250 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100251 return val & ((1 << split) - 1);
252}
253
254/* OK */
255static void
256write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
257 int flag)
258{
259 if (info->last_500_command[channel] == 0x80000000) {
260 info->last_500_command[channel] = 0x40000000;
261 write_500(info, channel, 0, 0xb61, 0, 0);
262 }
Felix Held04be2dd2018-07-29 04:53:22 +0200263 MCHBAR32(0x500 + (channel << 10)) = 0;
264 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
265 ;
266 MCHBAR32(0x504 + (channel << 10)) =
267 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
268 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200269 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200270 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100271}
272
273static int rw_test(int rank)
274{
275 const u32 mask = 0xf00fc33c;
276 int ok = 0xff;
277 int i;
278 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800279 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100280 sfence();
281 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800282 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100283 sfence();
284 for (i = 0; i < 32; i++) {
285 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800286 write32p((rank << 28) | (i << 3), pat);
287 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100288 }
289 sfence();
290 for (i = 0; i < 32; i++) {
291 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
292 int j;
293 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800294 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100295 for (j = 0; j < 4; j++)
296 if (((val >> (j * 8)) & 0xff) != pat)
297 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800298 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100299 for (j = 0; j < 4; j++)
300 if (((val >> (j * 8)) & 0xff) != pat)
301 ok &= ~(16 << j);
302 }
303 sfence();
304 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800305 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100306 sfence();
307 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800308 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100309
310 return ok;
311}
312
313static void
314program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
315{
316 int lane;
317 for (lane = 0; lane < 8; lane++) {
318 write_500(info, channel,
319 base +
320 info->training.
321 lane_timings[2][channel][slot][rank][lane],
322 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
323 write_500(info, channel,
324 base +
325 info->training.
326 lane_timings[3][channel][slot][rank][lane],
327 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
328 }
329}
330
331static void write_26c(int channel, u16 si)
332{
Felix Held04be2dd2018-07-29 04:53:22 +0200333 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
334 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
335 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100336}
337
338static u32 get_580(int channel, u8 addr)
339{
340 u32 ret;
341 gav(read_1d0(0x142, 3));
Felix Held04be2dd2018-07-29 04:53:22 +0200342 MCHBAR8(0x5ff) = 0x0;
343 MCHBAR8(0x5ff) = 0x80;
344 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
345 MCHBAR8_OR(0x580 + (channel << 10), 1);
346 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
347 ;
348 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100349 return ret;
350}
351
352const int cached_config = 0;
353
354#define NUM_CHANNELS 2
355#define NUM_SLOTS 2
356#define NUM_RANKS 2
357#define RANK_SHIFT 28
358#define CHANNEL_SHIFT 10
359
360#include "raminit_tables.c"
361
362static void seq9(struct raminfo *info, int channel, int slot, int rank)
363{
364 int i, lane;
365
366 for (i = 0; i < 2; i++)
367 for (lane = 0; lane < 8; lane++)
368 write_500(info, channel,
369 info->training.lane_timings[i +
370 1][channel][slot]
371 [rank][lane], get_timing_register_addr(lane,
372 i + 1,
373 slot,
374 rank),
375 9, 0);
376
377 write_1d0(1, 0x103, 6, 1);
378 for (lane = 0; lane < 8; lane++)
379 write_500(info, channel,
380 info->training.
381 lane_timings[0][channel][slot][rank][lane],
382 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
383
384 for (i = 0; i < 2; i++) {
385 for (lane = 0; lane < 8; lane++)
386 write_500(info, channel,
387 info->training.lane_timings[i +
388 1][channel][slot]
389 [rank][lane], get_timing_register_addr(lane,
390 i + 1,
391 slot,
392 rank),
393 9, 0);
394 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
395 }
396
397 gav(read_1d0(0x142, 3)); // = 0x10408118
Felix Held04be2dd2018-07-29 04:53:22 +0200398 MCHBAR8(0x5ff) = 0x0;
399 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100400 write_1d0(0x2, 0x142, 3, 1);
401 for (lane = 0; lane < 8; lane++) {
402 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
403 info->training.lane_timings[2][channel][slot][rank][lane] =
404 read_500(info, channel,
405 get_timing_register_addr(lane, 2, slot, rank), 9);
406 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
407 info->training.lane_timings[3][channel][slot][rank][lane] =
408 info->training.lane_timings[2][channel][slot][rank][lane] +
409 0x20;
410 }
411}
412
413static int count_ranks_in_channel(struct raminfo *info, int channel)
414{
415 int slot, rank;
416 int res = 0;
417 for (slot = 0; slot < NUM_SLOTS; slot++)
418 for (rank = 0; rank < NUM_SLOTS; rank++)
419 res += info->populated_ranks[channel][slot][rank];
420 return res;
421}
422
423static void
424config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
425{
426 int add;
427
428 write_1d0(0, 0x178, 7, 1);
429 seq9(info, channel, slot, rank);
430 program_timings(info, 0x80, channel, slot, rank);
431
432 if (channel == 0)
433 add = count_ranks_in_channel(info, 1);
434 else
435 add = 0;
436 if (!s3resume)
437 gav(rw_test(rank + add));
438 program_timings(info, 0x00, channel, slot, rank);
439 if (!s3resume)
440 gav(rw_test(rank + add));
441 if (!s3resume)
442 gav(rw_test(rank + add));
443 write_1d0(0, 0x142, 3, 1);
444 write_1d0(0, 0x103, 6, 1);
445
446 gav(get_580(channel, 0xc | (rank << 5)));
447 gav(read_1d0(0x142, 3));
448
Felix Held04be2dd2018-07-29 04:53:22 +0200449 MCHBAR8(0x5ff) = 0x0;
450 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100451}
452
453static void set_4cf(struct raminfo *info, int channel, u8 val)
454{
455 gav(read_500(info, channel, 0x4cf, 4)); // = 0xc2300cf9
456 write_500(info, channel, val, 0x4cf, 4, 1);
457 gav(read_500(info, channel, 0x659, 4)); // = 0x80300839
458 write_500(info, channel, val, 0x659, 4, 1);
459 gav(read_500(info, channel, 0x697, 4)); // = 0x80300839
460 write_500(info, channel, val, 0x697, 4, 1);
461}
462
463static void set_334(int zero)
464{
465 int j, k, channel;
466 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
467 u32 vd8[2][16];
468
469 for (channel = 0; channel < NUM_CHANNELS; channel++) {
470 for (j = 0; j < 4; j++) {
471 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
472 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
473 u16 c;
474 if ((j == 0 || j == 3) && zero)
475 c = 0;
476 else if (j == 3)
477 c = 0x5f;
478 else
479 c = 0x5f5f;
480
481 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200482 MCHBAR32(0x138 + 8 * k) =
483 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100484 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200485 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100486 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200487 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100488 }
489
Felix Held22ca8cb2018-07-29 05:09:44 +0200490 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
491 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200492 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
493 zero ? 0 : (0x18191819 & lmask);
494 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
495 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
496 zero ? 0 : (a & lmask);
497 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
498 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100499 }
500 }
501
Felix Held04be2dd2018-07-29 04:53:22 +0200502 MCHBAR32_OR(0x130, 1);
503 while (MCHBAR8(0x130) & 1)
504 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100505}
506
507static void rmw_1d0(u16 addr, u32 and, u32 or, int split, int flag)
508{
509 u32 v;
510 v = read_1d0(addr, split);
511 write_1d0((v & and) | or, addr, split, flag);
512}
513
514static int find_highest_bit_set(u16 val)
515{
516 int i;
517 for (i = 15; i >= 0; i--)
518 if (val & (1 << i))
519 return i;
520 return -1;
521}
522
523static int find_lowest_bit_set32(u32 val)
524{
525 int i;
526 for (i = 0; i < 32; i++)
527 if (val & (1 << i))
528 return i;
529 return -1;
530}
531
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100532enum {
533 DEVICE_TYPE = 2,
534 MODULE_TYPE = 3,
535 DENSITY = 4,
536 RANKS_AND_DQ = 7,
537 MEMORY_BUS_WIDTH = 8,
538 TIMEBASE_DIVIDEND = 10,
539 TIMEBASE_DIVISOR = 11,
540 CYCLETIME = 12,
541
542 CAS_LATENCIES_LSB = 14,
543 CAS_LATENCIES_MSB = 15,
544 CAS_LATENCY_TIME = 16,
545 THERMAL_AND_REFRESH = 31,
546 REFERENCE_RAW_CARD_USED = 62,
547 RANK1_ADDRESS_MAPPING = 63
548};
549
550static void calculate_timings(struct raminfo *info)
551{
552 unsigned cycletime;
553 unsigned cas_latency_time;
554 unsigned supported_cas_latencies;
555 unsigned channel, slot;
556 unsigned clock_speed_index;
557 unsigned min_cas_latency;
558 unsigned cas_latency;
559 unsigned max_clock_index;
560
561 /* Find common CAS latency */
562 supported_cas_latencies = 0x3fe;
563 for (channel = 0; channel < NUM_CHANNELS; channel++)
564 for (slot = 0; slot < NUM_SLOTS; slot++)
565 if (info->populated_ranks[channel][slot][0])
566 supported_cas_latencies &=
567 2 *
568 (info->
569 spd[channel][slot][CAS_LATENCIES_LSB] |
570 (info->
571 spd[channel][slot][CAS_LATENCIES_MSB] <<
572 8));
573
574 max_clock_index = min(3, info->max_supported_clock_speed_index);
575
576 cycletime = min_cycletime[max_clock_index];
577 cas_latency_time = min_cas_latency_time[max_clock_index];
578
579 for (channel = 0; channel < NUM_CHANNELS; channel++)
580 for (slot = 0; slot < NUM_SLOTS; slot++)
581 if (info->populated_ranks[channel][slot][0]) {
582 unsigned timebase;
583 timebase =
584 1000 *
585 info->
586 spd[channel][slot][TIMEBASE_DIVIDEND] /
587 info->spd[channel][slot][TIMEBASE_DIVISOR];
588 cycletime =
589 max(cycletime,
590 timebase *
591 info->spd[channel][slot][CYCLETIME]);
592 cas_latency_time =
593 max(cas_latency_time,
594 timebase *
595 info->
596 spd[channel][slot][CAS_LATENCY_TIME]);
597 }
598 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
599 if (cycletime == min_cycletime[clock_speed_index])
600 break;
601 if (cycletime > min_cycletime[clock_speed_index]) {
602 clock_speed_index--;
603 cycletime = min_cycletime[clock_speed_index];
604 break;
605 }
606 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100607 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100608 cas_latency = 0;
609 while (supported_cas_latencies) {
610 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
611 if (cas_latency <= min_cas_latency)
612 break;
613 supported_cas_latencies &=
614 ~(1 << find_highest_bit_set(supported_cas_latencies));
615 }
616
617 if (cas_latency != min_cas_latency && clock_speed_index)
618 clock_speed_index--;
619
620 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
621 die("Couldn't configure DRAM");
622 info->clock_speed_index = clock_speed_index;
623 info->cas_latency = cas_latency;
624}
625
626static void program_base_timings(struct raminfo *info)
627{
628 unsigned channel;
629 unsigned slot, rank, lane;
630 unsigned extended_silicon_revision;
631 int i;
632
633 extended_silicon_revision = info->silicon_revision;
634 if (info->silicon_revision == 0)
635 for (channel = 0; channel < NUM_CHANNELS; channel++)
636 for (slot = 0; slot < NUM_SLOTS; slot++)
637 if ((info->
638 spd[channel][slot][MODULE_TYPE] & 0xF) ==
639 3)
640 extended_silicon_revision = 4;
641
642 for (channel = 0; channel < NUM_CHANNELS; channel++) {
643 for (slot = 0; slot < NUM_SLOTS; slot++)
644 for (rank = 0; rank < NUM_SLOTS; rank++) {
645 int card_timing_2;
646 if (!info->populated_ranks[channel][slot][rank])
647 continue;
648
649 for (lane = 0; lane < 9; lane++) {
650 int tm_reg;
651 int card_timing;
652
653 card_timing = 0;
654 if ((info->
655 spd[channel][slot][MODULE_TYPE] &
656 0xF) == 3) {
657 int reference_card;
658 reference_card =
659 info->
660 spd[channel][slot]
661 [REFERENCE_RAW_CARD_USED] &
662 0x1f;
663 if (reference_card == 3)
664 card_timing =
665 u16_ffd1188[0][lane]
666 [info->
667 clock_speed_index];
668 if (reference_card == 5)
669 card_timing =
670 u16_ffd1188[1][lane]
671 [info->
672 clock_speed_index];
673 }
674
675 info->training.
676 lane_timings[0][channel][slot][rank]
677 [lane] =
678 u8_FFFD1218[info->
679 clock_speed_index];
680 info->training.
681 lane_timings[1][channel][slot][rank]
682 [lane] = 256;
683
684 for (tm_reg = 2; tm_reg < 4; tm_reg++)
685 info->training.
686 lane_timings[tm_reg]
687 [channel][slot][rank][lane]
688 =
689 u8_FFFD1240[channel]
690 [extended_silicon_revision]
691 [lane][2 * slot +
692 rank][info->
693 clock_speed_index]
694 + info->max4048[channel]
695 +
696 u8_FFFD0C78[channel]
697 [extended_silicon_revision]
698 [info->
699 mode4030[channel]][slot]
700 [rank][info->
701 clock_speed_index]
702 + card_timing;
703 for (tm_reg = 0; tm_reg < 4; tm_reg++)
704 write_500(info, channel,
705 info->training.
706 lane_timings[tm_reg]
707 [channel][slot][rank]
708 [lane],
709 get_timing_register_addr
710 (lane, tm_reg, slot,
711 rank), 9, 0);
712 }
713
714 card_timing_2 = 0;
715 if (!(extended_silicon_revision != 4
716 || (info->
717 populated_ranks_mask[channel] & 5) ==
718 5)) {
719 if ((info->
720 spd[channel][slot]
721 [REFERENCE_RAW_CARD_USED] & 0x1F)
722 == 3)
723 card_timing_2 =
724 u16_FFFE0EB8[0][info->
725 clock_speed_index];
726 if ((info->
727 spd[channel][slot]
728 [REFERENCE_RAW_CARD_USED] & 0x1F)
729 == 5)
730 card_timing_2 =
731 u16_FFFE0EB8[1][info->
732 clock_speed_index];
733 }
734
735 for (i = 0; i < 3; i++)
736 write_500(info, channel,
737 (card_timing_2 +
738 info->max4048[channel]
739 +
740 u8_FFFD0EF8[channel]
741 [extended_silicon_revision]
742 [info->
743 mode4030[channel]][info->
744 clock_speed_index]),
745 u16_fffd0c50[i][slot][rank],
746 8, 1);
747 write_500(info, channel,
748 (info->max4048[channel] +
749 u8_FFFD0C78[channel]
750 [extended_silicon_revision][info->
751 mode4030
752 [channel]]
753 [slot][rank][info->
754 clock_speed_index]),
755 u16_fffd0c70[slot][rank], 7, 1);
756 }
757 if (!info->populated_ranks_mask[channel])
758 continue;
759 for (i = 0; i < 3; i++)
760 write_500(info, channel,
761 (info->max4048[channel] +
762 info->avg4044[channel]
763 +
764 u8_FFFD17E0[channel]
765 [extended_silicon_revision][info->
766 mode4030
767 [channel]][info->
768 clock_speed_index]),
769 u16_fffd0c68[i], 8, 1);
770 }
771}
772
773static unsigned int fsbcycle_ps(struct raminfo *info)
774{
775 return 900000 / info->fsb_frequency;
776}
777
778/* The time of DDR transfer in ps. */
779static unsigned int halfcycle_ps(struct raminfo *info)
780{
781 return 3750 / (info->clock_speed_index + 3);
782}
783
784/* The time of clock cycle in ps. */
785static unsigned int cycle_ps(struct raminfo *info)
786{
787 return 2 * halfcycle_ps(info);
788}
789
790/* Frequency in 1.(1)=10/9 MHz units. */
791static unsigned frequency_11(struct raminfo *info)
792{
793 return (info->clock_speed_index + 3) * 120;
794}
795
796/* Frequency in 0.1 MHz units. */
797static unsigned frequency_01(struct raminfo *info)
798{
799 return 100 * frequency_11(info) / 9;
800}
801
802static unsigned ps_to_halfcycles(struct raminfo *info, unsigned int ps)
803{
804 return (frequency_11(info) * 2) * ps / 900000;
805}
806
807static unsigned ns_to_cycles(struct raminfo *info, unsigned int ns)
808{
809 return (frequency_11(info)) * ns / 900;
810}
811
812static void compute_derived_timings(struct raminfo *info)
813{
814 unsigned channel, slot, rank;
815 int extended_silicon_revision;
816 int some_delay_1_ps;
817 int some_delay_2_ps;
818 int some_delay_2_halfcycles_ceil;
819 int some_delay_2_halfcycles_floor;
820 int some_delay_3_ps;
821 int some_delay_3_halfcycles;
822 int some_delay_3_ps_rounded;
823 int some_delay_1_cycle_ceil;
824 int some_delay_1_cycle_floor;
825
826 some_delay_3_halfcycles = 0;
827 some_delay_3_ps_rounded = 0;
828 extended_silicon_revision = info->silicon_revision;
829 if (!info->silicon_revision)
830 for (channel = 0; channel < NUM_CHANNELS; channel++)
831 for (slot = 0; slot < NUM_SLOTS; slot++)
832 if ((info->
833 spd[channel][slot][MODULE_TYPE] & 0xF) ==
834 3)
835 extended_silicon_revision = 4;
836 if (info->board_lane_delay[7] < 5)
837 info->board_lane_delay[7] = 5;
838 info->revision_flag_1 = 2;
839 if (info->silicon_revision == 2 || info->silicon_revision == 3)
840 info->revision_flag_1 = 0;
841 if (info->revision < 16)
842 info->revision_flag_1 = 0;
843
844 if (info->revision < 8)
845 info->revision_flag_1 = 0;
846 if (info->revision >= 8 && (info->silicon_revision == 0
847 || info->silicon_revision == 1))
848 some_delay_2_ps = 735;
849 else
850 some_delay_2_ps = 750;
851
852 if (info->revision >= 0x10 && (info->silicon_revision == 0
853 || info->silicon_revision == 1))
854 some_delay_1_ps = 3929;
855 else
856 some_delay_1_ps = 3490;
857
858 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
859 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
860 if (some_delay_1_ps % cycle_ps(info))
861 some_delay_1_cycle_ceil++;
862 else
863 some_delay_1_cycle_floor--;
864 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
865 if (info->revision_flag_1)
866 some_delay_2_ps = halfcycle_ps(info) >> 6;
867 some_delay_2_ps +=
868 max(some_delay_1_ps - 30,
869 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
870 375;
871 some_delay_3_ps =
872 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
873 if (info->revision_flag_1) {
874 if (some_delay_3_ps < 150)
875 some_delay_3_halfcycles = 0;
876 else
877 some_delay_3_halfcycles =
878 (some_delay_3_ps << 6) / halfcycle_ps(info);
879 some_delay_3_ps_rounded =
880 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
881 }
882 some_delay_2_halfcycles_ceil =
883 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
884 2 * (some_delay_1_cycle_ceil - 1);
885 if (info->revision_flag_1 && some_delay_3_ps < 150)
886 some_delay_2_halfcycles_ceil++;
887 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
888 if (info->revision < 0x10)
889 some_delay_2_halfcycles_floor =
890 some_delay_2_halfcycles_ceil - 1;
891 if (!info->revision_flag_1)
892 some_delay_2_halfcycles_floor++;
893 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
894 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
895 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
896 || (info->populated_ranks[1][0][0]
897 && info->populated_ranks[1][1][0]))
898 info->max_slots_used_in_channel = 2;
899 else
900 info->max_slots_used_in_channel = 1;
901 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200902 MCHBAR32(0x244 + (channel << 10)) =
903 ((info->revision < 8) ? 1 : 0x200) |
904 ((2 - info->max_slots_used_in_channel) << 17) |
905 (channel << 21) |
906 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100907 if (info->max_slots_used_in_channel == 1) {
908 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
909 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
910 } else {
911 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 */
912 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
913 || (count_ranks_in_channel(info, 1) ==
914 2)) ? 2 : 3;
915 }
916 for (channel = 0; channel < NUM_CHANNELS; channel++) {
917 int max_of_unk;
918 int min_of_unk_2;
919
920 int i, count;
921 int sum;
922
923 if (!info->populated_ranks_mask[channel])
924 continue;
925
926 max_of_unk = 0;
927 min_of_unk_2 = 32767;
928
929 sum = 0;
930 count = 0;
931 for (i = 0; i < 3; i++) {
932 int unk1;
933 if (info->revision < 8)
934 unk1 =
935 u8_FFFD1891[0][channel][info->
936 clock_speed_index]
937 [i];
938 else if (!
939 (info->revision >= 0x10
940 || info->revision_flag_1))
941 unk1 =
942 u8_FFFD1891[1][channel][info->
943 clock_speed_index]
944 [i];
945 else
946 unk1 = 0;
947 for (slot = 0; slot < NUM_SLOTS; slot++)
948 for (rank = 0; rank < NUM_RANKS; rank++) {
949 int a = 0;
950 int b = 0;
951
952 if (!info->
953 populated_ranks[channel][slot]
954 [rank])
955 continue;
956 if (extended_silicon_revision == 4
957 && (info->
958 populated_ranks_mask[channel] &
959 5) != 5) {
960 if ((info->
961 spd[channel][slot]
962 [REFERENCE_RAW_CARD_USED] &
963 0x1F) == 3) {
964 a = u16_ffd1178[0]
965 [info->
966 clock_speed_index];
967 b = u16_fe0eb8[0][info->
968 clock_speed_index];
969 } else
970 if ((info->
971 spd[channel][slot]
972 [REFERENCE_RAW_CARD_USED]
973 & 0x1F) == 5) {
974 a = u16_ffd1178[1]
975 [info->
976 clock_speed_index];
977 b = u16_fe0eb8[1][info->
978 clock_speed_index];
979 }
980 }
981 min_of_unk_2 = min(min_of_unk_2, a);
982 min_of_unk_2 = min(min_of_unk_2, b);
983 if (rank == 0) {
984 sum += a;
985 count++;
986 }
987 {
988 int t;
989 t = b +
990 u8_FFFD0EF8[channel]
991 [extended_silicon_revision]
992 [info->
993 mode4030[channel]][info->
994 clock_speed_index];
995 if (unk1 >= t)
996 max_of_unk =
997 max(max_of_unk,
998 unk1 - t);
999 }
1000 }
1001 {
1002 int t =
1003 u8_FFFD17E0[channel]
1004 [extended_silicon_revision][info->
1005 mode4030
1006 [channel]]
1007 [info->clock_speed_index] + min_of_unk_2;
1008 if (unk1 >= t)
1009 max_of_unk = max(max_of_unk, unk1 - t);
1010 }
1011 }
1012
Jacob Garber64fb4a32019-06-10 17:29:18 -06001013 if (count == 0)
1014 die("No memory ranks found for channel %u\n", channel);
1015
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001016 info->avg4044[channel] = sum / count;
1017 info->max4048[channel] = max_of_unk;
1018 }
1019}
1020
1021static void jedec_read(struct raminfo *info,
1022 int channel, int slot, int rank,
1023 int total_rank, u8 addr3, unsigned int value)
1024{
1025 /* Handle mirrored mapping. */
1026 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001027 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1028 ((addr3 >> 1) & 0x10);
1029 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1030 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001031
1032 /* Handle mirrored mapping. */
1033 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1034 value =
1035 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1036 << 1);
1037
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001038 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001039
Felix Held04be2dd2018-07-29 04:53:22 +02001040 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1041 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001042
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001043 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001044}
1045
1046enum {
1047 MR1_RZQ12 = 512,
1048 MR1_RZQ2 = 64,
1049 MR1_RZQ4 = 4,
1050 MR1_ODS34OHM = 2
1051};
1052
1053enum {
1054 MR0_BT_INTERLEAVED = 8,
1055 MR0_DLL_RESET_ON = 256
1056};
1057
1058enum {
1059 MR2_RTT_WR_DISABLED = 0,
1060 MR2_RZQ2 = 1 << 10
1061};
1062
1063static void jedec_init(struct raminfo *info)
1064{
1065 int write_recovery;
1066 int channel, slot, rank;
1067 int total_rank;
1068 int dll_on;
1069 int self_refresh_temperature;
1070 int auto_self_refresh;
1071
1072 auto_self_refresh = 1;
1073 self_refresh_temperature = 1;
1074 if (info->board_lane_delay[3] <= 10) {
1075 if (info->board_lane_delay[3] <= 8)
1076 write_recovery = info->board_lane_delay[3] - 4;
1077 else
1078 write_recovery = 5;
1079 } else {
1080 write_recovery = 6;
1081 }
1082 FOR_POPULATED_RANKS {
1083 auto_self_refresh &=
1084 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1085 self_refresh_temperature &=
1086 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1087 }
1088 if (auto_self_refresh == 1)
1089 self_refresh_temperature = 0;
1090
1091 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1092 || (info->populated_ranks[0][0][0]
1093 && info->populated_ranks[0][1][0])
1094 || (info->populated_ranks[1][0][0]
1095 && info->populated_ranks[1][1][0]));
1096
1097 total_rank = 0;
1098
1099 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1100 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1101 int rzq_reg58e;
1102
1103 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1104 rzq_reg58e = 64;
1105 rtt = MR1_RZQ2;
1106 if (info->clock_speed_index != 0) {
1107 rzq_reg58e = 4;
1108 if (info->populated_ranks_mask[channel] == 3)
1109 rtt = MR1_RZQ4;
1110 }
1111 } else {
1112 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1113 rtt = MR1_RZQ12;
1114 rzq_reg58e = 64;
1115 rtt_wr = MR2_RZQ2;
1116 } else {
1117 rzq_reg58e = 4;
1118 rtt = MR1_RZQ4;
1119 }
1120 }
1121
Felix Held04be2dd2018-07-29 04:53:22 +02001122 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1123 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1124 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1125 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1126 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001127
1128 for (slot = 0; slot < NUM_SLOTS; slot++)
1129 for (rank = 0; rank < NUM_RANKS; rank++)
1130 if (info->populated_ranks[channel][slot][rank]) {
1131 jedec_read(info, channel, slot, rank,
1132 total_rank, 0x28,
1133 rtt_wr | (info->
1134 clock_speed_index
1135 << 3)
1136 | (auto_self_refresh << 6) |
1137 (self_refresh_temperature <<
1138 7));
1139 jedec_read(info, channel, slot, rank,
1140 total_rank, 0x38, 0);
1141 jedec_read(info, channel, slot, rank,
1142 total_rank, 0x18,
1143 rtt | MR1_ODS34OHM);
1144 jedec_read(info, channel, slot, rank,
1145 total_rank, 6,
1146 (dll_on << 12) |
1147 (write_recovery << 9)
1148 | ((info->cas_latency - 4) <<
1149 4) | MR0_BT_INTERLEAVED |
1150 MR0_DLL_RESET_ON);
1151 total_rank++;
1152 }
1153 }
1154}
1155
1156static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1157{
1158 unsigned channel, slot, rank;
1159 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1160 unsigned int channel_0_non_interleaved;
1161
1162 FOR_ALL_RANKS {
1163 if (info->populated_ranks[channel][slot][rank]) {
1164 total_mb[channel] +=
1165 pre_jedec ? 256 : (256 << info->
1166 density[channel][slot] >> info->
1167 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001168 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1169 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1170 (info->is_x16_module[channel][slot] |
1171 ((info->density[channel][slot] + 1) << 1))) |
1172 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001173 }
Felix Held04be2dd2018-07-29 04:53:22 +02001174 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1175 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001176 }
1177
1178 info->total_memory_mb = total_mb[0] + total_mb[1];
1179
1180 info->interleaved_part_mb =
1181 pre_jedec ? 0 : 2 * min(total_mb[0], total_mb[1]);
1182 info->non_interleaved_part_mb =
1183 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1184 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001185 MCHBAR32(0x100) = channel_0_non_interleaved |
1186 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001187 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001188 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001189}
1190
1191static void program_board_delay(struct raminfo *info)
1192{
1193 int cas_latency_shift;
1194 int some_delay_ns;
1195 int some_delay_3_half_cycles;
1196
1197 unsigned channel, i;
1198 int high_multiplier;
1199 int lane_3_delay;
1200 int cas_latency_derived;
1201
1202 high_multiplier = 0;
1203 some_delay_ns = 200;
1204 some_delay_3_half_cycles = 4;
1205 cas_latency_shift = info->silicon_revision == 0
1206 || info->silicon_revision == 1 ? 1 : 0;
1207 if (info->revision < 8) {
1208 some_delay_ns = 600;
1209 cas_latency_shift = 0;
1210 }
1211 {
1212 int speed_bit;
1213 speed_bit =
1214 ((info->clock_speed_index > 1
1215 || (info->silicon_revision != 2
1216 && info->silicon_revision != 3))) ^ (info->revision >=
1217 0x10);
1218 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1219 3, 1);
1220 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1221 3, 1);
1222 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1223 && (info->silicon_revision == 2
1224 || info->silicon_revision == 3))
1225 rmw_1d0(0x116, 5, 2, 4, 1);
1226 }
Felix Held04be2dd2018-07-29 04:53:22 +02001227 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1228 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001229
Felix Held04be2dd2018-07-29 04:53:22 +02001230 MCHBAR8(0x124) = info->board_lane_delay[4] +
1231 ((frequency_01(info) + 999) / 1000);
1232 MCHBAR16(0x125) = 0x1360;
1233 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001234 if (info->fsb_frequency < frequency_11(info) / 2) {
1235 unsigned some_delay_2_half_cycles;
1236 high_multiplier = 1;
1237 some_delay_2_half_cycles = ps_to_halfcycles(info,
1238 ((3 *
1239 fsbcycle_ps(info))
1240 >> 1) +
1241 (halfcycle_ps(info)
1242 *
1243 reg178_min[info->
1244 clock_speed_index]
1245 >> 6)
1246 +
1247 4 *
1248 halfcycle_ps(info)
1249 + 2230);
1250 some_delay_3_half_cycles =
1251 min((some_delay_2_half_cycles +
1252 (frequency_11(info) * 2) * (28 -
1253 some_delay_2_half_cycles) /
1254 (frequency_11(info) * 2 -
1255 4 * (info->fsb_frequency))) >> 3, 7);
1256 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001257 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001258 some_delay_3_half_cycles = 3;
1259 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001260 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1261 MCHBAR32(0x224 + (channel << 10)) =
1262 (info->max_slots_used_in_channel - 1) |
1263 ((info->cas_latency - 5 - info->clock_speed_index)
1264 << 21) | ((info->max_slots_used_in_channel +
1265 info->cas_latency - cas_latency_shift - 4) << 16) |
1266 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1267 ((info->cas_latency - info->clock_speed_index +
1268 info->max_slots_used_in_channel - 6) << 8);
1269 MCHBAR32(0x228 + (channel << 10)) =
1270 info->max_slots_used_in_channel;
1271 MCHBAR8(0x239 + (channel << 10)) = 32;
1272 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1273 (some_delay_3_half_cycles << 25) | 0x840000;
1274 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1275 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1276 MCHBAR32(0x24c + (channel << 10)) =
1277 ((!!info->clock_speed_index) << 17) |
1278 (((2 + info->clock_speed_index -
1279 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001280
Felix Held04be2dd2018-07-29 04:53:22 +02001281 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1282 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1283 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001284
1285 write_500(info, channel,
1286 ((!info->populated_ranks[channel][1][1])
1287 | (!info->populated_ranks[channel][1][0] << 1)
1288 | (!info->populated_ranks[channel][0][1] << 2)
1289 | (!info->populated_ranks[channel][0][0] << 3)),
1290 0x4c9, 4, 1);
1291 }
1292
Felix Held22ca8cb2018-07-29 05:09:44 +02001293 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001294 {
1295 u8 freq_divisor = 2;
1296 if (info->fsb_frequency == frequency_11(info))
1297 freq_divisor = 3;
1298 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1299 freq_divisor = 1;
1300 else
1301 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001302 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001303 }
1304
1305 if (info->board_lane_delay[3] <= 10) {
1306 if (info->board_lane_delay[3] <= 8)
1307 lane_3_delay = info->board_lane_delay[3];
1308 else
1309 lane_3_delay = 10;
1310 } else {
1311 lane_3_delay = 12;
1312 }
1313 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1314 if (info->clock_speed_index > 1)
1315 cas_latency_derived++;
1316 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001317 MCHBAR32(0x240 + (channel << 10)) =
1318 ((info->clock_speed_index == 0) * 0x11000) |
1319 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1320 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001321 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1322 0x609, 6, 1);
1323 write_500(info, channel,
1324 info->clock_speed_index + 2 * info->cas_latency - 7,
1325 0x601, 6, 1);
1326
Felix Held04be2dd2018-07-29 04:53:22 +02001327 MCHBAR32(0x250 + (channel << 10)) =
1328 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1329 (info->board_lane_delay[7] << 2) |
1330 (info->board_lane_delay[4] << 16) |
1331 (info->board_lane_delay[1] << 25) |
1332 (info->board_lane_delay[1] << 29) | 1;
1333 MCHBAR32(0x254 + (channel << 10)) =
1334 (info->board_lane_delay[1] >> 3) |
1335 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1336 0x80 | (info->board_lane_delay[6] << 1) |
1337 (info->board_lane_delay[2] << 28) |
1338 (cas_latency_derived << 16) | 0x4700000;
1339 MCHBAR32(0x258 + (channel << 10)) =
1340 ((info->board_lane_delay[5] + info->clock_speed_index +
1341 9) << 12) | ((info->clock_speed_index -
1342 info->cas_latency + 12) << 8) |
1343 (info->board_lane_delay[2] << 17) |
1344 (info->board_lane_delay[4] << 24) | 0x47;
1345 MCHBAR32(0x25c + (channel << 10)) =
1346 (info->board_lane_delay[1] << 1) |
1347 (info->board_lane_delay[0] << 8) | 0x1da50000;
1348 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1349 MCHBAR8(0x5f8 + (channel << 10)) =
1350 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001351 }
1352
1353 program_modules_memory_map(info, 1);
1354
Felix Held04be2dd2018-07-29 04:53:22 +02001355 MCHBAR16(0x610) = (min(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
1356 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1357 MCHBAR16_OR(0x612, 0x100);
1358 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001359 for (i = 0; i < 8; i++) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001360 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0x80 + 4 * i,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001361 (info->total_memory_mb - 64) | !i | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001362 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0xc0 + 4 * i, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001363 }
1364}
1365
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001366#define DEFAULT_PCI_MMIO_SIZE 2048
1367#define HOST_BRIDGE PCI_DEVFN(0, 0)
1368
1369static unsigned int get_mmio_size(void)
1370{
1371 const struct device *dev;
1372 const struct northbridge_intel_nehalem_config *cfg = NULL;
1373
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001374 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001375 if (dev)
1376 cfg = dev->chip_info;
1377
1378 /* If this is zero, it just means devicetree.cb didn't set it */
1379 if (!cfg || cfg->pci_mmio_size == 0)
1380 return DEFAULT_PCI_MMIO_SIZE;
1381 else
1382 return cfg->pci_mmio_size;
1383}
1384
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001385#define BETTER_MEMORY_MAP 0
1386
1387static void program_total_memory_map(struct raminfo *info)
1388{
1389 unsigned int TOM, TOLUD, TOUUD;
1390 unsigned int quickpath_reserved;
1391 unsigned int REMAPbase;
1392 unsigned int uma_base_igd;
1393 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001394 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001395 int memory_remap;
1396 unsigned int memory_map[8];
1397 int i;
1398 unsigned int current_limit;
1399 unsigned int tseg_base;
1400 int uma_size_igd = 0, uma_size_gtt = 0;
1401
1402 memset(memory_map, 0, sizeof(memory_map));
1403
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001404 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001405 u16 t = pci_read_config16(NORTHBRIDGE, D0F0_GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001406 gav(t);
1407 const int uma_sizes_gtt[16] =
1408 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1409 /* Igd memory */
1410 const int uma_sizes_igd[16] = {
1411 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1412 256, 512
1413 };
1414
1415 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1416 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1417 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001418
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001419 mmio_size = get_mmio_size();
1420
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001421 TOM = info->total_memory_mb;
1422 if (TOM == 4096)
1423 TOM = 4032;
1424 TOUUD = ALIGN_DOWN(TOM - info->memory_reserved_for_heci_mb, 64);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001425 TOLUD = ALIGN_DOWN(min(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
Elyes HAOUASa342f392018-10-17 10:56:26 +02001426 , TOUUD), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001427 memory_remap = 0;
1428 if (TOUUD - TOLUD > 64) {
1429 memory_remap = 1;
1430 REMAPbase = max(4096, TOUUD);
1431 TOUUD = TOUUD - TOLUD + 4096;
1432 }
1433 if (TOUUD > 4096)
1434 memory_map[2] = TOUUD | 1;
1435 quickpath_reserved = 0;
1436
Jacob Garber975a7e32019-06-10 16:32:47 -06001437 u32 t = pci_read_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001438
Jacob Garber975a7e32019-06-10 16:32:47 -06001439 gav(t);
1440
1441 if (t & 0x800) {
1442 u32 shift = t >> 20;
1443 if (shift == 0)
1444 die("Quickpath value is 0\n");
1445 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001446 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001447
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001448 if (memory_remap)
1449 TOUUD -= quickpath_reserved;
1450
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001451 uma_base_igd = TOLUD - uma_size_igd;
1452 uma_base_gtt = uma_base_igd - uma_size_gtt;
1453 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1454 if (!memory_remap)
1455 tseg_base -= quickpath_reserved;
1456 tseg_base = ALIGN_DOWN(tseg_base, 8);
1457
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001458 pci_write_config16(NORTHBRIDGE, D0F0_TOLUD, TOLUD << 4);
1459 pci_write_config16(NORTHBRIDGE, D0F0_TOM, TOM >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001460 if (memory_remap) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001461 pci_write_config16(NORTHBRIDGE, D0F0_REMAPBASE, REMAPbase >> 6);
1462 pci_write_config16(NORTHBRIDGE, D0F0_REMAPLIMIT, (TOUUD - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001463 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001464 pci_write_config16(NORTHBRIDGE, D0F0_TOUUD, TOUUD);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001465
1466 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001467 pci_write_config32(NORTHBRIDGE, D0F0_IGD_BASE, uma_base_igd << 20);
1468 pci_write_config32(NORTHBRIDGE, D0F0_GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001469 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001470 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001471
1472 current_limit = 0;
1473 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1474 memory_map[1] = 4096;
1475 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
1476 current_limit = max(current_limit, memory_map[i] & ~1);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001477 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0x80,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001478 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1479 1, 64) | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001480 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0xc0, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001481 }
1482}
1483
1484static void collect_system_info(struct raminfo *info)
1485{
1486 u32 capid0[3];
1487 int i;
1488 unsigned channel;
1489
1490 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001491 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1492 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001493
1494 if (!info->heci_bar)
1495 gav(info->heci_bar =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001496 pci_read_config32(HECIDEV, HECIBAR) & 0xFFFFFFF8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001497 if (!info->memory_reserved_for_heci_mb) {
1498 /* Wait for ME to be ready */
1499 intel_early_me_init();
1500 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1501 }
1502
1503 for (i = 0; i < 3; i++)
1504 gav(capid0[i] =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001505 pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 | (i << 2)));
1506 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001507 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1508
1509 if ((capid0[1] >> 11) & 1)
1510 info->uma_enabled = 0;
1511 else
1512 gav(info->uma_enabled =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001513 pci_read_config8(NORTHBRIDGE, D0F0_DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001514 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1515 info->silicon_revision = 0;
1516
1517 if (capid0[2] & 2) {
1518 info->silicon_revision = 0;
1519 info->max_supported_clock_speed_index = 2;
1520 for (channel = 0; channel < NUM_CHANNELS; channel++)
1521 if (info->populated_ranks[channel][0][0]
1522 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1523 3) {
1524 info->silicon_revision = 2;
1525 info->max_supported_clock_speed_index = 1;
1526 }
1527 } else {
1528 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1529 case 1:
1530 case 2:
1531 info->silicon_revision = 3;
1532 break;
1533 case 3:
1534 info->silicon_revision = 0;
1535 break;
1536 case 0:
1537 info->silicon_revision = 2;
1538 break;
1539 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001540 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001541 case 0x40:
1542 info->silicon_revision = 0;
1543 break;
1544 case 0x48:
1545 info->silicon_revision = 1;
1546 break;
1547 }
1548 }
1549}
1550
1551static void write_training_data(struct raminfo *info)
1552{
1553 int tm, channel, slot, rank, lane;
1554 if (info->revision < 8)
1555 return;
1556
1557 for (tm = 0; tm < 4; tm++)
1558 for (channel = 0; channel < NUM_CHANNELS; channel++)
1559 for (slot = 0; slot < NUM_SLOTS; slot++)
1560 for (rank = 0; rank < NUM_RANKS; rank++)
1561 for (lane = 0; lane < 9; lane++)
1562 write_500(info, channel,
1563 info->
1564 cached_training->
1565 lane_timings[tm]
1566 [channel][slot][rank]
1567 [lane],
1568 get_timing_register_addr
1569 (lane, tm, slot,
1570 rank), 9, 0);
1571 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1572 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1573}
1574
1575static void dump_timings(struct raminfo *info)
1576{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001577 int channel, slot, rank, lane, i;
Arthur Heymansb3282092019-04-14 17:53:28 +02001578 printk(RAM_DEBUG, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001579 FOR_POPULATED_RANKS {
Arthur Heymansb3282092019-04-14 17:53:28 +02001580 printk(RAM_DEBUG, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001581 slot, rank);
1582 for (lane = 0; lane < 9; lane++) {
Arthur Heymansb3282092019-04-14 17:53:28 +02001583 printk(RAM_DEBUG, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001584 for (i = 0; i < 4; i++) {
Arthur Heymansb3282092019-04-14 17:53:28 +02001585 printk(RAM_DEBUG, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001586 read_500(info, channel,
1587 get_timing_register_addr
1588 (lane, i, slot, rank),
1589 9),
1590 info->training.
1591 lane_timings[i][channel][slot][rank]
1592 [lane]);
1593 }
Arthur Heymansb3282092019-04-14 17:53:28 +02001594 printk(RAM_DEBUG, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001595 }
1596 }
Arthur Heymansb3282092019-04-14 17:53:28 +02001597 printk(RAM_DEBUG, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001598 info->training.reg_178);
Arthur Heymansb3282092019-04-14 17:53:28 +02001599 printk(RAM_DEBUG, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001600 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001601}
1602
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001603/* Read timings and other registers that need to be restored verbatim and
1604 put them to CBMEM.
1605 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001606static void save_timings(struct raminfo *info)
1607{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001608 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001609 int channel, slot, rank, lane, i;
1610
1611 train = info->training;
1612 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1613 for (i = 0; i < 4; i++)
1614 train.lane_timings[i][channel][slot][rank][lane] =
1615 read_500(info, channel,
1616 get_timing_register_addr(lane, i, slot,
1617 rank), 9);
1618 train.reg_178 = read_1d0(0x178, 7);
1619 train.reg_10b = read_1d0(0x10b, 6);
1620
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001621 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1622 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001623 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001624 train.reg274265[channel][0] = reg32 >> 16;
1625 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001626 train.reg274265[channel][2] =
1627 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001628 }
Felix Held04be2dd2018-07-29 04:53:22 +02001629 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1630 train.reg_6dc = MCHBAR32(0x6dc);
1631 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001632
Arthur Heymansb3282092019-04-14 17:53:28 +02001633 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1634 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001635
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001636 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001637 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1638 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001639}
1640
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001641static const struct ram_training *get_cached_training(void)
1642{
Arthur Heymansdc71e252018-01-29 10:14:48 +01001643 struct region_device rdev;
1644 if (mrc_cache_get_current(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1645 &rdev))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001646 return 0;
Arthur Heymansdc71e252018-01-29 10:14:48 +01001647 return (void *)rdev_mmap_full(&rdev);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001648}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001649
1650/* FIXME: add timeout. */
1651static void wait_heci_ready(void)
1652{
Felix Held04be2dd2018-07-29 04:53:22 +02001653 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1654 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001655 write32((DEFAULT_HECIBAR + 0x4),
1656 (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001657}
1658
1659/* FIXME: add timeout. */
1660static void wait_heci_cb_avail(int len)
1661{
1662 union {
1663 struct mei_csr csr;
1664 u32 raw;
1665 } csr;
1666
Felix Held22ca8cb2018-07-29 05:09:44 +02001667 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1668 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001669
1670 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001671 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001672 while (len >
1673 csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
Felix Held22ca8cb2018-07-29 05:09:44 +02001674 csr.csr.buffer_read_ptr))
1675 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001676}
1677
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001678static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001679{
1680 int len = (head->length + 3) / 4;
1681 int i;
1682
1683 wait_heci_cb_avail(len + 1);
1684
1685 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001686 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001687 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001688 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001689
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001690 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1691 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001692}
1693
1694static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001695send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001696{
1697 struct mei_header head;
1698 int maxlen;
1699
1700 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001701 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001702
1703 while (len) {
1704 int cur = len;
1705 if (cur > maxlen) {
1706 cur = maxlen;
1707 head.is_complete = 0;
1708 } else
1709 head.is_complete = 1;
1710 head.length = cur;
1711 head.reserved = 0;
1712 head.client_address = clientaddress;
1713 head.host_address = hostaddress;
1714 send_heci_packet(&head, (u32 *) msg);
1715 len -= cur;
1716 msg += cur;
1717 }
1718}
1719
1720/* FIXME: Add timeout. */
1721static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001722recv_heci_packet(struct raminfo *info, struct mei_header *head, u32 *packet,
1723 u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001724{
1725 union {
1726 struct mei_csr csr;
1727 u32 raw;
1728 } csr;
1729 int i = 0;
1730
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001731 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001732 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001733 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001734 }
Felix Held04be2dd2018-07-29 04:53:22 +02001735 while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr)
1736 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001737 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001738 if (!head->length) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001739 write32(DEFAULT_HECIBAR + 0x4,
1740 read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001741 *packet_size = 0;
1742 return 0;
1743 }
1744 if (head->length + 4 > 4 * csr.csr.buffer_depth
1745 || head->length > *packet_size) {
1746 *packet_size = 0;
1747 return -1;
1748 }
1749
1750 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001751 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Felix Held22ca8cb2018-07-29 05:09:44 +02001752 while (((head->length + 3) >> 2) >
1753 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr))
1754 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001755
1756 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001757 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001758 *packet_size = head->length;
1759 if (!csr.csr.ready)
1760 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001761 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001762 return 0;
1763}
1764
1765/* FIXME: Add timeout. */
1766static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001767recv_heci_message(struct raminfo *info, u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001768{
1769 struct mei_header head;
1770 int current_position;
1771
1772 current_position = 0;
1773 while (1) {
1774 u32 current_size;
1775 current_size = *message_size - current_position;
1776 if (recv_heci_packet
1777 (info, &head, message + (current_position >> 2),
1778 &current_size) == -1)
1779 break;
1780 if (!current_size)
1781 break;
1782 current_position += current_size;
1783 if (head.is_complete) {
1784 *message_size = current_position;
1785 return 0;
1786 }
1787
1788 if (current_position >= *message_size)
1789 break;
1790 }
1791 *message_size = 0;
1792 return -1;
1793}
1794
1795static void send_heci_uma_message(struct raminfo *info)
1796{
1797 struct uma_reply {
1798 u8 group_id;
1799 u8 command;
1800 u8 reserved;
1801 u8 result;
1802 u8 field2;
1803 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001804 } __packed reply;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001805 struct uma_message {
1806 u8 group_id;
1807 u8 cmd;
1808 u8 reserved;
1809 u8 result;
1810 u32 c2;
1811 u64 heci_uma_addr;
1812 u32 memory_reserved_for_heci_mb;
1813 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001814 } __packed msg = {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001815 0, MKHI_SET_UMA, 0, 0,
1816 0x82,
1817 info->heci_uma_addr, info->memory_reserved_for_heci_mb, 0};
1818 u32 reply_size;
1819
1820 send_heci_message((u8 *) & msg, sizeof(msg), 0, 7);
1821
1822 reply_size = sizeof(reply);
1823 if (recv_heci_message(info, (u32 *) & reply, &reply_size) == -1)
1824 return;
1825
1826 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1827 die("HECI init failed\n");
1828}
1829
1830static void setup_heci_uma(struct raminfo *info)
1831{
1832 u32 reg44;
1833
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001834 reg44 = pci_read_config32(HECIDEV, 0x44); // = 0x80010020
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001835 info->memory_reserved_for_heci_mb = 0;
1836 info->heci_uma_addr = 0;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001837 if (!((reg44 & 0x10000) && !(pci_read_config32(HECIDEV, 0x40) & 0x20)))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001838 return;
1839
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001840 info->heci_bar = pci_read_config32(HECIDEV, 0x10) & 0xFFFFFFF0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001841 info->memory_reserved_for_heci_mb = reg44 & 0x3f;
1842 info->heci_uma_addr =
1843 ((u64)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001844 ((((u64) pci_read_config16(NORTHBRIDGE, D0F0_TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001845 info->memory_reserved_for_heci_mb)) << 20;
1846
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001847 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001848 if (info->memory_reserved_for_heci_mb) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001849 write32(DEFAULT_DMIBAR + 0x14,
1850 read32(DEFAULT_DMIBAR + 0x14) & ~0x80);
1851 write32(DEFAULT_RCBA + 0x14,
1852 read32(DEFAULT_RCBA + 0x14) & ~0x80);
1853 write32(DEFAULT_DMIBAR + 0x20,
1854 read32(DEFAULT_DMIBAR + 0x20) & ~0x80);
1855 write32(DEFAULT_RCBA + 0x20,
1856 read32(DEFAULT_RCBA + 0x20) & ~0x80);
1857 write32(DEFAULT_DMIBAR + 0x2c,
1858 read32(DEFAULT_DMIBAR + 0x2c) & ~0x80);
1859 write32(DEFAULT_RCBA + 0x30,
1860 read32(DEFAULT_RCBA + 0x30) & ~0x80);
1861 write32(DEFAULT_DMIBAR + 0x38,
1862 read32(DEFAULT_DMIBAR + 0x38) & ~0x80);
1863 write32(DEFAULT_RCBA + 0x40,
1864 read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001865
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001866 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
1867 write32(DEFAULT_DMIBAR + 0x38, 0x87000080); // OK
Felix Held04be2dd2018-07-29 04:53:22 +02001868 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
1869 read16(DEFAULT_DMIBAR + 0x3e) & 2)
1870 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001871 }
1872
Felix Held04be2dd2018-07-29 04:53:22 +02001873 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001874
1875 send_heci_uma_message(info);
1876
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001877 pci_write_config32(HECIDEV, 0x10, 0x0);
1878 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001879
1880}
1881
1882static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1883{
1884 int ranks_in_channel;
1885 ranks_in_channel = info->populated_ranks[channel][0][0]
1886 + info->populated_ranks[channel][0][1]
1887 + info->populated_ranks[channel][1][0]
1888 + info->populated_ranks[channel][1][1];
1889
1890 /* empty channel */
1891 if (ranks_in_channel == 0)
1892 return 1;
1893
1894 if (ranks_in_channel != ranks)
1895 return 0;
1896 /* single slot */
1897 if (info->populated_ranks[channel][0][0] !=
1898 info->populated_ranks[channel][1][0])
1899 return 1;
1900 if (info->populated_ranks[channel][0][1] !=
1901 info->populated_ranks[channel][1][1])
1902 return 1;
1903 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1904 return 0;
1905 if (info->density[channel][0] != info->density[channel][1])
1906 return 0;
1907 return 1;
1908}
1909
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001910static void read_4090(struct raminfo *info)
1911{
1912 int i, channel, slot, rank, lane;
1913 for (i = 0; i < 2; i++)
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[0][i][slot][rank][lane]
1919 = 32;
1920
1921 for (i = 1; i < 4; i++)
1922 for (channel = 0; channel < NUM_CHANNELS; channel++)
1923 for (slot = 0; slot < NUM_SLOTS; slot++)
1924 for (rank = 0; rank < NUM_RANKS; rank++)
1925 for (lane = 0; lane < 9; lane++) {
1926 info->training.
1927 lane_timings[i][channel]
1928 [slot][rank][lane] =
1929 read_500(info, channel,
1930 get_timing_register_addr
1931 (lane, i, slot,
1932 rank), 9)
1933 + (i == 1) * 11; // !!!!
1934 }
1935
1936}
1937
1938static u32 get_etalon2(int flip, u32 addr)
1939{
1940 const u16 invmask[] = {
1941 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1942 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1943 };
1944 u32 ret;
1945 u32 comp4 = addr / 480;
1946 addr %= 480;
1947 u32 comp1 = addr & 0xf;
1948 u32 comp2 = (addr >> 4) & 1;
1949 u32 comp3 = addr >> 5;
1950
1951 if (comp4)
1952 ret = 0x1010101 << (comp4 - 1);
1953 else
1954 ret = 0;
1955 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1956 ret = ~ret;
1957
1958 return ret;
1959}
1960
1961static void disable_cache(void)
1962{
1963 msr_t msr = {.lo = 0, .hi = 0 };
1964
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001965 wrmsr(MTRR_PHYS_BASE(3), msr);
1966 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001967}
1968
1969static void enable_cache(unsigned int base, unsigned int size)
1970{
1971 msr_t msr;
1972 msr.lo = base | MTRR_TYPE_WRPROT;
1973 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001974 wrmsr(MTRR_PHYS_BASE(3), msr);
1975 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001976 & 0xffffffff);
1977 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001978 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001979}
1980
1981static void flush_cache(u32 start, u32 size)
1982{
1983 u32 end;
1984 u32 addr;
1985
1986 end = start + (ALIGN_DOWN(size + 4096, 4096));
1987 for (addr = start; addr < end; addr += 64)
1988 clflush(addr);
1989}
1990
1991static void clear_errors(void)
1992{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001993 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001994}
1995
1996static void write_testing(struct raminfo *info, int totalrank, int flip)
1997{
1998 int nwrites = 0;
1999 /* in 8-byte units. */
2000 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002001 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002002
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002003 base = (u8 *)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002004 for (offset = 0; offset < 9 * 480; offset += 2) {
2005 write32(base + offset * 8, get_etalon2(flip, offset));
2006 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
2007 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
2008 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
2009 nwrites += 4;
2010 if (nwrites >= 320) {
2011 clear_errors();
2012 nwrites = 0;
2013 }
2014 }
2015}
2016
2017static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
2018{
2019 u8 failmask = 0;
2020 int i;
2021 int comp1, comp2, comp3;
2022 u32 failxor[2] = { 0, 0 };
2023
2024 enable_cache((total_rank << 28), 1728 * 5 * 4);
2025
2026 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
2027 for (comp1 = 0; comp1 < 4; comp1++)
2028 for (comp2 = 0; comp2 < 60; comp2++) {
2029 u32 re[4];
2030 u32 curroffset =
2031 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
2032 read128((total_rank << 28) | (curroffset << 3),
2033 (u64 *) re);
2034 failxor[0] |=
2035 get_etalon2(flip, curroffset) ^ re[0];
2036 failxor[1] |=
2037 get_etalon2(flip, curroffset) ^ re[1];
2038 failxor[0] |=
2039 get_etalon2(flip, curroffset | 1) ^ re[2];
2040 failxor[1] |=
2041 get_etalon2(flip, curroffset | 1) ^ re[3];
2042 }
2043 for (i = 0; i < 8; i++)
2044 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2045 failmask |= 1 << i;
2046 }
2047 disable_cache();
2048 flush_cache((total_rank << 28), 1728 * 5 * 4);
2049 return failmask;
2050}
2051
2052const u32 seed1[0x18] = {
2053 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2054 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2055 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2056 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2057 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2058 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2059};
2060
2061static u32 get_seed2(int a, int b)
2062{
2063 const u32 seed2[5] = {
2064 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2065 0x5b6db6db,
2066 };
2067 u32 r;
2068 r = seed2[(a + (a >= 10)) / 5];
2069 return b ? ~r : r;
2070}
2071
2072static int make_shift(int comp2, int comp5, int x)
2073{
2074 const u8 seed3[32] = {
2075 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2076 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2077 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2078 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2079 };
2080
2081 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2082}
2083
2084static u32 get_etalon(int flip, u32 addr)
2085{
2086 u32 mask_byte = 0;
2087 int comp1 = (addr >> 1) & 1;
2088 int comp2 = (addr >> 3) & 0x1f;
2089 int comp3 = (addr >> 8) & 0xf;
2090 int comp4 = (addr >> 12) & 0xf;
2091 int comp5 = (addr >> 16) & 0x1f;
2092 u32 mask_bit = ~(0x10001 << comp3);
2093 u32 part1;
2094 u32 part2;
2095 int byte;
2096
2097 part2 =
2098 ((seed1[comp5] >>
2099 make_shift(comp2, comp5,
2100 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2101 part1 =
2102 ((seed1[comp5] >>
2103 make_shift(comp2, comp5,
2104 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2105
2106 for (byte = 0; byte < 4; byte++)
2107 if ((get_seed2(comp5, comp4) >>
2108 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2109 mask_byte |= 0xff << (8 * byte);
2110
2111 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2112 (comp3 + 16));
2113}
2114
2115static void
2116write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2117 char flip)
2118{
2119 int i;
2120 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002121 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2122 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002123}
2124
2125static u8
2126check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2127 char flip)
2128{
2129 u8 failmask = 0;
2130 u32 failxor[2];
2131 int i;
2132 int comp1, comp2, comp3;
2133
2134 failxor[0] = 0;
2135 failxor[1] = 0;
2136
2137 enable_cache(totalrank << 28, 134217728);
2138 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2139 for (comp1 = 0; comp1 < 16; comp1++)
2140 for (comp2 = 0; comp2 < 64; comp2++) {
2141 u32 addr =
2142 (totalrank << 28) | (region << 25) | (block
2143 << 16)
2144 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2145 2);
2146 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002147 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002148 }
2149 for (i = 0; i < 8; i++)
2150 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2151 failmask |= 1 << i;
2152 }
2153 disable_cache();
2154 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2155 return failmask;
2156}
2157
2158static int check_bounded(unsigned short *vals, u16 bound)
2159{
2160 int i;
2161
2162 for (i = 0; i < 8; i++)
2163 if (vals[i] < bound)
2164 return 0;
2165 return 1;
2166}
2167
2168enum state {
2169 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2170};
2171
2172static int validate_state(enum state *in)
2173{
2174 int i;
2175 for (i = 0; i < 8; i++)
2176 if (in[i] != COMPLETE)
2177 return 0;
2178 return 1;
2179}
2180
2181static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002182do_fsm(enum state *state, u16 *counter,
2183 u8 fail_mask, int margin, int uplimit,
2184 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002185{
2186 int lane;
2187
2188 for (lane = 0; lane < 8; lane++) {
2189 int is_fail = (fail_mask >> lane) & 1;
2190 switch (state[lane]) {
2191 case BEFORE_USABLE:
2192 if (!is_fail) {
2193 counter[lane] = 1;
2194 state[lane] = AT_USABLE;
2195 break;
2196 }
2197 counter[lane] = 0;
2198 state[lane] = BEFORE_USABLE;
2199 break;
2200 case AT_USABLE:
2201 if (!is_fail) {
2202 ++counter[lane];
2203 if (counter[lane] >= margin) {
2204 state[lane] = AT_MARGIN;
2205 res_low[lane] = val - margin + 1;
2206 break;
2207 }
2208 state[lane] = 1;
2209 break;
2210 }
2211 counter[lane] = 0;
2212 state[lane] = BEFORE_USABLE;
2213 break;
2214 case AT_MARGIN:
2215 if (is_fail) {
2216 state[lane] = COMPLETE;
2217 res_high[lane] = val - 1;
2218 } else {
2219 counter[lane]++;
2220 state[lane] = AT_MARGIN;
2221 if (val == uplimit) {
2222 state[lane] = COMPLETE;
2223 res_high[lane] = uplimit;
2224 }
2225 }
2226 break;
2227 case COMPLETE:
2228 break;
2229 }
2230 }
2231}
2232
2233static void
2234train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2235 u8 total_rank, u8 reg_178, int first_run, int niter,
2236 timing_bounds_t * timings)
2237{
2238 int lane;
2239 enum state state[8];
2240 u16 count[8];
2241 u8 lower_usable[8];
2242 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002243 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002244 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002245 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002246
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002247 for (i = 0; i < 8; i++)
2248 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002249
2250 if (!first_run) {
2251 int is_all_ok = 1;
2252 for (lane = 0; lane < 8; lane++)
2253 if (timings[reg_178][channel][slot][rank][lane].
2254 smallest ==
2255 timings[reg_178][channel][slot][rank][lane].
2256 largest) {
2257 timings[reg_178][channel][slot][rank][lane].
2258 smallest = 0;
2259 timings[reg_178][channel][slot][rank][lane].
2260 largest = 0;
2261 is_all_ok = 0;
2262 }
2263 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002264 for (i = 0; i < 8; i++)
2265 state[i] = COMPLETE;
2266 }
2267 }
2268
2269 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2270 u8 failmask = 0;
2271 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2272 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2273 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002274 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002275 do_fsm(state, count, failmask, 5, 47, lower_usable,
2276 upper_usable, reg1b3);
2277 }
2278
2279 if (reg1b3) {
2280 write_1d0(0, 0x1b3, 6, 1);
2281 write_1d0(0, 0x1a3, 6, 1);
2282 for (lane = 0; lane < 8; lane++) {
2283 if (state[lane] == COMPLETE) {
2284 timings[reg_178][channel][slot][rank][lane].
2285 smallest =
2286 lower_usable[lane] +
2287 (info->training.
2288 lane_timings[0][channel][slot][rank][lane]
2289 & 0x3F) - 32;
2290 timings[reg_178][channel][slot][rank][lane].
2291 largest =
2292 upper_usable[lane] +
2293 (info->training.
2294 lane_timings[0][channel][slot][rank][lane]
2295 & 0x3F) - 32;
2296 }
2297 }
2298 }
2299
2300 if (!first_run) {
2301 for (lane = 0; lane < 8; lane++)
2302 if (state[lane] == COMPLETE) {
2303 write_500(info, channel,
2304 timings[reg_178][channel][slot][rank]
2305 [lane].smallest,
2306 get_timing_register_addr(lane, 0,
2307 slot, rank),
2308 9, 1);
2309 write_500(info, channel,
2310 timings[reg_178][channel][slot][rank]
2311 [lane].smallest +
2312 info->training.
2313 lane_timings[1][channel][slot][rank]
2314 [lane]
2315 -
2316 info->training.
2317 lane_timings[0][channel][slot][rank]
2318 [lane], get_timing_register_addr(lane,
2319 1,
2320 slot,
2321 rank),
2322 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002323 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002324 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002325 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002326
2327 do {
2328 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002329 for (i = 0; i < niter; i++) {
2330 if (failmask == 0xFF)
2331 break;
2332 failmask |=
2333 check_testing_type2(info, total_rank, 2, i,
2334 0);
2335 failmask |=
2336 check_testing_type2(info, total_rank, 3, i,
2337 1);
2338 }
Felix Held04be2dd2018-07-29 04:53:22 +02002339 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002340 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002341 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002342 if ((1 << lane) & failmask) {
2343 if (timings[reg_178][channel]
2344 [slot][rank][lane].
2345 largest <=
2346 timings[reg_178][channel]
2347 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002348 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002349 [lane] = -1;
2350 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002351 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002352 [lane] = 0;
2353 timings[reg_178]
2354 [channel][slot]
2355 [rank][lane].
2356 smallest++;
2357 write_500(info, channel,
2358 timings
2359 [reg_178]
2360 [channel]
2361 [slot][rank]
2362 [lane].
2363 smallest,
2364 get_timing_register_addr
2365 (lane, 0,
2366 slot, rank),
2367 9, 1);
2368 write_500(info, channel,
2369 timings
2370 [reg_178]
2371 [channel]
2372 [slot][rank]
2373 [lane].
2374 smallest +
2375 info->
2376 training.
2377 lane_timings
2378 [1][channel]
2379 [slot][rank]
2380 [lane]
2381 -
2382 info->
2383 training.
2384 lane_timings
2385 [0][channel]
2386 [slot][rank]
2387 [lane],
2388 get_timing_register_addr
2389 (lane, 1,
2390 slot, rank),
2391 9, 1);
2392 }
2393 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002394 num_successfully_checked[lane]
2395 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002396 }
2397 }
Felix Held04be2dd2018-07-29 04:53:22 +02002398 while (!check_bounded(num_successfully_checked, 2))
2399 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002400
2401 for (lane = 0; lane < 8; lane++)
2402 if (state[lane] == COMPLETE) {
2403 write_500(info, channel,
2404 timings[reg_178][channel][slot][rank]
2405 [lane].largest,
2406 get_timing_register_addr(lane, 0,
2407 slot, rank),
2408 9, 1);
2409 write_500(info, channel,
2410 timings[reg_178][channel][slot][rank]
2411 [lane].largest +
2412 info->training.
2413 lane_timings[1][channel][slot][rank]
2414 [lane]
2415 -
2416 info->training.
2417 lane_timings[0][channel][slot][rank]
2418 [lane], get_timing_register_addr(lane,
2419 1,
2420 slot,
2421 rank),
2422 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002423 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002424 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002425 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002426
2427 do {
2428 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002429 for (i = 0; i < niter; i++) {
2430 if (failmask == 0xFF)
2431 break;
2432 failmask |=
2433 check_testing_type2(info, total_rank, 2, i,
2434 0);
2435 failmask |=
2436 check_testing_type2(info, total_rank, 3, i,
2437 1);
2438 }
2439
Felix Held04be2dd2018-07-29 04:53:22 +02002440 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002441 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002442 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002443 if ((1 << lane) & failmask) {
2444 if (timings[reg_178][channel]
2445 [slot][rank][lane].
2446 largest <=
2447 timings[reg_178][channel]
2448 [slot][rank][lane].
2449 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002450 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002451 [lane] = -1;
2452 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002453 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002454 [lane] = 0;
2455 timings[reg_178]
2456 [channel][slot]
2457 [rank][lane].
2458 largest--;
2459 write_500(info, channel,
2460 timings
2461 [reg_178]
2462 [channel]
2463 [slot][rank]
2464 [lane].
2465 largest,
2466 get_timing_register_addr
2467 (lane, 0,
2468 slot, rank),
2469 9, 1);
2470 write_500(info, channel,
2471 timings
2472 [reg_178]
2473 [channel]
2474 [slot][rank]
2475 [lane].
2476 largest +
2477 info->
2478 training.
2479 lane_timings
2480 [1][channel]
2481 [slot][rank]
2482 [lane]
2483 -
2484 info->
2485 training.
2486 lane_timings
2487 [0][channel]
2488 [slot][rank]
2489 [lane],
2490 get_timing_register_addr
2491 (lane, 1,
2492 slot, rank),
2493 9, 1);
2494 }
2495 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002496 num_successfully_checked[lane]
2497 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002498 }
2499 }
2500 }
Felix Held04be2dd2018-07-29 04:53:22 +02002501 while (!check_bounded(num_successfully_checked, 3))
2502 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002503
2504 for (lane = 0; lane < 8; lane++) {
2505 write_500(info, channel,
2506 info->training.
2507 lane_timings[0][channel][slot][rank][lane],
2508 get_timing_register_addr(lane, 0, slot, rank),
2509 9, 1);
2510 write_500(info, channel,
2511 info->training.
2512 lane_timings[1][channel][slot][rank][lane],
2513 get_timing_register_addr(lane, 1, slot, rank),
2514 9, 1);
2515 if (timings[reg_178][channel][slot][rank][lane].
2516 largest <=
2517 timings[reg_178][channel][slot][rank][lane].
2518 smallest) {
2519 timings[reg_178][channel][slot][rank][lane].
2520 largest = 0;
2521 timings[reg_178][channel][slot][rank][lane].
2522 smallest = 0;
2523 }
2524 }
2525 }
2526}
2527
2528static void set_10b(struct raminfo *info, u8 val)
2529{
2530 int channel;
2531 int slot, rank;
2532 int lane;
2533
2534 if (read_1d0(0x10b, 6) == val)
2535 return;
2536
2537 write_1d0(val, 0x10b, 6, 1);
2538
2539 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2540 u16 reg_500;
2541 reg_500 = read_500(info, channel,
2542 get_timing_register_addr(lane, 0, slot,
2543 rank), 9);
2544 if (val == 1) {
2545 if (lut16[info->clock_speed_index] <= reg_500)
2546 reg_500 -= lut16[info->clock_speed_index];
2547 else
2548 reg_500 = 0;
2549 } else {
2550 reg_500 += lut16[info->clock_speed_index];
2551 }
2552 write_500(info, channel, reg_500,
2553 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2554 }
2555}
2556
2557static void set_ecc(int onoff)
2558{
2559 int channel;
2560 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2561 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002562 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002563 if (onoff)
2564 t |= 1;
2565 else
2566 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002567 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002568 }
2569}
2570
2571static void set_178(u8 val)
2572{
2573 if (val >= 31)
2574 val = val - 31;
2575 else
2576 val = 63 - val;
2577
2578 write_1d0(2 * val, 0x178, 7, 1);
2579}
2580
2581static void
2582write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2583 int type)
2584{
2585 int lane;
2586
2587 for (lane = 0; lane < 8; lane++)
2588 write_500(info, channel,
2589 info->training.
2590 lane_timings[type][channel][slot][rank][lane],
2591 get_timing_register_addr(lane, type, slot, rank), 9,
2592 0);
2593}
2594
2595static void
2596try_timing_offsets(struct raminfo *info, int channel,
2597 int slot, int rank, int totalrank)
2598{
2599 u16 count[8];
2600 enum state state[8];
2601 u8 lower_usable[8], upper_usable[8];
2602 int lane;
2603 int i;
2604 int flip = 1;
2605 int timing_offset;
2606
2607 for (i = 0; i < 8; i++)
2608 state[i] = BEFORE_USABLE;
2609
2610 memset(count, 0, sizeof(count));
2611
2612 for (lane = 0; lane < 8; lane++)
2613 write_500(info, channel,
2614 info->training.
2615 lane_timings[2][channel][slot][rank][lane] + 32,
2616 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2617
2618 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2619 timing_offset++) {
2620 u8 failmask;
2621 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2622 failmask = 0;
2623 for (i = 0; i < 2 && failmask != 0xff; i++) {
2624 flip = !flip;
2625 write_testing(info, totalrank, flip);
2626 failmask |= check_testing(info, totalrank, flip);
2627 }
2628 do_fsm(state, count, failmask, 10, 63, lower_usable,
2629 upper_usable, timing_offset);
2630 }
2631 write_1d0(0, 0x1bb, 6, 1);
2632 dump_timings(info);
2633 if (!validate_state(state))
2634 die("Couldn't discover DRAM timings (1)\n");
2635
2636 for (lane = 0; lane < 8; lane++) {
2637 u8 bias = 0;
2638
2639 if (info->silicon_revision) {
2640 int usable_length;
2641
2642 usable_length = upper_usable[lane] - lower_usable[lane];
2643 if (usable_length >= 20) {
2644 bias = usable_length / 2 - 10;
2645 if (bias >= 2)
2646 bias = 2;
2647 }
2648 }
2649 write_500(info, channel,
2650 info->training.
2651 lane_timings[2][channel][slot][rank][lane] +
2652 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2653 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2654 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2655 info->training.lane_timings[2][channel][slot][rank][lane] +
2656 lower_usable[lane];
2657 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2658 info->training.lane_timings[2][channel][slot][rank][lane] +
2659 upper_usable[lane];
2660 info->training.timing2_offset[channel][slot][rank][lane] =
2661 info->training.lane_timings[2][channel][slot][rank][lane];
2662 }
2663}
2664
2665static u8
2666choose_training(struct raminfo *info, int channel, int slot, int rank,
2667 int lane, timing_bounds_t * timings, u8 center_178)
2668{
2669 u16 central_weight;
2670 u16 side_weight;
2671 unsigned int sum = 0, count = 0;
2672 u8 span;
2673 u8 lower_margin, upper_margin;
2674 u8 reg_178;
2675 u8 result;
2676
2677 span = 12;
2678 central_weight = 20;
2679 side_weight = 20;
2680 if (info->silicon_revision == 1 && channel == 1) {
2681 central_weight = 5;
2682 side_weight = 20;
2683 if ((info->
2684 populated_ranks_mask[1] ^ (info->
2685 populated_ranks_mask[1] >> 2)) &
2686 1)
2687 span = 18;
2688 }
2689 if ((info->populated_ranks_mask[0] & 5) == 5) {
2690 central_weight = 20;
2691 side_weight = 20;
2692 }
2693 if (info->clock_speed_index >= 2
2694 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2695 if (info->silicon_revision == 1) {
2696 switch (channel) {
2697 case 0:
2698 if (lane == 1) {
2699 central_weight = 10;
2700 side_weight = 20;
2701 }
2702 break;
2703 case 1:
2704 if (lane == 6) {
2705 side_weight = 5;
2706 central_weight = 20;
2707 }
2708 break;
2709 }
2710 }
2711 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2712 side_weight = 5;
2713 central_weight = 20;
2714 }
2715 }
2716 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2717 reg_178 += span) {
2718 u8 smallest;
2719 u8 largest;
2720 largest = timings[reg_178][channel][slot][rank][lane].largest;
2721 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2722 if (largest - smallest + 1 >= 5) {
2723 unsigned int weight;
2724 if (reg_178 == center_178)
2725 weight = central_weight;
2726 else
2727 weight = side_weight;
2728 sum += weight * (largest + smallest);
2729 count += weight;
2730 }
2731 }
2732 dump_timings(info);
2733 if (count == 0)
2734 die("Couldn't discover DRAM timings (2)\n");
2735 result = sum / (2 * count);
2736 lower_margin =
2737 result - timings[center_178][channel][slot][rank][lane].smallest;
2738 upper_margin =
2739 timings[center_178][channel][slot][rank][lane].largest - result;
2740 if (upper_margin < 10 && lower_margin > 10)
2741 result -= min(lower_margin - 10, 10 - upper_margin);
2742 if (upper_margin > 10 && lower_margin < 10)
2743 result += min(upper_margin - 10, 10 - lower_margin);
2744 return result;
2745}
2746
2747#define STANDARD_MIN_MARGIN 5
2748
2749static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2750{
2751 u16 margin[64];
2752 int lane, rank, slot, channel;
2753 u8 reg178;
2754 int count = 0, sum = 0;
2755
2756 for (reg178 = reg178_min[info->clock_speed_index];
2757 reg178 < reg178_max[info->clock_speed_index];
2758 reg178 += reg178_step[info->clock_speed_index]) {
2759 margin[reg178] = -1;
2760 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2761 int curmargin =
2762 timings[reg178][channel][slot][rank][lane].largest -
2763 timings[reg178][channel][slot][rank][lane].
2764 smallest + 1;
2765 if (curmargin < margin[reg178])
2766 margin[reg178] = curmargin;
2767 }
2768 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2769 u16 weight;
2770 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2771 sum += weight * reg178;
2772 count += weight;
2773 }
2774 }
2775 dump_timings(info);
2776 if (count == 0)
2777 die("Couldn't discover DRAM timings (3)\n");
2778
2779 u8 threshold;
2780
2781 for (threshold = 30; threshold >= 5; threshold--) {
2782 int usable_length = 0;
2783 int smallest_fount = 0;
2784 for (reg178 = reg178_min[info->clock_speed_index];
2785 reg178 < reg178_max[info->clock_speed_index];
2786 reg178 += reg178_step[info->clock_speed_index])
2787 if (margin[reg178] >= threshold) {
2788 usable_length +=
2789 reg178_step[info->clock_speed_index];
2790 info->training.reg178_largest =
2791 reg178 -
2792 2 * reg178_step[info->clock_speed_index];
2793
2794 if (!smallest_fount) {
2795 smallest_fount = 1;
2796 info->training.reg178_smallest =
2797 reg178 +
2798 reg178_step[info->
2799 clock_speed_index];
2800 }
2801 }
2802 if (usable_length >= 0x21)
2803 break;
2804 }
2805
2806 return sum / count;
2807}
2808
2809static int check_cached_sanity(struct raminfo *info)
2810{
2811 int lane;
2812 int slot, rank;
2813 int channel;
2814
2815 if (!info->cached_training)
2816 return 0;
2817
2818 for (channel = 0; channel < NUM_CHANNELS; channel++)
2819 for (slot = 0; slot < NUM_SLOTS; slot++)
2820 for (rank = 0; rank < NUM_RANKS; rank++)
2821 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2822 u16 cached_value, estimation_value;
2823 cached_value =
2824 info->cached_training->
2825 lane_timings[1][channel][slot][rank]
2826 [lane];
2827 if (cached_value >= 0x18
2828 && cached_value <= 0x1E7) {
2829 estimation_value =
2830 info->training.
2831 lane_timings[1][channel]
2832 [slot][rank][lane];
2833 if (estimation_value <
2834 cached_value - 24)
2835 return 0;
2836 if (estimation_value >
2837 cached_value + 24)
2838 return 0;
2839 }
2840 }
2841 return 1;
2842}
2843
2844static int try_cached_training(struct raminfo *info)
2845{
2846 u8 saved_243[2];
2847 u8 tm;
2848
2849 int channel, slot, rank, lane;
2850 int flip = 1;
2851 int i, j;
2852
2853 if (!check_cached_sanity(info))
2854 return 0;
2855
2856 info->training.reg178_center = info->cached_training->reg178_center;
2857 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2858 info->training.reg178_largest = info->cached_training->reg178_largest;
2859 memcpy(&info->training.timing_bounds,
2860 &info->cached_training->timing_bounds,
2861 sizeof(info->training.timing_bounds));
2862 memcpy(&info->training.timing_offset,
2863 &info->cached_training->timing_offset,
2864 sizeof(info->training.timing_offset));
2865
2866 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002867 saved_243[0] = MCHBAR8(0x243);
2868 saved_243[1] = MCHBAR8(0x643);
2869 MCHBAR8(0x243) = saved_243[0] | 2;
2870 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002871 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002872 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002873 if (read_1d0(0x10b, 6) & 1)
2874 set_10b(info, 0);
2875 for (tm = 0; tm < 2; tm++) {
2876 int totalrank;
2877
2878 set_178(tm ? info->cached_training->reg178_largest : info->
2879 cached_training->reg178_smallest);
2880
2881 totalrank = 0;
2882 /* Check timing ranges. With i == 0 we check smallest one and with
2883 i == 1 the largest bound. With j == 0 we check that on the bound
2884 it still works whereas with j == 1 we check that just outside of
2885 bound we fail.
2886 */
2887 FOR_POPULATED_RANKS_BACKWARDS {
2888 for (i = 0; i < 2; i++) {
2889 for (lane = 0; lane < 8; lane++) {
2890 write_500(info, channel,
2891 info->cached_training->
2892 timing2_bounds[channel][slot]
2893 [rank][lane][i],
2894 get_timing_register_addr(lane,
2895 3,
2896 slot,
2897 rank),
2898 9, 1);
2899
2900 if (!i)
2901 write_500(info, channel,
2902 info->
2903 cached_training->
2904 timing2_offset
2905 [channel][slot][rank]
2906 [lane],
2907 get_timing_register_addr
2908 (lane, 2, slot, rank),
2909 9, 1);
2910 write_500(info, channel,
2911 i ? info->cached_training->
2912 timing_bounds[tm][channel]
2913 [slot][rank][lane].
2914 largest : info->
2915 cached_training->
2916 timing_bounds[tm][channel]
2917 [slot][rank][lane].smallest,
2918 get_timing_register_addr(lane,
2919 0,
2920 slot,
2921 rank),
2922 9, 1);
2923 write_500(info, channel,
2924 info->cached_training->
2925 timing_offset[channel][slot]
2926 [rank][lane] +
2927 (i ? info->cached_training->
2928 timing_bounds[tm][channel]
2929 [slot][rank][lane].
2930 largest : info->
2931 cached_training->
2932 timing_bounds[tm][channel]
2933 [slot][rank][lane].
2934 smallest) - 64,
2935 get_timing_register_addr(lane,
2936 1,
2937 slot,
2938 rank),
2939 9, 1);
2940 }
2941 for (j = 0; j < 2; j++) {
2942 u8 failmask;
2943 u8 expected_failmask;
2944 char reg1b3;
2945
2946 reg1b3 = (j == 1) + 4;
2947 reg1b3 =
2948 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2949 write_1d0(reg1b3, 0x1bb, 6, 1);
2950 write_1d0(reg1b3, 0x1b3, 6, 1);
2951 write_1d0(reg1b3, 0x1a3, 6, 1);
2952
2953 flip = !flip;
2954 write_testing(info, totalrank, flip);
2955 failmask =
2956 check_testing(info, totalrank,
2957 flip);
2958 expected_failmask =
2959 j == 0 ? 0x00 : 0xff;
2960 if (failmask != expected_failmask)
2961 goto fail;
2962 }
2963 }
2964 totalrank++;
2965 }
2966 }
2967
2968 set_178(info->cached_training->reg178_center);
2969 if (info->use_ecc)
2970 set_ecc(1);
2971 write_training_data(info);
2972 write_1d0(0, 322, 3, 1);
2973 info->training = *info->cached_training;
2974
2975 write_1d0(0, 0x1bb, 6, 1);
2976 write_1d0(0, 0x1b3, 6, 1);
2977 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002978 MCHBAR8(0x243) = saved_243[0];
2979 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002980
2981 return 1;
2982
2983fail:
2984 FOR_POPULATED_RANKS {
2985 write_500_timings_type(info, channel, slot, rank, 1);
2986 write_500_timings_type(info, channel, slot, rank, 2);
2987 write_500_timings_type(info, channel, slot, rank, 3);
2988 }
2989
2990 write_1d0(0, 0x1bb, 6, 1);
2991 write_1d0(0, 0x1b3, 6, 1);
2992 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002993 MCHBAR8(0x243) = saved_243[0];
2994 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002995
2996 return 0;
2997}
2998
2999static void do_ram_training(struct raminfo *info)
3000{
3001 u8 saved_243[2];
3002 int totalrank = 0;
3003 u8 reg_178;
3004 int niter;
3005
Matthias Gazzaridfa51252018-05-19 00:44:20 +02003006 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003007 int lane, rank, slot, channel;
3008 u8 reg178_center;
3009
3010 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003011 saved_243[0] = MCHBAR8(0x243);
3012 saved_243[1] = MCHBAR8(0x643);
3013 MCHBAR8(0x243) = saved_243[0] | 2;
3014 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003015 switch (info->clock_speed_index) {
3016 case 0:
3017 niter = 5;
3018 break;
3019 case 1:
3020 niter = 10;
3021 break;
3022 default:
3023 niter = 19;
3024 break;
3025 }
3026 set_ecc(0);
3027
3028 FOR_POPULATED_RANKS_BACKWARDS {
3029 int i;
3030
3031 write_500_timings_type(info, channel, slot, rank, 0);
3032
3033 write_testing(info, totalrank, 0);
3034 for (i = 0; i < niter; i++) {
3035 write_testing_type2(info, totalrank, 2, i, 0);
3036 write_testing_type2(info, totalrank, 3, i, 1);
3037 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003038 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003039 totalrank++;
3040 }
3041
3042 if (reg178_min[info->clock_speed_index] <
3043 reg178_max[info->clock_speed_index])
3044 memset(timings[reg178_min[info->clock_speed_index]], 0,
3045 sizeof(timings[0]) *
3046 (reg178_max[info->clock_speed_index] -
3047 reg178_min[info->clock_speed_index]));
3048 for (reg_178 = reg178_min[info->clock_speed_index];
3049 reg_178 < reg178_max[info->clock_speed_index];
3050 reg_178 += reg178_step[info->clock_speed_index]) {
3051 totalrank = 0;
3052 set_178(reg_178);
3053 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3054 for (slot = 0; slot < NUM_SLOTS; slot++)
3055 for (rank = 0; rank < NUM_RANKS; rank++) {
3056 memset(&timings[reg_178][channel][slot]
3057 [rank][0].smallest, 0, 16);
3058 if (info->
3059 populated_ranks[channel][slot]
3060 [rank]) {
3061 train_ram_at_178(info, channel,
3062 slot, rank,
3063 totalrank,
3064 reg_178, 1,
3065 niter,
3066 timings);
3067 totalrank++;
3068 }
3069 }
3070 }
3071
3072 reg178_center = choose_reg178(info, timings);
3073
3074 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3075 info->training.timing_bounds[0][channel][slot][rank][lane].
3076 smallest =
3077 timings[info->training.
3078 reg178_smallest][channel][slot][rank][lane].
3079 smallest;
3080 info->training.timing_bounds[0][channel][slot][rank][lane].
3081 largest =
3082 timings[info->training.
3083 reg178_smallest][channel][slot][rank][lane].largest;
3084 info->training.timing_bounds[1][channel][slot][rank][lane].
3085 smallest =
3086 timings[info->training.
3087 reg178_largest][channel][slot][rank][lane].smallest;
3088 info->training.timing_bounds[1][channel][slot][rank][lane].
3089 largest =
3090 timings[info->training.
3091 reg178_largest][channel][slot][rank][lane].largest;
3092 info->training.timing_offset[channel][slot][rank][lane] =
3093 info->training.lane_timings[1][channel][slot][rank][lane]
3094 -
3095 info->training.lane_timings[0][channel][slot][rank][lane] +
3096 64;
3097 }
3098
3099 if (info->silicon_revision == 1
3100 && (info->
3101 populated_ranks_mask[1] ^ (info->
3102 populated_ranks_mask[1] >> 2)) & 1) {
3103 int ranks_after_channel1;
3104
3105 totalrank = 0;
3106 for (reg_178 = reg178_center - 18;
3107 reg_178 <= reg178_center + 18; reg_178 += 18) {
3108 totalrank = 0;
3109 set_178(reg_178);
3110 for (slot = 0; slot < NUM_SLOTS; slot++)
3111 for (rank = 0; rank < NUM_RANKS; rank++) {
3112 if (info->
3113 populated_ranks[1][slot][rank]) {
3114 train_ram_at_178(info, 1, slot,
3115 rank,
3116 totalrank,
3117 reg_178, 0,
3118 niter,
3119 timings);
3120 totalrank++;
3121 }
3122 }
3123 }
3124 ranks_after_channel1 = totalrank;
3125
3126 for (reg_178 = reg178_center - 12;
3127 reg_178 <= reg178_center + 12; reg_178 += 12) {
3128 totalrank = ranks_after_channel1;
3129 set_178(reg_178);
3130 for (slot = 0; slot < NUM_SLOTS; slot++)
3131 for (rank = 0; rank < NUM_RANKS; rank++)
3132 if (info->
3133 populated_ranks[0][slot][rank]) {
3134 train_ram_at_178(info, 0, slot,
3135 rank,
3136 totalrank,
3137 reg_178, 0,
3138 niter,
3139 timings);
3140 totalrank++;
3141 }
3142
3143 }
3144 } else {
3145 for (reg_178 = reg178_center - 12;
3146 reg_178 <= reg178_center + 12; reg_178 += 12) {
3147 totalrank = 0;
3148 set_178(reg_178);
3149 FOR_POPULATED_RANKS_BACKWARDS {
3150 train_ram_at_178(info, channel, slot, rank,
3151 totalrank, reg_178, 0, niter,
3152 timings);
3153 totalrank++;
3154 }
3155 }
3156 }
3157
3158 set_178(reg178_center);
3159 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3160 u16 tm0;
3161
3162 tm0 =
3163 choose_training(info, channel, slot, rank, lane, timings,
3164 reg178_center);
3165 write_500(info, channel, tm0,
3166 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3167 write_500(info, channel,
3168 tm0 +
3169 info->training.
3170 lane_timings[1][channel][slot][rank][lane] -
3171 info->training.
3172 lane_timings[0][channel][slot][rank][lane],
3173 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3174 }
3175
3176 totalrank = 0;
3177 FOR_POPULATED_RANKS_BACKWARDS {
3178 try_timing_offsets(info, channel, slot, rank, totalrank);
3179 totalrank++;
3180 }
Felix Held04be2dd2018-07-29 04:53:22 +02003181 MCHBAR8(0x243) = saved_243[0];
3182 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003183 write_1d0(0, 0x142, 3, 1);
3184 info->training.reg178_center = reg178_center;
3185}
3186
3187static void ram_training(struct raminfo *info)
3188{
3189 u16 saved_fc4;
3190
Felix Held04be2dd2018-07-29 04:53:22 +02003191 saved_fc4 = MCHBAR16(0xfc4);
3192 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003193
3194 if (info->revision >= 8)
3195 read_4090(info);
3196
3197 if (!try_cached_training(info))
3198 do_ram_training(info);
3199 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3200 && info->clock_speed_index < 2)
3201 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003202 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003203}
3204
3205static unsigned gcd(unsigned a, unsigned b)
3206{
3207 unsigned t;
3208 if (a > b) {
3209 t = a;
3210 a = b;
3211 b = t;
3212 }
3213 /* invariant a < b. */
3214 while (a) {
3215 t = b % a;
3216 b = a;
3217 a = t;
3218 }
3219 return b;
3220}
3221
3222static inline int div_roundup(int a, int b)
3223{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003224 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003225}
3226
3227static unsigned lcm(unsigned a, unsigned b)
3228{
3229 return (a * b) / gcd(a, b);
3230}
3231
3232struct stru1 {
3233 u8 freqs_reversed;
3234 u8 freq_diff_reduced;
3235 u8 freq_min_reduced;
3236 u8 divisor_f4_to_fmax;
3237 u8 divisor_f3_to_fmax;
3238 u8 freq4_to_max_remainder;
3239 u8 freq3_to_2_remainder;
3240 u8 freq3_to_2_remaindera;
3241 u8 freq4_to_2_remainder;
3242 int divisor_f3_to_f1, divisor_f4_to_f2;
3243 int common_time_unit_ps;
3244 int freq_max_reduced;
3245};
3246
3247static void
3248compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3249 int num_cycles_2, int num_cycles_1, int round_it,
3250 int add_freqs, struct stru1 *result)
3251{
3252 int g;
3253 int common_time_unit_ps;
3254 int freq1_reduced, freq2_reduced;
3255 int freq_min_reduced;
3256 int freq_max_reduced;
3257 int freq3, freq4;
3258
3259 g = gcd(freq1, freq2);
3260 freq1_reduced = freq1 / g;
3261 freq2_reduced = freq2 / g;
3262 freq_min_reduced = min(freq1_reduced, freq2_reduced);
3263 freq_max_reduced = max(freq1_reduced, freq2_reduced);
3264
3265 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3266 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3267 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3268 if (add_freqs) {
3269 freq3 += freq2_reduced;
3270 freq4 += freq1_reduced;
3271 }
3272
3273 if (round_it) {
3274 result->freq3_to_2_remainder = 0;
3275 result->freq3_to_2_remaindera = 0;
3276 result->freq4_to_max_remainder = 0;
3277 result->divisor_f4_to_f2 = 0;
3278 result->divisor_f3_to_f1 = 0;
3279 } else {
3280 if (freq2_reduced < freq1_reduced) {
3281 result->freq3_to_2_remainder =
3282 result->freq3_to_2_remaindera =
3283 freq3 % freq1_reduced - freq1_reduced + 1;
3284 result->freq4_to_max_remainder =
3285 -(freq4 % freq1_reduced);
3286 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3287 result->divisor_f4_to_f2 =
3288 (freq4 -
3289 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3290 result->freq4_to_2_remainder =
3291 -(char)((freq1_reduced - freq2_reduced) +
3292 ((u8) freq4 -
3293 (freq1_reduced -
3294 freq2_reduced)) % (u8) freq2_reduced);
3295 } else {
3296 if (freq2_reduced > freq1_reduced) {
3297 result->freq4_to_max_remainder =
3298 (freq4 % freq2_reduced) - freq2_reduced + 1;
3299 result->freq4_to_2_remainder =
3300 freq4 % freq_max_reduced -
3301 freq_max_reduced + 1;
3302 } else {
3303 result->freq4_to_max_remainder =
3304 -(freq4 % freq2_reduced);
3305 result->freq4_to_2_remainder =
3306 -(char)(freq4 % freq_max_reduced);
3307 }
3308 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3309 result->divisor_f3_to_f1 =
3310 (freq3 -
3311 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3312 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3313 result->freq3_to_2_remaindera =
3314 -(char)((freq_max_reduced - freq_min_reduced) +
3315 (freq3 -
3316 (freq_max_reduced -
3317 freq_min_reduced)) % freq1_reduced);
3318 }
3319 }
3320 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3321 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3322 if (round_it) {
3323 if (freq2_reduced > freq1_reduced) {
3324 if (freq3 % freq_max_reduced)
3325 result->divisor_f3_to_fmax++;
3326 }
3327 if (freq2_reduced < freq1_reduced) {
3328 if (freq4 % freq_max_reduced)
3329 result->divisor_f4_to_fmax++;
3330 }
3331 }
3332 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3333 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3334 result->freq_min_reduced = freq_min_reduced;
3335 result->common_time_unit_ps = common_time_unit_ps;
3336 result->freq_max_reduced = freq_max_reduced;
3337}
3338
3339static void
3340set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3341 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3342 int num_cycles_4, int reverse)
3343{
3344 struct stru1 vv;
3345 char multiplier;
3346
3347 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3348 0, 1, &vv);
3349
3350 multiplier =
3351 div_roundup(max
3352 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3353 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3354 div_roundup(num_cycles_1,
3355 vv.common_time_unit_ps) +
3356 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3357 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3358
3359 u32 y =
3360 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3361 vv.freq_max_reduced * multiplier)
3362 | (vv.
3363 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3364 multiplier) << 16) | ((u8) (vv.
3365 freq_min_reduced
3366 *
3367 multiplier)
3368 << 24);
3369 u32 x =
3370 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3371 divisor_f3_to_f1
3372 << 16)
3373 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3374 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003375 MCHBAR32(reg) = y;
3376 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003377 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003378 MCHBAR32(reg + 4) = y;
3379 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003380 }
3381}
3382
3383static void
3384set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3385 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3386 int num_cycles_4)
3387{
3388 struct stru1 ratios1;
3389 struct stru1 ratios2;
3390
3391 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3392 0, 1, &ratios2);
3393 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3394 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003395 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003396 ratios1.freq4_to_max_remainder | (ratios2.
3397 freq4_to_max_remainder
3398 << 8)
3399 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3400 divisor_f4_to_fmax
3401 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003402 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3403 (ratios2.freq4_to_max_remainder << 8) |
3404 (ratios1.divisor_f4_to_fmax << 16) |
3405 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003406}
3407
3408static void
3409set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3410 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3411{
3412 struct stru1 ratios;
3413
3414 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3415 round_it, add_freqs, &ratios);
3416 switch (mode) {
3417 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003418 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3419 (ratios.freqs_reversed << 8);
3420 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3421 (ratios.freq4_to_max_remainder << 8) |
3422 (ratios.divisor_f3_to_fmax << 16) |
3423 (ratios.divisor_f4_to_fmax << 20) |
3424 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003425 break;
3426
3427 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003428 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3429 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003430 break;
3431
3432 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003433 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3434 (ratios.freq4_to_max_remainder << 8) |
3435 (ratios.divisor_f3_to_fmax << 16) |
3436 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003437 break;
3438
3439 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003440 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3441 (ratios.divisor_f4_to_fmax << 8) |
3442 (ratios.freqs_reversed << 12) |
3443 (ratios.freq_min_reduced << 16) |
3444 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003445 break;
3446 }
3447}
3448
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003449static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003450{
3451 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3452 0, 1);
3453 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3454 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3455 1);
3456 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3457 frequency_11(info), 1231, 1524, 0, 1);
3458 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3459 frequency_11(info) / 2, 1278, 2008, 0, 1);
3460 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3461 1167, 1539, 0, 1);
3462 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3463 frequency_11(info) / 2, 1403, 1318, 0, 1);
3464 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3465 1);
3466 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3467 1);
3468 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3469 1, 1);
3470 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3471 1);
3472 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3473 frequency_11(info) / 2, 4000, 0, 0, 0);
3474 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3475 frequency_11(info) / 2, 4000, 4000, 0, 0);
3476
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003477 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003478 printk(RAM_SPEW, "[6dc] <= %x\n",
3479 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003480 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003481 } else
3482 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3483 info->delay46_ps[0], 0,
3484 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003485 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3486 frequency_11(info), 2500, 0, 0, 0);
3487 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3488 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003489 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003490 printk(RAM_SPEW, "[6e8] <= %x\n",
3491 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003492 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003493 } else
3494 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3495 info->delay46_ps[1], 0,
3496 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003497 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3498 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3499 470, 0);
3500 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3501 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3502 454, 459, 0);
3503 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3504 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3505 2588, 0);
3506 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3507 2405, 0);
3508 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3509 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3510 480, 0);
3511 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003512 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3513 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003514}
3515
3516static u16 get_max_timing(struct raminfo *info, int channel)
3517{
3518 int slot, rank, lane;
3519 u16 ret = 0;
3520
Felix Held04be2dd2018-07-29 04:53:22 +02003521 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003522 return 384;
3523
3524 if (info->revision < 8)
3525 return 256;
3526
3527 for (slot = 0; slot < NUM_SLOTS; slot++)
3528 for (rank = 0; rank < NUM_RANKS; rank++)
3529 if (info->populated_ranks[channel][slot][rank])
3530 for (lane = 0; lane < 8 + info->use_ecc; lane++)
3531 ret = max(ret, read_500(info, channel,
3532 get_timing_register_addr
3533 (lane, 0, slot,
3534 rank), 9));
3535 return ret;
3536}
3537
3538static void set_274265(struct raminfo *info)
3539{
3540 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3541 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3542 int delay_e_over_cycle_ps;
3543 int cycletime_ps;
3544 int channel;
3545
3546 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003547 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003548 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3549 cycletime_ps =
3550 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3551 delay_d_ps =
3552 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3553 - info->some_delay_3_ps_rounded + 200;
3554 if (!
3555 ((info->silicon_revision == 0
3556 || info->silicon_revision == 1)
3557 && (info->revision >= 8)))
3558 delay_d_ps += halfcycle_ps(info) * 2;
3559 delay_d_ps +=
3560 halfcycle_ps(info) * (!info->revision_flag_1 +
3561 info->some_delay_2_halfcycles_ceil +
3562 2 * info->some_delay_1_cycle_floor +
3563 info->clock_speed_index +
3564 2 * info->cas_latency - 7 + 11);
3565 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3566
Felix Held04be2dd2018-07-29 04:53:22 +02003567 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3568 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3569 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003570 delay_d_ps += 650;
3571 delay_c_ps = delay_d_ps + 1800;
3572 if (delay_c_ps <= delay_a_ps)
3573 delay_e_ps = 0;
3574 else
3575 delay_e_ps =
3576 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3577 cycletime_ps);
3578
3579 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3580 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3581 delay_f_cycles =
3582 div_roundup(2500 - delay_e_over_cycle_ps,
3583 2 * halfcycle_ps(info));
3584 if (delay_f_cycles > delay_e_cycles) {
3585 info->delay46_ps[channel] = delay_e_ps;
3586 delay_e_cycles = 0;
3587 } else {
3588 info->delay46_ps[channel] =
3589 delay_e_over_cycle_ps +
3590 2 * halfcycle_ps(info) * delay_f_cycles;
3591 delay_e_cycles -= delay_f_cycles;
3592 }
3593
3594 if (info->delay46_ps[channel] < 2500) {
3595 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003596 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003597 }
3598 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3599 if (delay_b_ps <= delay_a_ps)
3600 delay_b_ps = 0;
3601 else
3602 delay_b_ps -= delay_a_ps;
3603 info->delay54_ps[channel] =
3604 cycletime_ps * div_roundup(delay_b_ps,
3605 cycletime_ps) -
3606 2 * halfcycle_ps(info) * delay_e_cycles;
3607 if (info->delay54_ps[channel] < 2500)
3608 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003609 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003610 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3611 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003612 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003613 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003614 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003615 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3616 4 * halfcycle_ps(info)) - 6;
3617 MCHBAR32((channel << 10) + 0x274) =
3618 info->training.reg274265[channel][1] |
3619 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003620 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003621 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3622 4 * halfcycle_ps(info)) + 1;
3623 MCHBAR16((channel << 10) + 0x265) =
3624 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003625 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003626 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003627 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003628 else
Felix Held04be2dd2018-07-29 04:53:22 +02003629 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003630}
3631
3632static void restore_274265(struct raminfo *info)
3633{
3634 int channel;
3635
3636 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003637 MCHBAR32((channel << 10) + 0x274) =
3638 (info->cached_training->reg274265[channel][0] << 16) |
3639 info->cached_training->reg274265[channel][1];
3640 MCHBAR16((channel << 10) + 0x265) =
3641 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003642 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003643 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003644 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003645 else
Felix Held04be2dd2018-07-29 04:53:22 +02003646 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003647}
3648
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003649static void dmi_setup(void)
3650{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003651 gav(read8(DEFAULT_DMIBAR + 0x254));
3652 write8(DEFAULT_DMIBAR + 0x254, 0x1);
3653 write16(DEFAULT_DMIBAR + 0x1b8, 0x18f2);
Felix Heldf83d80b2018-07-29 05:30:30 +02003654 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003655
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003656 write32(DEFAULT_DMIBAR + 0xd68, read32(DEFAULT_DMIBAR + 0xd68) | 0x08000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003657
3658 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3659 DEFAULT_GPIOBASE | 0x38);
3660 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3661}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003662
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003663void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003664{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003665 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003666 u16 ggc;
3667 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003668
Felix Held04be2dd2018-07-29 04:53:22 +02003669 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003670 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3671 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003672 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003673 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003674 }
Felix Held29a9c072018-07-29 01:34:45 +02003675#if 0
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003676 if (!s3resume) {
3677 pre_raminit_3(x2ca8);
3678 }
Vladimir Serbinenkof62669c2014-01-09 10:59:38 +01003679 pre_raminit_4a(x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003680#endif
3681
3682 dmi_setup();
3683
Felix Held04be2dd2018-07-29 04:53:22 +02003684 MCHBAR16(0x1170) = 0xa880;
3685 MCHBAR8(0x11c1) = 0x1;
3686 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003687 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003688
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003689 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3690 /* 0 for 32MB */
3691 gfxsize = 0;
3692 }
3693
3694 ggc = 0xb00 | ((gfxsize + 5) << 4);
3695
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003696 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003697
3698 u16 deven;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003699 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003700
3701 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003702 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003703 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003704 MCHBAR16_OR(0x2c30, 0x200);
3705 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003706 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003707 pci_read_config8(GMA, 0x62); // = 0x2
3708 pci_write_config8(GMA, 0x62, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003709 read8(DEFAULT_RCBA + 0x2318);
3710 write8(DEFAULT_RCBA + 0x2318, 0x47);
3711 read8(DEFAULT_RCBA + 0x2320);
3712 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003713 }
3714
Felix Heldf83d80b2018-07-29 05:30:30 +02003715 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003716
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003717 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003718 gav(read32(DEFAULT_RCBA + 0x3428));
3719 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003720}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003721
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003722void raminit(const int s3resume, const u8 *spd_addrmap)
3723{
3724 unsigned channel, slot, lane, rank;
3725 int i;
3726 struct raminfo info;
3727 u8 x2ca8;
3728 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003729 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003730
Felix Held04be2dd2018-07-29 04:53:22 +02003731 x2ca8 = MCHBAR8(0x2ca8);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003732 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003733
3734 memset(&info, 0x5a, sizeof(info));
3735
3736 info.last_500_command[0] = 0;
3737 info.last_500_command[1] = 0;
3738
3739 info.fsb_frequency = 135 * 2;
3740 info.board_lane_delay[0] = 0x14;
3741 info.board_lane_delay[1] = 0x07;
3742 info.board_lane_delay[2] = 0x07;
3743 info.board_lane_delay[3] = 0x08;
3744 info.board_lane_delay[4] = 0x56;
3745 info.board_lane_delay[5] = 0x04;
3746 info.board_lane_delay[6] = 0x04;
3747 info.board_lane_delay[7] = 0x05;
3748 info.board_lane_delay[8] = 0x10;
3749
3750 info.training.reg_178 = 0;
3751 info.training.reg_10b = 0;
3752
3753 info.heci_bar = 0;
3754 info.memory_reserved_for_heci_mb = 0;
3755
3756 /* before SPD */
3757 timestamp_add_now(101);
3758
Felix Held29a9c072018-07-29 01:34:45 +02003759 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003760 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003761
3762 collect_system_info(&info);
3763
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003764 /* Enable SMBUS. */
3765 enable_smbus();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003766
3767 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3768
3769 info.use_ecc = 1;
3770 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003771 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003772 int v;
3773 int try;
3774 int addr;
3775 const u8 useful_addresses[] = {
3776 DEVICE_TYPE,
3777 MODULE_TYPE,
3778 DENSITY,
3779 RANKS_AND_DQ,
3780 MEMORY_BUS_WIDTH,
3781 TIMEBASE_DIVIDEND,
3782 TIMEBASE_DIVISOR,
3783 CYCLETIME,
3784 CAS_LATENCIES_LSB,
3785 CAS_LATENCIES_MSB,
3786 CAS_LATENCY_TIME,
3787 0x11, 0x12, 0x13, 0x14, 0x15,
3788 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3789 0x1c, 0x1d,
3790 THERMAL_AND_REFRESH,
3791 0x20,
3792 REFERENCE_RAW_CARD_USED,
3793 RANK1_ADDRESS_MAPPING,
3794 0x75, 0x76, 0x77, 0x78,
3795 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3796 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3797 0x85, 0x86, 0x87, 0x88,
3798 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3799 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3800 0x95
3801 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003802 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003803 continue;
3804 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003805 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003806 DEVICE_TYPE);
3807 if (v >= 0)
3808 break;
3809 }
3810 if (v < 0)
3811 continue;
3812 for (addr = 0;
3813 addr <
3814 sizeof(useful_addresses) /
3815 sizeof(useful_addresses[0]); addr++)
3816 gav(info.
3817 spd[channel][0][useful_addresses
3818 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003819 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003820 useful_addresses
3821 [addr]));
3822 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3823 die("Only DDR3 is supported");
3824
3825 v = info.spd[channel][0][RANKS_AND_DQ];
3826 info.populated_ranks[channel][0][0] = 1;
3827 info.populated_ranks[channel][0][1] =
3828 ((v >> 3) & 7);
3829 if (((v >> 3) & 7) > 1)
3830 die("At most 2 ranks are supported");
3831 if ((v & 7) == 0 || (v & 7) > 2)
3832 die("Only x8 and x16 modules are supported");
3833 if ((info.
3834 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3835 && (info.
3836 spd[channel][slot][MODULE_TYPE] & 0xF)
3837 != 3)
3838 die("Registered memory is not supported");
3839 info.is_x16_module[channel][0] = (v & 7) - 1;
3840 info.density[channel][slot] =
3841 info.spd[channel][slot][DENSITY] & 0xF;
3842 if (!
3843 (info.
3844 spd[channel][slot][MEMORY_BUS_WIDTH] &
3845 0x18))
3846 info.use_ecc = 0;
3847 }
3848
3849 gav(0x55);
3850
3851 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3852 int v = 0;
3853 for (slot = 0; slot < NUM_SLOTS; slot++)
3854 for (rank = 0; rank < NUM_RANKS; rank++)
3855 v |= info.
3856 populated_ranks[channel][slot][rank]
3857 << (2 * slot + rank);
3858 info.populated_ranks_mask[channel] = v;
3859 }
3860
3861 gav(0x55);
3862
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003863 gav(pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003864 }
3865
3866 /* after SPD */
3867 timestamp_add_now(102);
3868
Felix Held04be2dd2018-07-29 04:53:22 +02003869 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003870
3871 collect_system_info(&info);
3872 calculate_timings(&info);
3873
Felix Held29a9c072018-07-29 01:34:45 +02003874#if 0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003875 pci_write_config8(NORTHBRIDGE, 0xdf, 0x82);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003876#endif
3877
3878 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003879 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003880 if (x2ca8 == 0 && (reg8 & 0x80)) {
3881 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3882 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3883 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3884 */
3885
3886 /* Clear bit7. */
3887
3888 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3889 (reg8 & ~(1 << 7)));
3890
3891 printk(BIOS_INFO,
3892 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003893 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003894 }
3895 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003896
3897 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003898 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3899 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003900
3901 compute_derived_timings(&info);
3902
3903 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003904 gav(MCHBAR8(0x164));
3905 MCHBAR8(0x164) = 0x26;
3906 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003907 }
3908
Felix Held04be2dd2018-07-29 04:53:22 +02003909 MCHBAR32_OR(0x18b4, 0x210000);
3910 MCHBAR32_OR(0x1890, 0x2000000);
3911 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003912
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003913 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x50)); // !!!!
3914 pci_write_config8(PCI_DEV(0xff, 2, 1), 0x54, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003915
Felix Held04be2dd2018-07-29 04:53:22 +02003916 gav(MCHBAR16(0x2c10));
3917 MCHBAR16(0x2c10) = 0x412;
3918 gav(MCHBAR16(0x2c10));
3919 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003920
Felix Held04be2dd2018-07-29 04:53:22 +02003921 gav(MCHBAR8(0x2ca8)); // !!!!
3922 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003923
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003924 pci_read_config32(PCI_DEV(0xff, 2, 1), 0x6c); // !!!!
3925 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x6c, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003926 gav(MCHBAR32(0x1c04)); // !!!!
3927 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003928
3929 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003930 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003931 }
3932
Felix Held04be2dd2018-07-29 04:53:22 +02003933 MCHBAR32(0x18d8) = 0x120000;
3934 MCHBAR32(0x18dc) = 0x30a484a;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003935 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x0);
3936 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003937 MCHBAR32(0x18d8) = 0x40000;
3938 MCHBAR32(0x18dc) = 0xb000000;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003939 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x60000);
3940 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003941 MCHBAR32(0x18d8) = 0x180000;
3942 MCHBAR32(0x18dc) = 0xc0000142;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003943 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x20000);
3944 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003945 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003946
Felix Held04be2dd2018-07-29 04:53:22 +02003947 gav(MCHBAR32(0x18dc)); // !!!!
3948 MCHBAR32(0x18dc) = 0x3;
3949 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003950
3951 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003952 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003953 }
3954
Felix Held04be2dd2018-07-29 04:53:22 +02003955 MCHBAR32(0x188c) = 0x20bc09;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003956 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xd0, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003957 MCHBAR32(0x1a10) = 0x4200010e;
3958 MCHBAR32_OR(0x18b8, 0x200);
3959 gav(MCHBAR32(0x1918)); // !!!!
3960 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003961
Felix Held04be2dd2018-07-29 04:53:22 +02003962 gav(MCHBAR32(0x18b8)); // !!!!
3963 MCHBAR32(0x18b8) = 0xe00;
3964 gav(MCHBAR32(0x182c)); // !!!!
3965 MCHBAR32(0x182c) = 0x10202;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003966 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x94)); // !!!!
3967 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x94, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003968 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3969 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003970
Felix Held04be2dd2018-07-29 04:53:22 +02003971 MCHBAR32_AND(0x18b4, 0xffff7fff);
3972 gav(MCHBAR32(0x1a68)); // !!!!
3973 MCHBAR32(0x1a68) = 0x343800;
3974 gav(MCHBAR32(0x1e68)); // !!!!
3975 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003976
3977 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003978 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003979 }
3980
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003981 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x048); // !!!!
3982 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x048, 0x140000);
3983 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3984 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x058, 0x64555);
3985 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3986 pci_read_config32(PCI_DEV (0xff, 0, 0), 0xd0); // !!!!
3987 pci_write_config32(PCI_DEV (0xff, 0, 0), 0xd0, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003988 gav(MCHBAR32(0x1af0)); // !!!!
3989 gav(MCHBAR32(0x1af0)); // !!!!
3990 MCHBAR32(0x1af0) = 0x1f020003;
3991 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003992
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003993 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003994 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003995 }
3996
Felix Held04be2dd2018-07-29 04:53:22 +02003997 gav(MCHBAR32(0x1890)); // !!!!
3998 MCHBAR32(0x1890) = 0x80102;
3999 gav(MCHBAR32(0x18b4)); // !!!!
4000 MCHBAR32(0x18b4) = 0x216000;
4001 MCHBAR32(0x18a4) = 0x22222222;
4002 MCHBAR32(0x18a8) = 0x22222222;
4003 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004004
4005 udelay(1000);
4006
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004007 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004008
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004009 if (x2ca8 == 0) {
4010 int j;
4011 if (s3resume && info.cached_training) {
4012 restore_274265(&info);
Arthur Heymansb3282092019-04-14 17:53:28 +02004013 printk(RAM_DEBUG, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004014 info.cached_training->reg2ca9_bit0);
4015 for (i = 0; i < 2; i++)
4016 for (j = 0; j < 3; j++)
Arthur Heymansb3282092019-04-14 17:53:28 +02004017 printk(RAM_DEBUG, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004018 i, j, info.cached_training->reg274265[i][j]);
4019 } else {
4020 set_274265(&info);
Arthur Heymansb3282092019-04-14 17:53:28 +02004021 printk(RAM_DEBUG, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004022 info.training.reg2ca9_bit0);
4023 for (i = 0; i < 2; i++)
4024 for (j = 0; j < 3; j++)
Arthur Heymansb3282092019-04-14 17:53:28 +02004025 printk(RAM_DEBUG, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004026 i, j, info.training.reg274265[i][j]);
4027 }
4028
4029 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004030
4031 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02004032 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004033 }
4034
4035 udelay(1000);
4036
4037 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02004038 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02004039 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004040 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4041 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4042 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004043
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004044 MCHBAR8(0x1150);
4045 MCHBAR8(0x1151);
4046 MCHBAR8(0x1022);
4047 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004048 MCHBAR32(0x1300) = 0x60606060;
4049 MCHBAR32(0x1304) = 0x60606060;
4050 MCHBAR32(0x1308) = 0x78797a7b;
4051 MCHBAR32(0x130c) = 0x7c7d7e7f;
4052 MCHBAR32(0x1310) = 0x60606060;
4053 MCHBAR32(0x1314) = 0x60606060;
4054 MCHBAR32(0x1318) = 0x60606060;
4055 MCHBAR32(0x131c) = 0x60606060;
4056 MCHBAR32(0x1320) = 0x50515253;
4057 MCHBAR32(0x1324) = 0x54555657;
4058 MCHBAR32(0x1328) = 0x58595a5b;
4059 MCHBAR32(0x132c) = 0x5c5d5e5f;
4060 MCHBAR32(0x1330) = 0x40414243;
4061 MCHBAR32(0x1334) = 0x44454647;
4062 MCHBAR32(0x1338) = 0x48494a4b;
4063 MCHBAR32(0x133c) = 0x4c4d4e4f;
4064 MCHBAR32(0x1340) = 0x30313233;
4065 MCHBAR32(0x1344) = 0x34353637;
4066 MCHBAR32(0x1348) = 0x38393a3b;
4067 MCHBAR32(0x134c) = 0x3c3d3e3f;
4068 MCHBAR32(0x1350) = 0x20212223;
4069 MCHBAR32(0x1354) = 0x24252627;
4070 MCHBAR32(0x1358) = 0x28292a2b;
4071 MCHBAR32(0x135c) = 0x2c2d2e2f;
4072 MCHBAR32(0x1360) = 0x10111213;
4073 MCHBAR32(0x1364) = 0x14151617;
4074 MCHBAR32(0x1368) = 0x18191a1b;
4075 MCHBAR32(0x136c) = 0x1c1d1e1f;
4076 MCHBAR32(0x1370) = 0x10203;
4077 MCHBAR32(0x1374) = 0x4050607;
4078 MCHBAR32(0x1378) = 0x8090a0b;
4079 MCHBAR32(0x137c) = 0xc0d0e0f;
4080 MCHBAR8(0x11cc) = 0x4e;
4081 MCHBAR32(0x1110) = 0x73970404;
4082 MCHBAR32(0x1114) = 0x72960404;
4083 MCHBAR32(0x1118) = 0x6f950404;
4084 MCHBAR32(0x111c) = 0x6d940404;
4085 MCHBAR32(0x1120) = 0x6a930404;
4086 MCHBAR32(0x1124) = 0x68a41404;
4087 MCHBAR32(0x1128) = 0x66a21404;
4088 MCHBAR32(0x112c) = 0x63a01404;
4089 MCHBAR32(0x1130) = 0x609e1404;
4090 MCHBAR32(0x1134) = 0x5f9c1404;
4091 MCHBAR32(0x1138) = 0x5c961404;
4092 MCHBAR32(0x113c) = 0x58a02404;
4093 MCHBAR32(0x1140) = 0x54942404;
4094 MCHBAR32(0x1190) = 0x900080a;
4095 MCHBAR16(0x11c0) = 0xc40b;
4096 MCHBAR16(0x11c2) = 0x303;
4097 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004098 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004099 MCHBAR32(0x11b8) = 0x70c3000;
4100 MCHBAR8(0x11ec) = 0xa;
4101 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004102 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004103 MCHBAR16(0x11ca) = 0xfa;
4104 MCHBAR32(0x11e4) = 0x4e20;
4105 MCHBAR8(0x11bc) = 0xf;
4106 MCHBAR16(0x11da) = 0x19;
4107 MCHBAR16(0x11ba) = 0x470c;
4108 MCHBAR32(0x1680) = 0xe6ffe4ff;
4109 MCHBAR32(0x1684) = 0xdeffdaff;
4110 MCHBAR32(0x1688) = 0xd4ffd0ff;
4111 MCHBAR32(0x168c) = 0xccffc6ff;
4112 MCHBAR32(0x1690) = 0xc0ffbeff;
4113 MCHBAR32(0x1694) = 0xb8ffb0ff;
4114 MCHBAR32(0x1698) = 0xa8ff0000;
4115 MCHBAR32(0x169c) = 0xc00;
4116 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004117 }
4118
Felix Held04be2dd2018-07-29 04:53:22 +02004119 MCHBAR32(0x124c) = 0x15040d00;
4120 MCHBAR32(0x1250) = 0x7f0000;
4121 MCHBAR32(0x1254) = 0x1e220004;
4122 MCHBAR32(0x1258) = 0x4000004;
4123 MCHBAR32(0x1278) = 0x0;
4124 MCHBAR32(0x125c) = 0x0;
4125 MCHBAR32(0x1260) = 0x0;
4126 MCHBAR32(0x1264) = 0x0;
4127 MCHBAR32(0x1268) = 0x0;
4128 MCHBAR32(0x126c) = 0x0;
4129 MCHBAR32(0x1270) = 0x0;
4130 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004131 }
4132
4133 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004134 MCHBAR16(0x1214) = 0x320;
4135 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004136 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4137 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004138 MCHBAR32(0x1400) = 0x13040020;
4139 MCHBAR32(0x1404) = 0xe090120;
4140 MCHBAR32(0x1408) = 0x5120220;
4141 MCHBAR32(0x140c) = 0x5120330;
4142 MCHBAR32(0x1410) = 0xe090220;
4143 MCHBAR32(0x1414) = 0x1010001;
4144 MCHBAR32(0x1418) = 0x1110000;
4145 MCHBAR32(0x141c) = 0x9020020;
4146 MCHBAR32(0x1420) = 0xd090220;
4147 MCHBAR32(0x1424) = 0x2090220;
4148 MCHBAR32(0x1428) = 0x2090330;
4149 MCHBAR32(0x142c) = 0xd090220;
4150 MCHBAR32(0x1430) = 0x1010001;
4151 MCHBAR32(0x1434) = 0x1110000;
4152 MCHBAR32(0x1438) = 0x11040020;
4153 MCHBAR32(0x143c) = 0x4030220;
4154 MCHBAR32(0x1440) = 0x1060220;
4155 MCHBAR32(0x1444) = 0x1060330;
4156 MCHBAR32(0x1448) = 0x4030220;
4157 MCHBAR32(0x144c) = 0x1010001;
4158 MCHBAR32(0x1450) = 0x1110000;
4159 MCHBAR32(0x1454) = 0x4010020;
4160 MCHBAR32(0x1458) = 0xb090220;
4161 MCHBAR32(0x145c) = 0x1090220;
4162 MCHBAR32(0x1460) = 0x1090330;
4163 MCHBAR32(0x1464) = 0xb090220;
4164 MCHBAR32(0x1468) = 0x1010001;
4165 MCHBAR32(0x146c) = 0x1110000;
4166 MCHBAR32(0x1470) = 0xf040020;
4167 MCHBAR32(0x1474) = 0xa090220;
4168 MCHBAR32(0x1478) = 0x1120220;
4169 MCHBAR32(0x147c) = 0x1120330;
4170 MCHBAR32(0x1480) = 0xa090220;
4171 MCHBAR32(0x1484) = 0x1010001;
4172 MCHBAR32(0x1488) = 0x1110000;
4173 MCHBAR32(0x148c) = 0x7020020;
4174 MCHBAR32(0x1490) = 0x1010220;
4175 MCHBAR32(0x1494) = 0x10210;
4176 MCHBAR32(0x1498) = 0x10320;
4177 MCHBAR32(0x149c) = 0x1010220;
4178 MCHBAR32(0x14a0) = 0x1010001;
4179 MCHBAR32(0x14a4) = 0x1110000;
4180 MCHBAR32(0x14a8) = 0xd040020;
4181 MCHBAR32(0x14ac) = 0x8090220;
4182 MCHBAR32(0x14b0) = 0x1111310;
4183 MCHBAR32(0x14b4) = 0x1111420;
4184 MCHBAR32(0x14b8) = 0x8090220;
4185 MCHBAR32(0x14bc) = 0x1010001;
4186 MCHBAR32(0x14c0) = 0x1110000;
4187 MCHBAR32(0x14c4) = 0x3010020;
4188 MCHBAR32(0x14c8) = 0x7090220;
4189 MCHBAR32(0x14cc) = 0x1081310;
4190 MCHBAR32(0x14d0) = 0x1081420;
4191 MCHBAR32(0x14d4) = 0x7090220;
4192 MCHBAR32(0x14d8) = 0x1010001;
4193 MCHBAR32(0x14dc) = 0x1110000;
4194 MCHBAR32(0x14e0) = 0xb040020;
4195 MCHBAR32(0x14e4) = 0x2030220;
4196 MCHBAR32(0x14e8) = 0x1051310;
4197 MCHBAR32(0x14ec) = 0x1051420;
4198 MCHBAR32(0x14f0) = 0x2030220;
4199 MCHBAR32(0x14f4) = 0x1010001;
4200 MCHBAR32(0x14f8) = 0x1110000;
4201 MCHBAR32(0x14fc) = 0x5020020;
4202 MCHBAR32(0x1500) = 0x5090220;
4203 MCHBAR32(0x1504) = 0x2071310;
4204 MCHBAR32(0x1508) = 0x2071420;
4205 MCHBAR32(0x150c) = 0x5090220;
4206 MCHBAR32(0x1510) = 0x1010001;
4207 MCHBAR32(0x1514) = 0x1110000;
4208 MCHBAR32(0x1518) = 0x7040120;
4209 MCHBAR32(0x151c) = 0x2090220;
4210 MCHBAR32(0x1520) = 0x70b1210;
4211 MCHBAR32(0x1524) = 0x70b1310;
4212 MCHBAR32(0x1528) = 0x2090220;
4213 MCHBAR32(0x152c) = 0x1010001;
4214 MCHBAR32(0x1530) = 0x1110000;
4215 MCHBAR32(0x1534) = 0x1010110;
4216 MCHBAR32(0x1538) = 0x1081310;
4217 MCHBAR32(0x153c) = 0x5041200;
4218 MCHBAR32(0x1540) = 0x5041310;
4219 MCHBAR32(0x1544) = 0x1081310;
4220 MCHBAR32(0x1548) = 0x1010001;
4221 MCHBAR32(0x154c) = 0x1110000;
4222 MCHBAR32(0x1550) = 0x1040120;
4223 MCHBAR32(0x1554) = 0x4051210;
4224 MCHBAR32(0x1558) = 0xd051200;
4225 MCHBAR32(0x155c) = 0xd051200;
4226 MCHBAR32(0x1560) = 0x4051210;
4227 MCHBAR32(0x1564) = 0x1010001;
4228 MCHBAR32(0x1568) = 0x1110000;
4229 MCHBAR16(0x1222) = 0x220a;
4230 MCHBAR16(0x123c) = 0x1fc0;
4231 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004232 }
4233
Felix Heldf83d80b2018-07-29 05:30:30 +02004234 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004235 MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004236 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004237
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004238 MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004239
4240 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004241 MCHBAR8_AND(0x2ca8, ~3);
4242 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
4243 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004244 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004245 }
4246
Felix Held04be2dd2018-07-29 04:53:22 +02004247 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004248 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004249 pci_write_config32(PCI_DEV (0xff, 0, 0), 0x60, 0x20220);
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004250 MCHBAR16(0x2c20); // !!!!
4251 MCHBAR16(0x2c10); // !!!!
4252 MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004253 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004254 udelay(1000);
4255 write_1d0(0, 0x33d, 0, 0);
4256 write_500(&info, 0, 0, 0xb61, 0, 0);
4257 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004258 MCHBAR32(0x1a30) = 0x0;
4259 MCHBAR32(0x1a34) = 0x0;
4260 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4261 (info.populated_ranks[0][0][0] * 0xa0);
4262 MCHBAR16(0x616) = 0x26a;
4263 MCHBAR32(0x134) = 0x856000;
4264 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004265 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4266 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004267 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004268 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4269 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004270 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004271 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004272 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4273 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004274 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4275 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4276 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4277 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4278 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4279 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4280 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4281 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4282 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4283 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004284 }
4285
4286 write_1d0(0x4, 0x151, 4, 1);
4287 write_1d0(0, 0x142, 3, 1);
4288 rdmsr(0x1ac); // !!!!
4289 write_500(&info, 1, 1, 0x6b3, 4, 1);
4290 write_500(&info, 1, 1, 0x6cf, 4, 1);
4291
4292 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4293
4294 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4295 populated_ranks[0]
4296 [0][0]) << 0),
4297 0x1d1, 3, 1);
4298 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004299 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4300 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004301 }
4302
4303 set_334(0);
4304
4305 program_base_timings(&info);
4306
Felix Held04be2dd2018-07-29 04:53:22 +02004307 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004308
4309 write_1d0(0x2, 0x1d5, 2, 1);
4310 write_1d0(0x20, 0x166, 7, 1);
4311 write_1d0(0x0, 0xeb, 3, 1);
4312 write_1d0(0x0, 0xf3, 6, 1);
4313
4314 for (channel = 0; channel < NUM_CHANNELS; channel++)
4315 for (lane = 0; lane < 9; lane++) {
4316 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4317 u8 a;
4318 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4319 write_500(&info, channel, a, addr, 6, 1);
4320 }
4321
4322 udelay(1000);
4323
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004324 if (s3resume) {
4325 if (info.cached_training == NULL) {
4326 u32 reg32;
4327 printk(BIOS_ERR,
4328 "Couldn't find training data. Rebooting\n");
4329 reg32 = inl(DEFAULT_PMBASE + 0x04);
4330 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004331 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004332 }
4333 int tm;
4334 info.training = *info.cached_training;
4335 for (tm = 0; tm < 4; tm++)
4336 for (channel = 0; channel < NUM_CHANNELS; channel++)
4337 for (slot = 0; slot < NUM_SLOTS; slot++)
4338 for (rank = 0; rank < NUM_RANKS; rank++)
4339 for (lane = 0; lane < 9; lane++)
4340 write_500(&info,
4341 channel,
4342 info.training.
4343 lane_timings
4344 [tm][channel]
4345 [slot][rank]
4346 [lane],
4347 get_timing_register_addr
4348 (lane, tm,
4349 slot, rank),
4350 9, 0);
4351 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4352 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4353 }
4354
Felix Heldf83d80b2018-07-29 05:30:30 +02004355 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004356 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004357 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004358 MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004359
4360 program_board_delay(&info);
4361
Felix Held04be2dd2018-07-29 04:53:22 +02004362 MCHBAR8(0x5ff) = 0x0;
4363 MCHBAR8(0x5ff) = 0x80;
4364 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004365
Felix Held04be2dd2018-07-29 04:53:22 +02004366 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004367 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004368 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004369 gav(read_1d0(0x14b, 7)); // = 0x81023100
4370 write_1d0(0x30, 0x14b, 7, 1);
4371 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4372 write_1d0(7, 0xd6, 6, 1);
4373 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4374 write_1d0(7, 0x328, 6, 1);
4375
4376 for (channel = 0; channel < NUM_CHANNELS; channel++)
4377 set_4cf(&info, channel,
4378 info.populated_ranks[channel][0][0] ? 8 : 0);
4379
4380 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4381 write_1d0(2, 0x116, 4, 1);
4382 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4383 write_1d0(0, 0xae, 6, 1);
4384 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4385 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004386 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4387 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004388 MCHBAR32_AND(0x140, ~0x07000000);
4389 MCHBAR32_AND(0x138, ~0x07000000);
4390 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004391 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004392 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004393 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004394
4395 {
4396 u32 t;
4397 u8 val_a1;
4398 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4399 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4400 rmw_1d0(0x320, 0x07,
4401 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4402 rmw_1d0(0x14b, 0x78,
4403 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4404 4), 7,
4405 1);
4406 rmw_1d0(0xce, 0x38,
4407 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4408 4), 6,
4409 1);
4410 }
4411
4412 for (channel = 0; channel < NUM_CHANNELS; channel++)
4413 set_4cf(&info, channel,
4414 info.populated_ranks[channel][0][0] ? 9 : 1);
4415
4416 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004417 MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004418 write_1d0(2, 0xae, 6, 1);
4419 write_1d0(2, 0x300, 6, 1);
4420 write_1d0(2, 0x121, 3, 1);
4421 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4422 write_1d0(4, 0xd6, 6, 1);
4423 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4424 write_1d0(4, 0x328, 6, 1);
4425
4426 for (channel = 0; channel < NUM_CHANNELS; channel++)
4427 set_4cf(&info, channel,
4428 info.populated_ranks[channel][0][0] ? 9 : 0);
4429
Felix Held04be2dd2018-07-29 04:53:22 +02004430 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4431 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004432 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004433 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004434 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4435 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4436 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4437 write_1d0(0, 0x21c, 6, 1);
4438 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4439 write_1d0(0x35, 0x14b, 7, 1);
4440
4441 for (channel = 0; channel < NUM_CHANNELS; channel++)
4442 set_4cf(&info, channel,
4443 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4444
4445 set_334(1);
4446
Felix Held04be2dd2018-07-29 04:53:22 +02004447 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004448
4449 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4450 write_500(&info, channel,
4451 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4452 1);
4453 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4454 }
Felix Held04be2dd2018-07-29 04:53:22 +02004455 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4456 MCHBAR16(0x6c0) = 0x14a0;
4457 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4458 MCHBAR16(0x232) = 0x8;
4459 /* 0x40004 or 0 depending on ? */
4460 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4461 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4462 MCHBAR32(0x128) = 0x2150d05;
4463 MCHBAR8(0x12c) = 0x1f;
4464 MCHBAR8(0x12d) = 0x56;
4465 MCHBAR8(0x12e) = 0x31;
4466 MCHBAR8(0x12f) = 0x0;
4467 MCHBAR8(0x271) = 0x2;
4468 MCHBAR8(0x671) = 0x2;
4469 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004470 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004471 MCHBAR32(0x294 + (channel << 10)) =
4472 (info.populated_ranks_mask[channel] & 3) << 16;
4473 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4474 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004475 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004476 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4477 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004478
4479 if (!s3resume)
4480 jedec_init(&info);
4481
4482 int totalrank = 0;
4483 for (channel = 0; channel < NUM_CHANNELS; channel++)
4484 for (slot = 0; slot < NUM_SLOTS; slot++)
4485 for (rank = 0; rank < NUM_RANKS; rank++)
4486 if (info.populated_ranks[channel][slot][rank]) {
4487 jedec_read(&info, channel, slot, rank,
4488 totalrank, 0xa, 0x400);
4489 totalrank++;
4490 }
4491
Felix Held04be2dd2018-07-29 04:53:22 +02004492 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004493
Felix Heldf83d80b2018-07-29 05:30:30 +02004494 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4495 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004496
4497 if (!s3resume) {
4498 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004499 MCHBAR32(0x294 + (channel << 10)) =
4500 (info.populated_ranks_mask[channel] & 3) << 16;
4501 MCHBAR16(0x298 + (channel << 10)) =
4502 info.populated_ranks[channel][0][0] |
4503 (info.populated_ranks[channel][0][1] << 5);
4504 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004505 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004506 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004507
4508 {
4509 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004510 a = MCHBAR8(0x243);
4511 b = MCHBAR8(0x643);
4512 MCHBAR8(0x243) = a | 2;
4513 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004514 }
4515
4516 write_1d0(7, 0x19b, 3, 1);
4517 write_1d0(7, 0x1c0, 3, 1);
4518 write_1d0(4, 0x1c6, 4, 1);
4519 write_1d0(4, 0x1cc, 4, 1);
4520 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4521 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004522 MCHBAR32(0x584) = 0xfffff;
4523 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004524
4525 for (channel = 0; channel < NUM_CHANNELS; channel++)
4526 for (slot = 0; slot < NUM_SLOTS; slot++)
4527 for (rank = 0; rank < NUM_RANKS; rank++)
4528 if (info.
4529 populated_ranks[channel][slot]
4530 [rank])
4531 config_rank(&info, s3resume,
4532 channel, slot,
4533 rank);
4534
Felix Held04be2dd2018-07-29 04:53:22 +02004535 MCHBAR8(0x243) = 0x1;
4536 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004537 }
4538
4539 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004540 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004541 write_26c(0, 0x820);
4542 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004543 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004544 /* end */
4545
4546 if (s3resume) {
4547 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004548 MCHBAR32(0x294 + (channel << 10)) =
4549 (info.populated_ranks_mask[channel] & 3) << 16;
4550 MCHBAR16(0x298 + (channel << 10)) =
4551 info.populated_ranks[channel][0][0] |
4552 (info.populated_ranks[channel][0][1] << 5);
4553 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004554 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004555 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004556 }
4557
Felix Held04be2dd2018-07-29 04:53:22 +02004558 MCHBAR32_AND(0xfa4, ~0x01000002);
4559 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004560
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004561 /* Before training. */
4562 timestamp_add_now(103);
4563
4564 if (!s3resume)
4565 ram_training(&info);
4566
4567 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004568 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004569
4570 dump_timings(&info);
4571
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004572 program_modules_memory_map(&info, 0);
4573 program_total_memory_map(&info);
4574
4575 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004576 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004577 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004578 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004579 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004580 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004581 else
Felix Held04be2dd2018-07-29 04:53:22 +02004582 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004583
Felix Held04be2dd2018-07-29 04:53:22 +02004584 MCHBAR32_AND(0xfac, ~0x80000000);
4585 MCHBAR32(0xfb4) = 0x4800;
4586 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4587 MCHBAR32(0xe94) = 0x7ffff;
4588 MCHBAR32(0xfc0) = 0x80002040;
4589 MCHBAR32(0xfc4) = 0x701246;
4590 MCHBAR8_AND(0xfc8, ~0x70);
4591 MCHBAR32_OR(0xe5c, 0x1000000);
4592 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4593 MCHBAR32(0x50) = 0x700b0;
4594 MCHBAR32(0x3c) = 0x10;
4595 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4596 MCHBAR8_OR(0xff4, 0x2);
4597 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004598
Felix Held29a9c072018-07-29 01:34:45 +02004599#if 1
Felix Held04be2dd2018-07-29 04:53:22 +02004600 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4601 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4602 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004603
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004604 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4605 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4606 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004607
4608#else
4609 {
4610 u32 eax;
Felix Held04be2dd2018-07-29 04:53:22 +02004611 // = 0xe911714b
4612 eax = read32p(0xffc + (MCHBAR32(0xd00) & ~1)) | 0x08000000;
4613 write32p(0xffc + (MCHBAR32(0xd00) & ~1), eax);
4614 // = 0xe911714b
4615 eax = read32p(0xffc + (MCHBAR32(0xdc0) & ~1)) | 0x40000000;
4616 write32p(0xffc + (MCHBAR32(0xdc0) & ~1), eax);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004617 }
4618#endif
4619
4620 {
4621 u32 eax;
4622
4623 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004624 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4625 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4626 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004627 }
4628
4629 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004630 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004631 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004632 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004633 else
Felix Held04be2dd2018-07-29 04:53:22 +02004634 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004635
Felix Held04be2dd2018-07-29 04:53:22 +02004636 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004637
Felix Held04be2dd2018-07-29 04:53:22 +02004638 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004639 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004640 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004641 else
Felix Held04be2dd2018-07-29 04:53:22 +02004642 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004643 }
4644
Felix Held04be2dd2018-07-29 04:53:22 +02004645 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004646
4647 {
4648 u8 al;
4649 al = 0xd;
4650 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4651 al += 2;
4652 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004653 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004654 }
4655
4656 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004657 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4658 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4659 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4660 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004661 }
4662 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004663 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004664 reg1c = read32p(DEFAULT_EPBAR | 0x01c); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004665 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004666 write32p(DEFAULT_EPBAR | 0x01c, reg1c); // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004667 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004668 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004669 MCHBAR8_OR(0x1210, 2);
4670 MCHBAR32(0x1200) = 0x8800440;
4671 MCHBAR32(0x1204) = 0x53ff0453;
4672 MCHBAR32(0x1208) = 0x19002043;
4673 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004674
4675 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004676 MCHBAR16(0x1214) = 0x220;
4677 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004678 }
4679
Felix Held04be2dd2018-07-29 04:53:22 +02004680 MCHBAR8_OR(0x1214, 0x4);
4681 MCHBAR8(0x120c) = 0x1;
4682 MCHBAR8(0x1218) = 0x3;
4683 MCHBAR8(0x121a) = 0x3;
4684 MCHBAR8(0x121c) = 0x3;
4685 MCHBAR16(0xc14) = 0x0;
4686 MCHBAR16(0xc20) = 0x0;
4687 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004688
4689 /* revision dependent here. */
4690
Felix Held04be2dd2018-07-29 04:53:22 +02004691 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004692
4693 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004694 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004695
Felix Held04be2dd2018-07-29 04:53:22 +02004696 MCHBAR16_OR(0x1230, 0x8000);
4697 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004698
4699 u8 bl, ebpb;
4700 u16 reg_1020;
4701
Felix Held04be2dd2018-07-29 04:53:22 +02004702 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4703 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004704
Felix Held04be2dd2018-07-29 04:53:22 +02004705 MCHBAR32(0x1000) = 0x100;
4706 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004707
4708 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004709 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004710 bl = reg_1020 >> 8;
4711 ebpb = reg_1020 & 0xff;
4712 } else {
4713 ebpb = 0;
4714 bl = 8;
4715 }
4716
4717 rdmsr(0x1a2);
4718
Felix Held04be2dd2018-07-29 04:53:22 +02004719 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004720
Felix Held04be2dd2018-07-29 04:53:22 +02004721 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004722
Felix Held04be2dd2018-07-29 04:53:22 +02004723 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004724
Felix Held04be2dd2018-07-29 04:53:22 +02004725 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004726 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004727 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4728 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004729 }
4730
4731 setup_heci_uma(&info);
4732
4733 if (info.uma_enabled) {
4734 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004735 MCHBAR32_OR(0x11b0, 0x4000);
4736 MCHBAR32_OR(0x11b4, 0x4000);
4737 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004738
Felix Held04be2dd2018-07-29 04:53:22 +02004739 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4740 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4741 MCHBAR16_OR(0x1170, 0x1000);
4742
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004743 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004744
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004745 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004746 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004747 ;
4748 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004749 }
4750
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004751 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4752 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004753 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004754 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004755
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004756 udelay(1000);
4757 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004758 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4759
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004760 if (!s3resume)
4761 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004762 if (s3resume && cbmem_wasnot_inited) {
4763 u32 reg32;
4764 printk(BIOS_ERR, "Failed S3 resume.\n");
4765 ram_check(0x100000, 0x200000);
4766
4767 /* Clear SLP_TYPE. */
4768 reg32 = inl(DEFAULT_PMBASE + 0x04);
4769 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4770
4771 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004772 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004773 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004774}