blob: 8a2837e66e5fdce4e084570f1a00dcef9225e044 [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
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010017#include <console/console.h>
Elyes HAOUASba9b5042019-12-19 07:47:52 +010018#include <commonlib/helpers.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010019#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>
Arthur Heymans2878c0b2019-10-14 18:42:00 +020039#include <southbridge/intel/common/pmbase.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010040#include <delay.h>
Elyes HAOUAS51401c32019-05-15 21:09:30 +020041#include <types.h>
42
43#include "chip.h"
44#include "nehalem.h"
45#include "raminit.h"
Angel Pons18a55cd2019-08-14 20:46:00 +020046#include "raminit_tables.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010047
48#define NORTHBRIDGE PCI_DEV(0, 0, 0)
49#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
50#define GMA PCI_DEV (0, 0x2, 0x0)
51#define HECIDEV PCI_DEV(0, 0x16, 0)
52#define HECIBAR 0x10
53
54#define FOR_ALL_RANKS \
55 for (channel = 0; channel < NUM_CHANNELS; channel++) \
56 for (slot = 0; slot < NUM_SLOTS; slot++) \
57 for (rank = 0; rank < NUM_RANKS; rank++)
58
59#define FOR_POPULATED_RANKS \
60 for (channel = 0; channel < NUM_CHANNELS; channel++) \
61 for (slot = 0; slot < NUM_SLOTS; slot++) \
62 for (rank = 0; rank < NUM_RANKS; rank++) \
63 if (info->populated_ranks[channel][slot][rank])
64
65#define FOR_POPULATED_RANKS_BACKWARDS \
66 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
67 for (slot = 0; slot < NUM_SLOTS; slot++) \
68 for (rank = 0; rank < NUM_RANKS; rank++) \
69 if (info->populated_ranks[channel][slot][rank])
70
71/* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */
72typedef struct {
73 u8 smallest;
74 u8 largest;
75} timing_bounds_t[2][2][2][9];
76
Arthur Heymansdc71e252018-01-29 10:14:48 +010077#define MRC_CACHE_VERSION 1
78
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010079struct ram_training {
80 /* [TM][CHANNEL][SLOT][RANK][LANE] */
81 u16 lane_timings[4][2][2][2][9];
82 u16 reg_178;
83 u16 reg_10b;
84
85 u8 reg178_center;
86 u8 reg178_smallest;
87 u8 reg178_largest;
88 timing_bounds_t timing_bounds[2];
89 u16 timing_offset[2][2][2][9];
90 u16 timing2_offset[2][2][2][9];
91 u16 timing2_bounds[2][2][2][9][2];
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +010092 u8 reg274265[2][3]; /* [CHANNEL][REGISTER] */
93 u8 reg2ca9_bit0;
94 u32 reg_6dc;
95 u32 reg_6e8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010096};
97
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010098#include <lib.h> /* Prototypes */
99
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100100
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100101static void clflush(u32 addr)
102{
103 asm volatile ("clflush (%0)"::"r" (addr));
104}
105
106typedef struct _u128 {
107 u64 lo;
108 u64 hi;
109} u128;
110
111static void read128(u32 addr, u64 * out)
112{
113 u128 ret;
114 u128 stor;
115 asm volatile ("movdqu %%xmm0, %0\n"
116 "movdqa (%2), %%xmm0\n"
117 "movdqu %%xmm0, %1\n"
118 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
119 out[0] = ret.lo;
120 out[1] = ret.hi;
121}
122
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100123/* OK */
124static void write_1d0(u32 val, u16 addr, int bits, int flag)
125{
Felix Held04be2dd2018-07-29 04:53:22 +0200126 MCHBAR32(0x1d0) = 0;
127 while (MCHBAR32(0x1d0) & 0x800000)
128 ;
129 MCHBAR32(0x1d4) =
130 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
131 MCHBAR32(0x1d0) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200132 while (MCHBAR32(0x1d0) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200133 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100134}
135
136/* OK */
137static u16 read_1d0(u16 addr, int split)
138{
139 u32 val;
Felix Held04be2dd2018-07-29 04:53:22 +0200140 MCHBAR32(0x1d0) = 0;
141 while (MCHBAR32(0x1d0) & 0x800000)
142 ;
143 MCHBAR32(0x1d0) =
144 0x80000000 | (((MCHBAR8(0x246) >> 2) & 3) + 0x361 - addr);
145 while (MCHBAR32(0x1d0) & 0x800000)
146 ;
147 val = MCHBAR32(0x1d8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100148 write_1d0(0, 0x33d, 0, 0);
149 write_1d0(0, 0x33d, 0, 0);
150 val &= ((1 << split) - 1);
151 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
152 return val;
153}
154
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800155static void write32p(uintptr_t addr, uint32_t val)
156{
157 write32((void *)addr, val);
158}
159
160static uint32_t read32p(uintptr_t addr)
161{
162 return read32((void *)addr);
163}
164
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100165static void sfence(void)
166{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100167 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100168}
169
170static inline u16 get_lane_offset(int slot, int rank, int lane)
171{
172 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
173 0x452 * (lane == 8);
174}
175
176static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
177{
178 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
179 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
180}
181
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100182static u32 gav_real(int line, u32 in)
183{
184 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
185 return in;
186}
187
188#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200189
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100190struct raminfo {
191 u16 clock_speed_index; /* clock_speed (REAL, not DDR) / 133.(3) - 3 */
192 u16 fsb_frequency; /* in 1.(1)/2 MHz. */
193 u8 is_x16_module[2][2]; /* [CHANNEL][SLOT] */
194 u8 density[2][2]; /* [CHANNEL][SLOT] */
195 u8 populated_ranks[2][2][2]; /* [CHANNEL][SLOT][RANK] */
196 int rank_start[2][2][2];
197 u8 cas_latency;
198 u8 board_lane_delay[9];
199 u8 use_ecc;
200 u8 revision;
201 u8 max_supported_clock_speed_index;
202 u8 uma_enabled;
203 u8 spd[2][2][151]; /* [CHANNEL][SLOT][BYTE] */
204 u8 silicon_revision;
205 u8 populated_ranks_mask[2];
206 u8 max_slots_used_in_channel;
207 u8 mode4030[2];
208 u16 avg4044[2];
209 u16 max4048[2];
Martin Roth468d02c2019-10-23 21:44:42 -0600210 unsigned int total_memory_mb;
211 unsigned int interleaved_part_mb;
212 unsigned int non_interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100213
214 u32 heci_bar;
215 u64 heci_uma_addr;
Martin Roth468d02c2019-10-23 21:44:42 -0600216 unsigned int memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100217
218 struct ram_training training;
219 u32 last_500_command[2];
220
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100221 u32 delay46_ps[2];
222 u32 delay54_ps[2];
223 u8 revision_flag_1;
224 u8 some_delay_1_cycle_floor;
225 u8 some_delay_2_halfcycles_ceil;
226 u8 some_delay_3_ps_rounded;
227
228 const struct ram_training *cached_training;
229};
230
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200231/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100232timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200233
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100234static void
235write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
236 int flag);
237
238/* OK */
239static u16
240read_500(struct raminfo *info, int channel, u16 addr, int split)
241{
242 u32 val;
243 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200244 MCHBAR32(0x500 + (channel << 10)) = 0;
245 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
246 ;
247 MCHBAR32(0x500 + (channel << 10)) =
248 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
249 + 0xb88 - addr);
250 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
251 ;
252 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100253 return val & ((1 << split) - 1);
254}
255
256/* OK */
257static void
258write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
259 int flag)
260{
261 if (info->last_500_command[channel] == 0x80000000) {
262 info->last_500_command[channel] = 0x40000000;
263 write_500(info, channel, 0, 0xb61, 0, 0);
264 }
Felix Held04be2dd2018-07-29 04:53:22 +0200265 MCHBAR32(0x500 + (channel << 10)) = 0;
266 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
267 ;
268 MCHBAR32(0x504 + (channel << 10)) =
269 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
270 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200271 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200272 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100273}
274
275static int rw_test(int rank)
276{
277 const u32 mask = 0xf00fc33c;
278 int ok = 0xff;
279 int i;
280 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800281 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100282 sfence();
283 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800284 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100285 sfence();
286 for (i = 0; i < 32; i++) {
287 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800288 write32p((rank << 28) | (i << 3), pat);
289 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100290 }
291 sfence();
292 for (i = 0; i < 32; i++) {
293 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
294 int j;
295 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800296 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100297 for (j = 0; j < 4; j++)
298 if (((val >> (j * 8)) & 0xff) != pat)
299 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800300 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100301 for (j = 0; j < 4; j++)
302 if (((val >> (j * 8)) & 0xff) != pat)
303 ok &= ~(16 << j);
304 }
305 sfence();
306 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800307 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100308 sfence();
309 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800310 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100311
312 return ok;
313}
314
315static void
316program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
317{
318 int lane;
319 for (lane = 0; lane < 8; lane++) {
320 write_500(info, channel,
321 base +
322 info->training.
323 lane_timings[2][channel][slot][rank][lane],
324 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
325 write_500(info, channel,
326 base +
327 info->training.
328 lane_timings[3][channel][slot][rank][lane],
329 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
330 }
331}
332
333static void write_26c(int channel, u16 si)
334{
Felix Held04be2dd2018-07-29 04:53:22 +0200335 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
336 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
337 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100338}
339
340static u32 get_580(int channel, u8 addr)
341{
342 u32 ret;
343 gav(read_1d0(0x142, 3));
Felix Held04be2dd2018-07-29 04:53:22 +0200344 MCHBAR8(0x5ff) = 0x0;
345 MCHBAR8(0x5ff) = 0x80;
346 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
347 MCHBAR8_OR(0x580 + (channel << 10), 1);
348 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
349 ;
350 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100351 return ret;
352}
353
354const int cached_config = 0;
355
356#define NUM_CHANNELS 2
357#define NUM_SLOTS 2
358#define NUM_RANKS 2
359#define RANK_SHIFT 28
360#define CHANNEL_SHIFT 10
361
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100362static 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{
Martin Roth468d02c2019-10-23 21:44:42 -0600552 unsigned int cycletime;
553 unsigned int cas_latency_time;
554 unsigned int supported_cas_latencies;
555 unsigned int channel, slot;
556 unsigned int clock_speed_index;
557 unsigned int min_cas_latency;
558 unsigned int cas_latency;
559 unsigned int max_clock_index;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100560
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
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100574 max_clock_index = MIN(3, info->max_supported_clock_speed_index);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100575
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]) {
Martin Roth468d02c2019-10-23 21:44:42 -0600582 unsigned int timebase;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100583 timebase =
584 1000 *
585 info->
586 spd[channel][slot][TIMEBASE_DIVIDEND] /
587 info->spd[channel][slot][TIMEBASE_DIVISOR];
588 cycletime =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100589 MAX(cycletime,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100590 timebase *
591 info->spd[channel][slot][CYCLETIME]);
592 cas_latency_time =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100593 MAX(cas_latency_time,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100594 timebase *
595 info->
596 spd[channel][slot][CAS_LATENCY_TIME]);
597 }
Jacob Garber3c193822019-06-10 18:23:32 -0600598 if (cycletime > min_cycletime[0])
599 die("RAM init: Decoded SPD DRAM freq is slower than the controller minimum!");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100600 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
601 if (cycletime == min_cycletime[clock_speed_index])
602 break;
603 if (cycletime > min_cycletime[clock_speed_index]) {
604 clock_speed_index--;
605 cycletime = min_cycletime[clock_speed_index];
606 break;
607 }
608 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100609 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100610 cas_latency = 0;
611 while (supported_cas_latencies) {
612 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
613 if (cas_latency <= min_cas_latency)
614 break;
615 supported_cas_latencies &=
616 ~(1 << find_highest_bit_set(supported_cas_latencies));
617 }
618
619 if (cas_latency != min_cas_latency && clock_speed_index)
620 clock_speed_index--;
621
622 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
623 die("Couldn't configure DRAM");
624 info->clock_speed_index = clock_speed_index;
625 info->cas_latency = cas_latency;
626}
627
628static void program_base_timings(struct raminfo *info)
629{
Martin Roth468d02c2019-10-23 21:44:42 -0600630 unsigned int channel;
631 unsigned int slot, rank, lane;
632 unsigned int extended_silicon_revision;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100633 int i;
634
635 extended_silicon_revision = info->silicon_revision;
636 if (info->silicon_revision == 0)
637 for (channel = 0; channel < NUM_CHANNELS; channel++)
638 for (slot = 0; slot < NUM_SLOTS; slot++)
639 if ((info->
640 spd[channel][slot][MODULE_TYPE] & 0xF) ==
641 3)
642 extended_silicon_revision = 4;
643
644 for (channel = 0; channel < NUM_CHANNELS; channel++) {
645 for (slot = 0; slot < NUM_SLOTS; slot++)
646 for (rank = 0; rank < NUM_SLOTS; rank++) {
647 int card_timing_2;
648 if (!info->populated_ranks[channel][slot][rank])
649 continue;
650
651 for (lane = 0; lane < 9; lane++) {
652 int tm_reg;
653 int card_timing;
654
655 card_timing = 0;
656 if ((info->
657 spd[channel][slot][MODULE_TYPE] &
658 0xF) == 3) {
659 int reference_card;
660 reference_card =
661 info->
662 spd[channel][slot]
663 [REFERENCE_RAW_CARD_USED] &
664 0x1f;
665 if (reference_card == 3)
666 card_timing =
667 u16_ffd1188[0][lane]
668 [info->
669 clock_speed_index];
670 if (reference_card == 5)
671 card_timing =
672 u16_ffd1188[1][lane]
673 [info->
674 clock_speed_index];
675 }
676
677 info->training.
678 lane_timings[0][channel][slot][rank]
679 [lane] =
680 u8_FFFD1218[info->
681 clock_speed_index];
682 info->training.
683 lane_timings[1][channel][slot][rank]
684 [lane] = 256;
685
686 for (tm_reg = 2; tm_reg < 4; tm_reg++)
687 info->training.
688 lane_timings[tm_reg]
689 [channel][slot][rank][lane]
690 =
691 u8_FFFD1240[channel]
692 [extended_silicon_revision]
693 [lane][2 * slot +
694 rank][info->
695 clock_speed_index]
696 + info->max4048[channel]
697 +
698 u8_FFFD0C78[channel]
699 [extended_silicon_revision]
700 [info->
701 mode4030[channel]][slot]
702 [rank][info->
703 clock_speed_index]
704 + card_timing;
705 for (tm_reg = 0; tm_reg < 4; tm_reg++)
706 write_500(info, channel,
707 info->training.
708 lane_timings[tm_reg]
709 [channel][slot][rank]
710 [lane],
711 get_timing_register_addr
712 (lane, tm_reg, slot,
713 rank), 9, 0);
714 }
715
716 card_timing_2 = 0;
717 if (!(extended_silicon_revision != 4
718 || (info->
719 populated_ranks_mask[channel] & 5) ==
720 5)) {
721 if ((info->
722 spd[channel][slot]
723 [REFERENCE_RAW_CARD_USED] & 0x1F)
724 == 3)
725 card_timing_2 =
726 u16_FFFE0EB8[0][info->
727 clock_speed_index];
728 if ((info->
729 spd[channel][slot]
730 [REFERENCE_RAW_CARD_USED] & 0x1F)
731 == 5)
732 card_timing_2 =
733 u16_FFFE0EB8[1][info->
734 clock_speed_index];
735 }
736
737 for (i = 0; i < 3; i++)
738 write_500(info, channel,
739 (card_timing_2 +
740 info->max4048[channel]
741 +
742 u8_FFFD0EF8[channel]
743 [extended_silicon_revision]
744 [info->
745 mode4030[channel]][info->
746 clock_speed_index]),
747 u16_fffd0c50[i][slot][rank],
748 8, 1);
749 write_500(info, channel,
750 (info->max4048[channel] +
751 u8_FFFD0C78[channel]
752 [extended_silicon_revision][info->
753 mode4030
754 [channel]]
755 [slot][rank][info->
756 clock_speed_index]),
757 u16_fffd0c70[slot][rank], 7, 1);
758 }
759 if (!info->populated_ranks_mask[channel])
760 continue;
761 for (i = 0; i < 3; i++)
762 write_500(info, channel,
763 (info->max4048[channel] +
764 info->avg4044[channel]
765 +
766 u8_FFFD17E0[channel]
767 [extended_silicon_revision][info->
768 mode4030
769 [channel]][info->
770 clock_speed_index]),
771 u16_fffd0c68[i], 8, 1);
772 }
773}
774
775static unsigned int fsbcycle_ps(struct raminfo *info)
776{
777 return 900000 / info->fsb_frequency;
778}
779
780/* The time of DDR transfer in ps. */
781static unsigned int halfcycle_ps(struct raminfo *info)
782{
783 return 3750 / (info->clock_speed_index + 3);
784}
785
786/* The time of clock cycle in ps. */
787static unsigned int cycle_ps(struct raminfo *info)
788{
789 return 2 * halfcycle_ps(info);
790}
791
792/* Frequency in 1.(1)=10/9 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600793static unsigned int frequency_11(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100794{
795 return (info->clock_speed_index + 3) * 120;
796}
797
798/* Frequency in 0.1 MHz units. */
Martin Roth468d02c2019-10-23 21:44:42 -0600799static unsigned int frequency_01(struct raminfo *info)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100800{
801 return 100 * frequency_11(info) / 9;
802}
803
Martin Roth468d02c2019-10-23 21:44:42 -0600804static unsigned int ps_to_halfcycles(struct raminfo *info, unsigned int ps)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100805{
806 return (frequency_11(info) * 2) * ps / 900000;
807}
808
Martin Roth468d02c2019-10-23 21:44:42 -0600809static unsigned int ns_to_cycles(struct raminfo *info, unsigned int ns)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100810{
811 return (frequency_11(info)) * ns / 900;
812}
813
814static void compute_derived_timings(struct raminfo *info)
815{
Martin Roth468d02c2019-10-23 21:44:42 -0600816 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100817 int extended_silicon_revision;
818 int some_delay_1_ps;
819 int some_delay_2_ps;
820 int some_delay_2_halfcycles_ceil;
821 int some_delay_2_halfcycles_floor;
822 int some_delay_3_ps;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100823 int some_delay_3_ps_rounded;
824 int some_delay_1_cycle_ceil;
825 int some_delay_1_cycle_floor;
826
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100827 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 +=
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100868 MAX(some_delay_1_ps - 30,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100869 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) {
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200874 if (some_delay_3_ps >= 150) {
875 const int some_delay_3_halfcycles =
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100876 (some_delay_3_ps << 6) / halfcycle_ps(info);
Elyes HAOUAS6f7c9552019-10-18 20:20:03 +0200877 some_delay_3_ps_rounded =
878 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
879 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100880 }
881 some_delay_2_halfcycles_ceil =
882 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
883 2 * (some_delay_1_cycle_ceil - 1);
884 if (info->revision_flag_1 && some_delay_3_ps < 150)
885 some_delay_2_halfcycles_ceil++;
886 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
887 if (info->revision < 0x10)
888 some_delay_2_halfcycles_floor =
889 some_delay_2_halfcycles_ceil - 1;
890 if (!info->revision_flag_1)
891 some_delay_2_halfcycles_floor++;
892 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
893 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
894 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
895 || (info->populated_ranks[1][0][0]
896 && info->populated_ranks[1][1][0]))
897 info->max_slots_used_in_channel = 2;
898 else
899 info->max_slots_used_in_channel = 1;
900 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200901 MCHBAR32(0x244 + (channel << 10)) =
902 ((info->revision < 8) ? 1 : 0x200) |
903 ((2 - info->max_slots_used_in_channel) << 17) |
904 (channel << 21) |
905 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100906 if (info->max_slots_used_in_channel == 1) {
907 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
908 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
909 } else {
910 info->mode4030[0] = ((count_ranks_in_channel(info, 0) == 1) || (count_ranks_in_channel(info, 0) == 2)) ? 2 : 3; /* 2 if 1 or 2 ranks */
911 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
912 || (count_ranks_in_channel(info, 1) ==
913 2)) ? 2 : 3;
914 }
915 for (channel = 0; channel < NUM_CHANNELS; channel++) {
916 int max_of_unk;
917 int min_of_unk_2;
918
919 int i, count;
920 int sum;
921
922 if (!info->populated_ranks_mask[channel])
923 continue;
924
925 max_of_unk = 0;
926 min_of_unk_2 = 32767;
927
928 sum = 0;
929 count = 0;
930 for (i = 0; i < 3; i++) {
931 int unk1;
932 if (info->revision < 8)
933 unk1 =
934 u8_FFFD1891[0][channel][info->
935 clock_speed_index]
936 [i];
937 else if (!
938 (info->revision >= 0x10
939 || info->revision_flag_1))
940 unk1 =
941 u8_FFFD1891[1][channel][info->
942 clock_speed_index]
943 [i];
944 else
945 unk1 = 0;
946 for (slot = 0; slot < NUM_SLOTS; slot++)
947 for (rank = 0; rank < NUM_RANKS; rank++) {
948 int a = 0;
949 int b = 0;
950
951 if (!info->
952 populated_ranks[channel][slot]
953 [rank])
954 continue;
955 if (extended_silicon_revision == 4
956 && (info->
957 populated_ranks_mask[channel] &
958 5) != 5) {
959 if ((info->
960 spd[channel][slot]
961 [REFERENCE_RAW_CARD_USED] &
962 0x1F) == 3) {
963 a = u16_ffd1178[0]
964 [info->
965 clock_speed_index];
966 b = u16_fe0eb8[0][info->
967 clock_speed_index];
968 } else
969 if ((info->
970 spd[channel][slot]
971 [REFERENCE_RAW_CARD_USED]
972 & 0x1F) == 5) {
973 a = u16_ffd1178[1]
974 [info->
975 clock_speed_index];
976 b = u16_fe0eb8[1][info->
977 clock_speed_index];
978 }
979 }
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100980 min_of_unk_2 = MIN(min_of_unk_2, a);
981 min_of_unk_2 = MIN(min_of_unk_2, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100982 if (rank == 0) {
983 sum += a;
984 count++;
985 }
986 {
987 int t;
988 t = b +
989 u8_FFFD0EF8[channel]
990 [extended_silicon_revision]
991 [info->
992 mode4030[channel]][info->
993 clock_speed_index];
994 if (unk1 >= t)
995 max_of_unk =
Elyes HAOUASba9b5042019-12-19 07:47:52 +0100996 MAX(max_of_unk,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100997 unk1 - t);
998 }
999 }
1000 {
1001 int t =
1002 u8_FFFD17E0[channel]
1003 [extended_silicon_revision][info->
1004 mode4030
1005 [channel]]
1006 [info->clock_speed_index] + min_of_unk_2;
1007 if (unk1 >= t)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001008 max_of_unk = MAX(max_of_unk, unk1 - t);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001009 }
1010 }
1011
Jacob Garber64fb4a32019-06-10 17:29:18 -06001012 if (count == 0)
1013 die("No memory ranks found for channel %u\n", channel);
1014
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001015 info->avg4044[channel] = sum / count;
1016 info->max4048[channel] = max_of_unk;
1017 }
1018}
1019
1020static void jedec_read(struct raminfo *info,
1021 int channel, int slot, int rank,
1022 int total_rank, u8 addr3, unsigned int value)
1023{
1024 /* Handle mirrored mapping. */
1025 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001026 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1027 ((addr3 >> 1) & 0x10);
1028 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1029 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001030
1031 /* Handle mirrored mapping. */
1032 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1033 value =
1034 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1035 << 1);
1036
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001037 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001038
Felix Held04be2dd2018-07-29 04:53:22 +02001039 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1040 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001041
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001042 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001043}
1044
1045enum {
1046 MR1_RZQ12 = 512,
1047 MR1_RZQ2 = 64,
1048 MR1_RZQ4 = 4,
1049 MR1_ODS34OHM = 2
1050};
1051
1052enum {
1053 MR0_BT_INTERLEAVED = 8,
1054 MR0_DLL_RESET_ON = 256
1055};
1056
1057enum {
1058 MR2_RTT_WR_DISABLED = 0,
1059 MR2_RZQ2 = 1 << 10
1060};
1061
1062static void jedec_init(struct raminfo *info)
1063{
1064 int write_recovery;
1065 int channel, slot, rank;
1066 int total_rank;
1067 int dll_on;
1068 int self_refresh_temperature;
1069 int auto_self_refresh;
1070
1071 auto_self_refresh = 1;
1072 self_refresh_temperature = 1;
1073 if (info->board_lane_delay[3] <= 10) {
1074 if (info->board_lane_delay[3] <= 8)
1075 write_recovery = info->board_lane_delay[3] - 4;
1076 else
1077 write_recovery = 5;
1078 } else {
1079 write_recovery = 6;
1080 }
1081 FOR_POPULATED_RANKS {
1082 auto_self_refresh &=
1083 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1084 self_refresh_temperature &=
1085 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1086 }
1087 if (auto_self_refresh == 1)
1088 self_refresh_temperature = 0;
1089
1090 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1091 || (info->populated_ranks[0][0][0]
1092 && info->populated_ranks[0][1][0])
1093 || (info->populated_ranks[1][0][0]
1094 && info->populated_ranks[1][1][0]));
1095
1096 total_rank = 0;
1097
1098 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1099 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1100 int rzq_reg58e;
1101
1102 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1103 rzq_reg58e = 64;
1104 rtt = MR1_RZQ2;
1105 if (info->clock_speed_index != 0) {
1106 rzq_reg58e = 4;
1107 if (info->populated_ranks_mask[channel] == 3)
1108 rtt = MR1_RZQ4;
1109 }
1110 } else {
1111 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1112 rtt = MR1_RZQ12;
1113 rzq_reg58e = 64;
1114 rtt_wr = MR2_RZQ2;
1115 } else {
1116 rzq_reg58e = 4;
1117 rtt = MR1_RZQ4;
1118 }
1119 }
1120
Felix Held04be2dd2018-07-29 04:53:22 +02001121 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1122 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1123 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1124 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1125 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001126
1127 for (slot = 0; slot < NUM_SLOTS; slot++)
1128 for (rank = 0; rank < NUM_RANKS; rank++)
1129 if (info->populated_ranks[channel][slot][rank]) {
1130 jedec_read(info, channel, slot, rank,
1131 total_rank, 0x28,
1132 rtt_wr | (info->
1133 clock_speed_index
1134 << 3)
1135 | (auto_self_refresh << 6) |
1136 (self_refresh_temperature <<
1137 7));
1138 jedec_read(info, channel, slot, rank,
1139 total_rank, 0x38, 0);
1140 jedec_read(info, channel, slot, rank,
1141 total_rank, 0x18,
1142 rtt | MR1_ODS34OHM);
1143 jedec_read(info, channel, slot, rank,
1144 total_rank, 6,
1145 (dll_on << 12) |
1146 (write_recovery << 9)
1147 | ((info->cas_latency - 4) <<
1148 4) | MR0_BT_INTERLEAVED |
1149 MR0_DLL_RESET_ON);
1150 total_rank++;
1151 }
1152 }
1153}
1154
1155static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1156{
Martin Roth468d02c2019-10-23 21:44:42 -06001157 unsigned int channel, slot, rank;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001158 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1159 unsigned int channel_0_non_interleaved;
1160
1161 FOR_ALL_RANKS {
1162 if (info->populated_ranks[channel][slot][rank]) {
1163 total_mb[channel] +=
1164 pre_jedec ? 256 : (256 << info->
1165 density[channel][slot] >> info->
1166 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001167 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1168 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1169 (info->is_x16_module[channel][slot] |
1170 ((info->density[channel][slot] + 1) << 1))) |
1171 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001172 }
Felix Held04be2dd2018-07-29 04:53:22 +02001173 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1174 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001175 }
1176
1177 info->total_memory_mb = total_mb[0] + total_mb[1];
1178
1179 info->interleaved_part_mb =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001180 pre_jedec ? 0 : 2 * MIN(total_mb[0], total_mb[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001181 info->non_interleaved_part_mb =
1182 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1183 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001184 MCHBAR32(0x100) = channel_0_non_interleaved |
1185 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001186 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001187 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001188}
1189
1190static void program_board_delay(struct raminfo *info)
1191{
1192 int cas_latency_shift;
1193 int some_delay_ns;
1194 int some_delay_3_half_cycles;
1195
Martin Roth468d02c2019-10-23 21:44:42 -06001196 unsigned int channel, i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001197 int high_multiplier;
1198 int lane_3_delay;
1199 int cas_latency_derived;
1200
1201 high_multiplier = 0;
1202 some_delay_ns = 200;
1203 some_delay_3_half_cycles = 4;
1204 cas_latency_shift = info->silicon_revision == 0
1205 || info->silicon_revision == 1 ? 1 : 0;
1206 if (info->revision < 8) {
1207 some_delay_ns = 600;
1208 cas_latency_shift = 0;
1209 }
1210 {
1211 int speed_bit;
1212 speed_bit =
1213 ((info->clock_speed_index > 1
1214 || (info->silicon_revision != 2
1215 && info->silicon_revision != 3))) ^ (info->revision >=
1216 0x10);
1217 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1218 3, 1);
1219 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1220 3, 1);
1221 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1222 && (info->silicon_revision == 2
1223 || info->silicon_revision == 3))
1224 rmw_1d0(0x116, 5, 2, 4, 1);
1225 }
Felix Held04be2dd2018-07-29 04:53:22 +02001226 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1227 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001228
Felix Held04be2dd2018-07-29 04:53:22 +02001229 MCHBAR8(0x124) = info->board_lane_delay[4] +
1230 ((frequency_01(info) + 999) / 1000);
1231 MCHBAR16(0x125) = 0x1360;
1232 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001233 if (info->fsb_frequency < frequency_11(info) / 2) {
Martin Roth468d02c2019-10-23 21:44:42 -06001234 unsigned int some_delay_2_half_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001235 high_multiplier = 1;
1236 some_delay_2_half_cycles = ps_to_halfcycles(info,
1237 ((3 *
1238 fsbcycle_ps(info))
1239 >> 1) +
1240 (halfcycle_ps(info)
1241 *
1242 reg178_min[info->
1243 clock_speed_index]
1244 >> 6)
1245 +
1246 4 *
1247 halfcycle_ps(info)
1248 + 2230);
1249 some_delay_3_half_cycles =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001250 MIN((some_delay_2_half_cycles +
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001251 (frequency_11(info) * 2) * (28 -
1252 some_delay_2_half_cycles) /
1253 (frequency_11(info) * 2 -
1254 4 * (info->fsb_frequency))) >> 3, 7);
1255 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001256 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001257 some_delay_3_half_cycles = 3;
1258 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001259 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1260 MCHBAR32(0x224 + (channel << 10)) =
1261 (info->max_slots_used_in_channel - 1) |
1262 ((info->cas_latency - 5 - info->clock_speed_index)
1263 << 21) | ((info->max_slots_used_in_channel +
1264 info->cas_latency - cas_latency_shift - 4) << 16) |
1265 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1266 ((info->cas_latency - info->clock_speed_index +
1267 info->max_slots_used_in_channel - 6) << 8);
1268 MCHBAR32(0x228 + (channel << 10)) =
1269 info->max_slots_used_in_channel;
1270 MCHBAR8(0x239 + (channel << 10)) = 32;
1271 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1272 (some_delay_3_half_cycles << 25) | 0x840000;
1273 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1274 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1275 MCHBAR32(0x24c + (channel << 10)) =
1276 ((!!info->clock_speed_index) << 17) |
1277 (((2 + info->clock_speed_index -
1278 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001279
Felix Held04be2dd2018-07-29 04:53:22 +02001280 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1281 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1282 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001283
1284 write_500(info, channel,
1285 ((!info->populated_ranks[channel][1][1])
1286 | (!info->populated_ranks[channel][1][0] << 1)
1287 | (!info->populated_ranks[channel][0][1] << 2)
1288 | (!info->populated_ranks[channel][0][0] << 3)),
1289 0x4c9, 4, 1);
1290 }
1291
Felix Held22ca8cb2018-07-29 05:09:44 +02001292 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001293 {
1294 u8 freq_divisor = 2;
1295 if (info->fsb_frequency == frequency_11(info))
1296 freq_divisor = 3;
1297 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1298 freq_divisor = 1;
1299 else
1300 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001301 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001302 }
1303
1304 if (info->board_lane_delay[3] <= 10) {
1305 if (info->board_lane_delay[3] <= 8)
1306 lane_3_delay = info->board_lane_delay[3];
1307 else
1308 lane_3_delay = 10;
1309 } else {
1310 lane_3_delay = 12;
1311 }
1312 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1313 if (info->clock_speed_index > 1)
1314 cas_latency_derived++;
1315 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001316 MCHBAR32(0x240 + (channel << 10)) =
1317 ((info->clock_speed_index == 0) * 0x11000) |
1318 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1319 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001320 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1321 0x609, 6, 1);
1322 write_500(info, channel,
1323 info->clock_speed_index + 2 * info->cas_latency - 7,
1324 0x601, 6, 1);
1325
Felix Held04be2dd2018-07-29 04:53:22 +02001326 MCHBAR32(0x250 + (channel << 10)) =
1327 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1328 (info->board_lane_delay[7] << 2) |
1329 (info->board_lane_delay[4] << 16) |
1330 (info->board_lane_delay[1] << 25) |
1331 (info->board_lane_delay[1] << 29) | 1;
1332 MCHBAR32(0x254 + (channel << 10)) =
1333 (info->board_lane_delay[1] >> 3) |
1334 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1335 0x80 | (info->board_lane_delay[6] << 1) |
1336 (info->board_lane_delay[2] << 28) |
1337 (cas_latency_derived << 16) | 0x4700000;
1338 MCHBAR32(0x258 + (channel << 10)) =
1339 ((info->board_lane_delay[5] + info->clock_speed_index +
1340 9) << 12) | ((info->clock_speed_index -
1341 info->cas_latency + 12) << 8) |
1342 (info->board_lane_delay[2] << 17) |
1343 (info->board_lane_delay[4] << 24) | 0x47;
1344 MCHBAR32(0x25c + (channel << 10)) =
1345 (info->board_lane_delay[1] << 1) |
1346 (info->board_lane_delay[0] << 8) | 0x1da50000;
1347 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1348 MCHBAR8(0x5f8 + (channel << 10)) =
1349 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001350 }
1351
1352 program_modules_memory_map(info, 1);
1353
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001354 MCHBAR16(0x610) = (MIN(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
Felix Held04be2dd2018-07-29 04:53:22 +02001355 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1356 MCHBAR16_OR(0x612, 0x100);
1357 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001358 for (i = 0; i < 8; i++) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001359 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0x80 + 4 * i,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001360 (info->total_memory_mb - 64) | !i | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001361 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0xc0 + 4 * i, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001362 }
1363}
1364
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001365#define DEFAULT_PCI_MMIO_SIZE 2048
1366#define HOST_BRIDGE PCI_DEVFN(0, 0)
1367
1368static unsigned int get_mmio_size(void)
1369{
1370 const struct device *dev;
1371 const struct northbridge_intel_nehalem_config *cfg = NULL;
1372
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001373 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001374 if (dev)
1375 cfg = dev->chip_info;
1376
1377 /* If this is zero, it just means devicetree.cb didn't set it */
1378 if (!cfg || cfg->pci_mmio_size == 0)
1379 return DEFAULT_PCI_MMIO_SIZE;
1380 else
1381 return cfg->pci_mmio_size;
1382}
1383
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001384#define BETTER_MEMORY_MAP 0
1385
1386static void program_total_memory_map(struct raminfo *info)
1387{
1388 unsigned int TOM, TOLUD, TOUUD;
1389 unsigned int quickpath_reserved;
1390 unsigned int REMAPbase;
1391 unsigned int uma_base_igd;
1392 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001393 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001394 int memory_remap;
1395 unsigned int memory_map[8];
1396 int i;
1397 unsigned int current_limit;
1398 unsigned int tseg_base;
1399 int uma_size_igd = 0, uma_size_gtt = 0;
1400
1401 memset(memory_map, 0, sizeof(memory_map));
1402
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001403 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001404 u16 t = pci_read_config16(NORTHBRIDGE, D0F0_GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001405 gav(t);
1406 const int uma_sizes_gtt[16] =
1407 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1408 /* Igd memory */
1409 const int uma_sizes_igd[16] = {
1410 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1411 256, 512
1412 };
1413
1414 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1415 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1416 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001417
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001418 mmio_size = get_mmio_size();
1419
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001420 TOM = info->total_memory_mb;
1421 if (TOM == 4096)
1422 TOM = 4032;
1423 TOUUD = ALIGN_DOWN(TOM - info->memory_reserved_for_heci_mb, 64);
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001424 TOLUD = ALIGN_DOWN(MIN(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
Elyes HAOUASa342f392018-10-17 10:56:26 +02001425 , TOUUD), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001426 memory_remap = 0;
1427 if (TOUUD - TOLUD > 64) {
1428 memory_remap = 1;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001429 REMAPbase = MAX(4096, TOUUD);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001430 TOUUD = TOUUD - TOLUD + 4096;
1431 }
1432 if (TOUUD > 4096)
1433 memory_map[2] = TOUUD | 1;
1434 quickpath_reserved = 0;
1435
Jacob Garber975a7e32019-06-10 16:32:47 -06001436 u32 t = pci_read_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001437
Jacob Garber975a7e32019-06-10 16:32:47 -06001438 gav(t);
1439
1440 if (t & 0x800) {
1441 u32 shift = t >> 20;
1442 if (shift == 0)
1443 die("Quickpath value is 0\n");
1444 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001445 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001446
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001447 if (memory_remap)
1448 TOUUD -= quickpath_reserved;
1449
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001450 uma_base_igd = TOLUD - uma_size_igd;
1451 uma_base_gtt = uma_base_igd - uma_size_gtt;
1452 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1453 if (!memory_remap)
1454 tseg_base -= quickpath_reserved;
1455 tseg_base = ALIGN_DOWN(tseg_base, 8);
1456
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001457 pci_write_config16(NORTHBRIDGE, D0F0_TOLUD, TOLUD << 4);
1458 pci_write_config16(NORTHBRIDGE, D0F0_TOM, TOM >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001459 if (memory_remap) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001460 pci_write_config16(NORTHBRIDGE, D0F0_REMAPBASE, REMAPbase >> 6);
1461 pci_write_config16(NORTHBRIDGE, D0F0_REMAPLIMIT, (TOUUD - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001462 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001463 pci_write_config16(NORTHBRIDGE, D0F0_TOUUD, TOUUD);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001464
1465 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001466 pci_write_config32(NORTHBRIDGE, D0F0_IGD_BASE, uma_base_igd << 20);
1467 pci_write_config32(NORTHBRIDGE, D0F0_GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001468 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001469 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001470
1471 current_limit = 0;
1472 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1473 memory_map[1] = 4096;
1474 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
Elyes HAOUASba9b5042019-12-19 07:47:52 +01001475 current_limit = MAX(current_limit, memory_map[i] & ~1);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001476 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0x80,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001477 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1478 1, 64) | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001479 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0xc0, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001480 }
1481}
1482
1483static void collect_system_info(struct raminfo *info)
1484{
1485 u32 capid0[3];
1486 int i;
Martin Roth468d02c2019-10-23 21:44:42 -06001487 unsigned int channel;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001488
1489 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001490 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1491 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001492
1493 if (!info->heci_bar)
1494 gav(info->heci_bar =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001495 pci_read_config32(HECIDEV, HECIBAR) & 0xFFFFFFF8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001496 if (!info->memory_reserved_for_heci_mb) {
1497 /* Wait for ME to be ready */
1498 intel_early_me_init();
1499 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1500 }
1501
1502 for (i = 0; i < 3; i++)
1503 gav(capid0[i] =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001504 pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 | (i << 2)));
1505 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001506 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1507
1508 if ((capid0[1] >> 11) & 1)
1509 info->uma_enabled = 0;
1510 else
1511 gav(info->uma_enabled =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001512 pci_read_config8(NORTHBRIDGE, D0F0_DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001513 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1514 info->silicon_revision = 0;
1515
1516 if (capid0[2] & 2) {
1517 info->silicon_revision = 0;
1518 info->max_supported_clock_speed_index = 2;
1519 for (channel = 0; channel < NUM_CHANNELS; channel++)
1520 if (info->populated_ranks[channel][0][0]
1521 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1522 3) {
1523 info->silicon_revision = 2;
1524 info->max_supported_clock_speed_index = 1;
1525 }
1526 } else {
1527 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1528 case 1:
1529 case 2:
1530 info->silicon_revision = 3;
1531 break;
1532 case 3:
1533 info->silicon_revision = 0;
1534 break;
1535 case 0:
1536 info->silicon_revision = 2;
1537 break;
1538 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001539 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001540 case 0x40:
1541 info->silicon_revision = 0;
1542 break;
1543 case 0x48:
1544 info->silicon_revision = 1;
1545 break;
1546 }
1547 }
1548}
1549
1550static void write_training_data(struct raminfo *info)
1551{
1552 int tm, channel, slot, rank, lane;
1553 if (info->revision < 8)
1554 return;
1555
1556 for (tm = 0; tm < 4; tm++)
1557 for (channel = 0; channel < NUM_CHANNELS; channel++)
1558 for (slot = 0; slot < NUM_SLOTS; slot++)
1559 for (rank = 0; rank < NUM_RANKS; rank++)
1560 for (lane = 0; lane < 9; lane++)
1561 write_500(info, channel,
1562 info->
1563 cached_training->
1564 lane_timings[tm]
1565 [channel][slot][rank]
1566 [lane],
1567 get_timing_register_addr
1568 (lane, tm, slot,
1569 rank), 9, 0);
1570 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1571 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1572}
1573
1574static void dump_timings(struct raminfo *info)
1575{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001576 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001577 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001578 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001579 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001580 slot, rank);
1581 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001582 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001583 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001584 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001585 read_500(info, channel,
1586 get_timing_register_addr
1587 (lane, i, slot, rank),
1588 9),
1589 info->training.
1590 lane_timings[i][channel][slot][rank]
1591 [lane]);
1592 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001593 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001594 }
1595 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001596 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001597 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001598 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001599 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001600}
1601
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001602/* Read timings and other registers that need to be restored verbatim and
1603 put them to CBMEM.
1604 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001605static void save_timings(struct raminfo *info)
1606{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001607 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001608 int channel, slot, rank, lane, i;
1609
1610 train = info->training;
1611 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1612 for (i = 0; i < 4; i++)
1613 train.lane_timings[i][channel][slot][rank][lane] =
1614 read_500(info, channel,
1615 get_timing_register_addr(lane, i, slot,
1616 rank), 9);
1617 train.reg_178 = read_1d0(0x178, 7);
1618 train.reg_10b = read_1d0(0x10b, 6);
1619
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001620 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1621 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001622 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001623 train.reg274265[channel][0] = reg32 >> 16;
1624 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001625 train.reg274265[channel][2] =
1626 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001627 }
Felix Held04be2dd2018-07-29 04:53:22 +02001628 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1629 train.reg_6dc = MCHBAR32(0x6dc);
1630 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001631
Arthur Heymansb3282092019-04-14 17:53:28 +02001632 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1633 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001634
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001635 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001636 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1637 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001638}
1639
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001640static const struct ram_training *get_cached_training(void)
1641{
Arthur Heymansdc71e252018-01-29 10:14:48 +01001642 struct region_device rdev;
1643 if (mrc_cache_get_current(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1644 &rdev))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001645 return 0;
Arthur Heymansdc71e252018-01-29 10:14:48 +01001646 return (void *)rdev_mmap_full(&rdev);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001647}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001648
1649/* FIXME: add timeout. */
1650static void wait_heci_ready(void)
1651{
Felix Held04be2dd2018-07-29 04:53:22 +02001652 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1653 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001654 write32((DEFAULT_HECIBAR + 0x4),
1655 (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001656}
1657
1658/* FIXME: add timeout. */
1659static void wait_heci_cb_avail(int len)
1660{
1661 union {
1662 struct mei_csr csr;
1663 u32 raw;
1664 } csr;
1665
Felix Held22ca8cb2018-07-29 05:09:44 +02001666 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1667 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001668
1669 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001670 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001671 while (len >
1672 csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
Felix Held22ca8cb2018-07-29 05:09:44 +02001673 csr.csr.buffer_read_ptr))
1674 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001675}
1676
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001677static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001678{
1679 int len = (head->length + 3) / 4;
1680 int i;
1681
1682 wait_heci_cb_avail(len + 1);
1683
1684 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001685 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001686 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001687 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001688
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001689 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1690 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001691}
1692
1693static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001694send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001695{
1696 struct mei_header head;
1697 int maxlen;
1698
1699 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001700 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001701
1702 while (len) {
1703 int cur = len;
1704 if (cur > maxlen) {
1705 cur = maxlen;
1706 head.is_complete = 0;
1707 } else
1708 head.is_complete = 1;
1709 head.length = cur;
1710 head.reserved = 0;
1711 head.client_address = clientaddress;
1712 head.host_address = hostaddress;
1713 send_heci_packet(&head, (u32 *) msg);
1714 len -= cur;
1715 msg += cur;
1716 }
1717}
1718
1719/* FIXME: Add timeout. */
1720static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001721recv_heci_packet(struct raminfo *info, struct mei_header *head, u32 *packet,
1722 u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001723{
1724 union {
1725 struct mei_csr csr;
1726 u32 raw;
1727 } csr;
1728 int i = 0;
1729
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001730 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001731 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001732 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001733 }
Felix Held04be2dd2018-07-29 04:53:22 +02001734 while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr)
1735 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001736 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001737 if (!head->length) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001738 write32(DEFAULT_HECIBAR + 0x4,
1739 read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001740 *packet_size = 0;
1741 return 0;
1742 }
1743 if (head->length + 4 > 4 * csr.csr.buffer_depth
1744 || head->length > *packet_size) {
1745 *packet_size = 0;
1746 return -1;
1747 }
1748
1749 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001750 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Felix Held22ca8cb2018-07-29 05:09:44 +02001751 while (((head->length + 3) >> 2) >
1752 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr))
1753 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001754
1755 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001756 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001757 *packet_size = head->length;
1758 if (!csr.csr.ready)
1759 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001760 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001761 return 0;
1762}
1763
1764/* FIXME: Add timeout. */
1765static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001766recv_heci_message(struct raminfo *info, u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001767{
1768 struct mei_header head;
1769 int current_position;
1770
1771 current_position = 0;
1772 while (1) {
1773 u32 current_size;
1774 current_size = *message_size - current_position;
1775 if (recv_heci_packet
1776 (info, &head, message + (current_position >> 2),
1777 &current_size) == -1)
1778 break;
1779 if (!current_size)
1780 break;
1781 current_position += current_size;
1782 if (head.is_complete) {
1783 *message_size = current_position;
1784 return 0;
1785 }
1786
1787 if (current_position >= *message_size)
1788 break;
1789 }
1790 *message_size = 0;
1791 return -1;
1792}
1793
1794static void send_heci_uma_message(struct raminfo *info)
1795{
1796 struct uma_reply {
1797 u8 group_id;
1798 u8 command;
1799 u8 reserved;
1800 u8 result;
1801 u8 field2;
1802 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001803 } __packed reply;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001804 struct uma_message {
1805 u8 group_id;
1806 u8 cmd;
1807 u8 reserved;
1808 u8 result;
1809 u32 c2;
1810 u64 heci_uma_addr;
1811 u32 memory_reserved_for_heci_mb;
1812 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001813 } __packed msg = {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001814 0, MKHI_SET_UMA, 0, 0,
1815 0x82,
1816 info->heci_uma_addr, info->memory_reserved_for_heci_mb, 0};
1817 u32 reply_size;
1818
1819 send_heci_message((u8 *) & msg, sizeof(msg), 0, 7);
1820
1821 reply_size = sizeof(reply);
1822 if (recv_heci_message(info, (u32 *) & reply, &reply_size) == -1)
1823 return;
1824
1825 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1826 die("HECI init failed\n");
1827}
1828
1829static void setup_heci_uma(struct raminfo *info)
1830{
1831 u32 reg44;
1832
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001833 reg44 = pci_read_config32(HECIDEV, 0x44); // = 0x80010020
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001834 info->memory_reserved_for_heci_mb = 0;
1835 info->heci_uma_addr = 0;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001836 if (!((reg44 & 0x10000) && !(pci_read_config32(HECIDEV, 0x40) & 0x20)))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001837 return;
1838
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001839 info->heci_bar = pci_read_config32(HECIDEV, 0x10) & 0xFFFFFFF0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001840 info->memory_reserved_for_heci_mb = reg44 & 0x3f;
1841 info->heci_uma_addr =
1842 ((u64)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001843 ((((u64) pci_read_config16(NORTHBRIDGE, D0F0_TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001844 info->memory_reserved_for_heci_mb)) << 20;
1845
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001846 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001847 if (info->memory_reserved_for_heci_mb) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001848 write32(DEFAULT_DMIBAR + 0x14,
1849 read32(DEFAULT_DMIBAR + 0x14) & ~0x80);
1850 write32(DEFAULT_RCBA + 0x14,
1851 read32(DEFAULT_RCBA + 0x14) & ~0x80);
1852 write32(DEFAULT_DMIBAR + 0x20,
1853 read32(DEFAULT_DMIBAR + 0x20) & ~0x80);
1854 write32(DEFAULT_RCBA + 0x20,
1855 read32(DEFAULT_RCBA + 0x20) & ~0x80);
1856 write32(DEFAULT_DMIBAR + 0x2c,
1857 read32(DEFAULT_DMIBAR + 0x2c) & ~0x80);
1858 write32(DEFAULT_RCBA + 0x30,
1859 read32(DEFAULT_RCBA + 0x30) & ~0x80);
1860 write32(DEFAULT_DMIBAR + 0x38,
1861 read32(DEFAULT_DMIBAR + 0x38) & ~0x80);
1862 write32(DEFAULT_RCBA + 0x40,
1863 read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001864
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001865 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
1866 write32(DEFAULT_DMIBAR + 0x38, 0x87000080); // OK
Felix Held04be2dd2018-07-29 04:53:22 +02001867 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
1868 read16(DEFAULT_DMIBAR + 0x3e) & 2)
1869 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001870 }
1871
Felix Held04be2dd2018-07-29 04:53:22 +02001872 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001873
1874 send_heci_uma_message(info);
1875
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001876 pci_write_config32(HECIDEV, 0x10, 0x0);
1877 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001878
1879}
1880
1881static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1882{
1883 int ranks_in_channel;
1884 ranks_in_channel = info->populated_ranks[channel][0][0]
1885 + info->populated_ranks[channel][0][1]
1886 + info->populated_ranks[channel][1][0]
1887 + info->populated_ranks[channel][1][1];
1888
1889 /* empty channel */
1890 if (ranks_in_channel == 0)
1891 return 1;
1892
1893 if (ranks_in_channel != ranks)
1894 return 0;
1895 /* single slot */
1896 if (info->populated_ranks[channel][0][0] !=
1897 info->populated_ranks[channel][1][0])
1898 return 1;
1899 if (info->populated_ranks[channel][0][1] !=
1900 info->populated_ranks[channel][1][1])
1901 return 1;
1902 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1903 return 0;
1904 if (info->density[channel][0] != info->density[channel][1])
1905 return 0;
1906 return 1;
1907}
1908
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001909static void read_4090(struct raminfo *info)
1910{
1911 int i, channel, slot, rank, lane;
1912 for (i = 0; i < 2; i++)
1913 for (slot = 0; slot < NUM_SLOTS; slot++)
1914 for (rank = 0; rank < NUM_RANKS; rank++)
1915 for (lane = 0; lane < 9; lane++)
1916 info->training.
1917 lane_timings[0][i][slot][rank][lane]
1918 = 32;
1919
1920 for (i = 1; i < 4; i++)
1921 for (channel = 0; channel < NUM_CHANNELS; channel++)
1922 for (slot = 0; slot < NUM_SLOTS; slot++)
1923 for (rank = 0; rank < NUM_RANKS; rank++)
1924 for (lane = 0; lane < 9; lane++) {
1925 info->training.
1926 lane_timings[i][channel]
1927 [slot][rank][lane] =
1928 read_500(info, channel,
1929 get_timing_register_addr
1930 (lane, i, slot,
1931 rank), 9)
1932 + (i == 1) * 11; // !!!!
1933 }
1934
1935}
1936
1937static u32 get_etalon2(int flip, u32 addr)
1938{
1939 const u16 invmask[] = {
1940 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1941 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1942 };
1943 u32 ret;
1944 u32 comp4 = addr / 480;
1945 addr %= 480;
1946 u32 comp1 = addr & 0xf;
1947 u32 comp2 = (addr >> 4) & 1;
1948 u32 comp3 = addr >> 5;
1949
1950 if (comp4)
1951 ret = 0x1010101 << (comp4 - 1);
1952 else
1953 ret = 0;
1954 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1955 ret = ~ret;
1956
1957 return ret;
1958}
1959
1960static void disable_cache(void)
1961{
1962 msr_t msr = {.lo = 0, .hi = 0 };
1963
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001964 wrmsr(MTRR_PHYS_BASE(3), msr);
1965 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001966}
1967
1968static void enable_cache(unsigned int base, unsigned int size)
1969{
1970 msr_t msr;
1971 msr.lo = base | MTRR_TYPE_WRPROT;
1972 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001973 wrmsr(MTRR_PHYS_BASE(3), msr);
1974 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001975 & 0xffffffff);
1976 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001977 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001978}
1979
1980static void flush_cache(u32 start, u32 size)
1981{
1982 u32 end;
1983 u32 addr;
1984
1985 end = start + (ALIGN_DOWN(size + 4096, 4096));
1986 for (addr = start; addr < end; addr += 64)
1987 clflush(addr);
1988}
1989
1990static void clear_errors(void)
1991{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001992 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001993}
1994
1995static void write_testing(struct raminfo *info, int totalrank, int flip)
1996{
1997 int nwrites = 0;
1998 /* in 8-byte units. */
1999 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002000 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002001
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002002 base = (u8 *)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002003 for (offset = 0; offset < 9 * 480; offset += 2) {
2004 write32(base + offset * 8, get_etalon2(flip, offset));
2005 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
2006 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
2007 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
2008 nwrites += 4;
2009 if (nwrites >= 320) {
2010 clear_errors();
2011 nwrites = 0;
2012 }
2013 }
2014}
2015
2016static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
2017{
2018 u8 failmask = 0;
2019 int i;
2020 int comp1, comp2, comp3;
2021 u32 failxor[2] = { 0, 0 };
2022
2023 enable_cache((total_rank << 28), 1728 * 5 * 4);
2024
2025 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
2026 for (comp1 = 0; comp1 < 4; comp1++)
2027 for (comp2 = 0; comp2 < 60; comp2++) {
2028 u32 re[4];
2029 u32 curroffset =
2030 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
2031 read128((total_rank << 28) | (curroffset << 3),
2032 (u64 *) re);
2033 failxor[0] |=
2034 get_etalon2(flip, curroffset) ^ re[0];
2035 failxor[1] |=
2036 get_etalon2(flip, curroffset) ^ re[1];
2037 failxor[0] |=
2038 get_etalon2(flip, curroffset | 1) ^ re[2];
2039 failxor[1] |=
2040 get_etalon2(flip, curroffset | 1) ^ re[3];
2041 }
2042 for (i = 0; i < 8; i++)
2043 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2044 failmask |= 1 << i;
2045 }
2046 disable_cache();
2047 flush_cache((total_rank << 28), 1728 * 5 * 4);
2048 return failmask;
2049}
2050
2051const u32 seed1[0x18] = {
2052 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2053 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2054 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2055 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2056 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2057 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2058};
2059
2060static u32 get_seed2(int a, int b)
2061{
2062 const u32 seed2[5] = {
2063 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2064 0x5b6db6db,
2065 };
2066 u32 r;
2067 r = seed2[(a + (a >= 10)) / 5];
2068 return b ? ~r : r;
2069}
2070
2071static int make_shift(int comp2, int comp5, int x)
2072{
2073 const u8 seed3[32] = {
2074 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2075 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2076 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2077 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2078 };
2079
2080 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2081}
2082
2083static u32 get_etalon(int flip, u32 addr)
2084{
2085 u32 mask_byte = 0;
2086 int comp1 = (addr >> 1) & 1;
2087 int comp2 = (addr >> 3) & 0x1f;
2088 int comp3 = (addr >> 8) & 0xf;
2089 int comp4 = (addr >> 12) & 0xf;
2090 int comp5 = (addr >> 16) & 0x1f;
2091 u32 mask_bit = ~(0x10001 << comp3);
2092 u32 part1;
2093 u32 part2;
2094 int byte;
2095
2096 part2 =
2097 ((seed1[comp5] >>
2098 make_shift(comp2, comp5,
2099 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2100 part1 =
2101 ((seed1[comp5] >>
2102 make_shift(comp2, comp5,
2103 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2104
2105 for (byte = 0; byte < 4; byte++)
2106 if ((get_seed2(comp5, comp4) >>
2107 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2108 mask_byte |= 0xff << (8 * byte);
2109
2110 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2111 (comp3 + 16));
2112}
2113
2114static void
2115write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2116 char flip)
2117{
2118 int i;
2119 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002120 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2121 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002122}
2123
2124static u8
2125check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2126 char flip)
2127{
2128 u8 failmask = 0;
2129 u32 failxor[2];
2130 int i;
2131 int comp1, comp2, comp3;
2132
2133 failxor[0] = 0;
2134 failxor[1] = 0;
2135
2136 enable_cache(totalrank << 28, 134217728);
2137 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2138 for (comp1 = 0; comp1 < 16; comp1++)
2139 for (comp2 = 0; comp2 < 64; comp2++) {
2140 u32 addr =
2141 (totalrank << 28) | (region << 25) | (block
2142 << 16)
2143 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2144 2);
2145 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002146 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002147 }
2148 for (i = 0; i < 8; i++)
2149 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2150 failmask |= 1 << i;
2151 }
2152 disable_cache();
2153 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2154 return failmask;
2155}
2156
2157static int check_bounded(unsigned short *vals, u16 bound)
2158{
2159 int i;
2160
2161 for (i = 0; i < 8; i++)
2162 if (vals[i] < bound)
2163 return 0;
2164 return 1;
2165}
2166
2167enum state {
2168 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2169};
2170
2171static int validate_state(enum state *in)
2172{
2173 int i;
2174 for (i = 0; i < 8; i++)
2175 if (in[i] != COMPLETE)
2176 return 0;
2177 return 1;
2178}
2179
2180static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002181do_fsm(enum state *state, u16 *counter,
2182 u8 fail_mask, int margin, int uplimit,
2183 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002184{
2185 int lane;
2186
2187 for (lane = 0; lane < 8; lane++) {
2188 int is_fail = (fail_mask >> lane) & 1;
2189 switch (state[lane]) {
2190 case BEFORE_USABLE:
2191 if (!is_fail) {
2192 counter[lane] = 1;
2193 state[lane] = AT_USABLE;
2194 break;
2195 }
2196 counter[lane] = 0;
2197 state[lane] = BEFORE_USABLE;
2198 break;
2199 case AT_USABLE:
2200 if (!is_fail) {
2201 ++counter[lane];
2202 if (counter[lane] >= margin) {
2203 state[lane] = AT_MARGIN;
2204 res_low[lane] = val - margin + 1;
2205 break;
2206 }
2207 state[lane] = 1;
2208 break;
2209 }
2210 counter[lane] = 0;
2211 state[lane] = BEFORE_USABLE;
2212 break;
2213 case AT_MARGIN:
2214 if (is_fail) {
2215 state[lane] = COMPLETE;
2216 res_high[lane] = val - 1;
2217 } else {
2218 counter[lane]++;
2219 state[lane] = AT_MARGIN;
2220 if (val == uplimit) {
2221 state[lane] = COMPLETE;
2222 res_high[lane] = uplimit;
2223 }
2224 }
2225 break;
2226 case COMPLETE:
2227 break;
2228 }
2229 }
2230}
2231
2232static void
2233train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2234 u8 total_rank, u8 reg_178, int first_run, int niter,
2235 timing_bounds_t * timings)
2236{
2237 int lane;
2238 enum state state[8];
2239 u16 count[8];
2240 u8 lower_usable[8];
2241 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002242 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002243 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002244 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002245
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002246 for (i = 0; i < 8; i++)
2247 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002248
2249 if (!first_run) {
2250 int is_all_ok = 1;
2251 for (lane = 0; lane < 8; lane++)
2252 if (timings[reg_178][channel][slot][rank][lane].
2253 smallest ==
2254 timings[reg_178][channel][slot][rank][lane].
2255 largest) {
2256 timings[reg_178][channel][slot][rank][lane].
2257 smallest = 0;
2258 timings[reg_178][channel][slot][rank][lane].
2259 largest = 0;
2260 is_all_ok = 0;
2261 }
2262 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002263 for (i = 0; i < 8; i++)
2264 state[i] = COMPLETE;
2265 }
2266 }
2267
2268 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2269 u8 failmask = 0;
2270 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2271 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2272 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002273 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002274 do_fsm(state, count, failmask, 5, 47, lower_usable,
2275 upper_usable, reg1b3);
2276 }
2277
2278 if (reg1b3) {
2279 write_1d0(0, 0x1b3, 6, 1);
2280 write_1d0(0, 0x1a3, 6, 1);
2281 for (lane = 0; lane < 8; lane++) {
2282 if (state[lane] == COMPLETE) {
2283 timings[reg_178][channel][slot][rank][lane].
2284 smallest =
2285 lower_usable[lane] +
2286 (info->training.
2287 lane_timings[0][channel][slot][rank][lane]
2288 & 0x3F) - 32;
2289 timings[reg_178][channel][slot][rank][lane].
2290 largest =
2291 upper_usable[lane] +
2292 (info->training.
2293 lane_timings[0][channel][slot][rank][lane]
2294 & 0x3F) - 32;
2295 }
2296 }
2297 }
2298
2299 if (!first_run) {
2300 for (lane = 0; lane < 8; lane++)
2301 if (state[lane] == COMPLETE) {
2302 write_500(info, channel,
2303 timings[reg_178][channel][slot][rank]
2304 [lane].smallest,
2305 get_timing_register_addr(lane, 0,
2306 slot, rank),
2307 9, 1);
2308 write_500(info, channel,
2309 timings[reg_178][channel][slot][rank]
2310 [lane].smallest +
2311 info->training.
2312 lane_timings[1][channel][slot][rank]
2313 [lane]
2314 -
2315 info->training.
2316 lane_timings[0][channel][slot][rank]
2317 [lane], get_timing_register_addr(lane,
2318 1,
2319 slot,
2320 rank),
2321 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002322 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002323 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002324 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002325
2326 do {
2327 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002328 for (i = 0; i < niter; i++) {
2329 if (failmask == 0xFF)
2330 break;
2331 failmask |=
2332 check_testing_type2(info, total_rank, 2, i,
2333 0);
2334 failmask |=
2335 check_testing_type2(info, total_rank, 3, i,
2336 1);
2337 }
Felix Held04be2dd2018-07-29 04:53:22 +02002338 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002339 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002340 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002341 if ((1 << lane) & failmask) {
2342 if (timings[reg_178][channel]
2343 [slot][rank][lane].
2344 largest <=
2345 timings[reg_178][channel]
2346 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002347 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002348 [lane] = -1;
2349 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002350 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002351 [lane] = 0;
2352 timings[reg_178]
2353 [channel][slot]
2354 [rank][lane].
2355 smallest++;
2356 write_500(info, channel,
2357 timings
2358 [reg_178]
2359 [channel]
2360 [slot][rank]
2361 [lane].
2362 smallest,
2363 get_timing_register_addr
2364 (lane, 0,
2365 slot, rank),
2366 9, 1);
2367 write_500(info, channel,
2368 timings
2369 [reg_178]
2370 [channel]
2371 [slot][rank]
2372 [lane].
2373 smallest +
2374 info->
2375 training.
2376 lane_timings
2377 [1][channel]
2378 [slot][rank]
2379 [lane]
2380 -
2381 info->
2382 training.
2383 lane_timings
2384 [0][channel]
2385 [slot][rank]
2386 [lane],
2387 get_timing_register_addr
2388 (lane, 1,
2389 slot, rank),
2390 9, 1);
2391 }
2392 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002393 num_successfully_checked[lane]
2394 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002395 }
2396 }
Felix Held04be2dd2018-07-29 04:53:22 +02002397 while (!check_bounded(num_successfully_checked, 2))
2398 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002399
2400 for (lane = 0; lane < 8; lane++)
2401 if (state[lane] == COMPLETE) {
2402 write_500(info, channel,
2403 timings[reg_178][channel][slot][rank]
2404 [lane].largest,
2405 get_timing_register_addr(lane, 0,
2406 slot, rank),
2407 9, 1);
2408 write_500(info, channel,
2409 timings[reg_178][channel][slot][rank]
2410 [lane].largest +
2411 info->training.
2412 lane_timings[1][channel][slot][rank]
2413 [lane]
2414 -
2415 info->training.
2416 lane_timings[0][channel][slot][rank]
2417 [lane], get_timing_register_addr(lane,
2418 1,
2419 slot,
2420 rank),
2421 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002422 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002423 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002424 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002425
2426 do {
2427 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002428 for (i = 0; i < niter; i++) {
2429 if (failmask == 0xFF)
2430 break;
2431 failmask |=
2432 check_testing_type2(info, total_rank, 2, i,
2433 0);
2434 failmask |=
2435 check_testing_type2(info, total_rank, 3, i,
2436 1);
2437 }
2438
Felix Held04be2dd2018-07-29 04:53:22 +02002439 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002440 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002441 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002442 if ((1 << lane) & failmask) {
2443 if (timings[reg_178][channel]
2444 [slot][rank][lane].
2445 largest <=
2446 timings[reg_178][channel]
2447 [slot][rank][lane].
2448 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002449 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002450 [lane] = -1;
2451 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002452 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002453 [lane] = 0;
2454 timings[reg_178]
2455 [channel][slot]
2456 [rank][lane].
2457 largest--;
2458 write_500(info, channel,
2459 timings
2460 [reg_178]
2461 [channel]
2462 [slot][rank]
2463 [lane].
2464 largest,
2465 get_timing_register_addr
2466 (lane, 0,
2467 slot, rank),
2468 9, 1);
2469 write_500(info, channel,
2470 timings
2471 [reg_178]
2472 [channel]
2473 [slot][rank]
2474 [lane].
2475 largest +
2476 info->
2477 training.
2478 lane_timings
2479 [1][channel]
2480 [slot][rank]
2481 [lane]
2482 -
2483 info->
2484 training.
2485 lane_timings
2486 [0][channel]
2487 [slot][rank]
2488 [lane],
2489 get_timing_register_addr
2490 (lane, 1,
2491 slot, rank),
2492 9, 1);
2493 }
2494 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002495 num_successfully_checked[lane]
2496 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002497 }
2498 }
2499 }
Felix Held04be2dd2018-07-29 04:53:22 +02002500 while (!check_bounded(num_successfully_checked, 3))
2501 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002502
2503 for (lane = 0; lane < 8; lane++) {
2504 write_500(info, channel,
2505 info->training.
2506 lane_timings[0][channel][slot][rank][lane],
2507 get_timing_register_addr(lane, 0, slot, rank),
2508 9, 1);
2509 write_500(info, channel,
2510 info->training.
2511 lane_timings[1][channel][slot][rank][lane],
2512 get_timing_register_addr(lane, 1, slot, rank),
2513 9, 1);
2514 if (timings[reg_178][channel][slot][rank][lane].
2515 largest <=
2516 timings[reg_178][channel][slot][rank][lane].
2517 smallest) {
2518 timings[reg_178][channel][slot][rank][lane].
2519 largest = 0;
2520 timings[reg_178][channel][slot][rank][lane].
2521 smallest = 0;
2522 }
2523 }
2524 }
2525}
2526
2527static void set_10b(struct raminfo *info, u8 val)
2528{
2529 int channel;
2530 int slot, rank;
2531 int lane;
2532
2533 if (read_1d0(0x10b, 6) == val)
2534 return;
2535
2536 write_1d0(val, 0x10b, 6, 1);
2537
2538 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2539 u16 reg_500;
2540 reg_500 = read_500(info, channel,
2541 get_timing_register_addr(lane, 0, slot,
2542 rank), 9);
2543 if (val == 1) {
2544 if (lut16[info->clock_speed_index] <= reg_500)
2545 reg_500 -= lut16[info->clock_speed_index];
2546 else
2547 reg_500 = 0;
2548 } else {
2549 reg_500 += lut16[info->clock_speed_index];
2550 }
2551 write_500(info, channel, reg_500,
2552 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2553 }
2554}
2555
2556static void set_ecc(int onoff)
2557{
2558 int channel;
2559 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2560 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002561 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002562 if (onoff)
2563 t |= 1;
2564 else
2565 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002566 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002567 }
2568}
2569
2570static void set_178(u8 val)
2571{
2572 if (val >= 31)
2573 val = val - 31;
2574 else
2575 val = 63 - val;
2576
2577 write_1d0(2 * val, 0x178, 7, 1);
2578}
2579
2580static void
2581write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2582 int type)
2583{
2584 int lane;
2585
2586 for (lane = 0; lane < 8; lane++)
2587 write_500(info, channel,
2588 info->training.
2589 lane_timings[type][channel][slot][rank][lane],
2590 get_timing_register_addr(lane, type, slot, rank), 9,
2591 0);
2592}
2593
2594static void
2595try_timing_offsets(struct raminfo *info, int channel,
2596 int slot, int rank, int totalrank)
2597{
2598 u16 count[8];
2599 enum state state[8];
2600 u8 lower_usable[8], upper_usable[8];
2601 int lane;
2602 int i;
2603 int flip = 1;
2604 int timing_offset;
2605
2606 for (i = 0; i < 8; i++)
2607 state[i] = BEFORE_USABLE;
2608
2609 memset(count, 0, sizeof(count));
2610
2611 for (lane = 0; lane < 8; lane++)
2612 write_500(info, channel,
2613 info->training.
2614 lane_timings[2][channel][slot][rank][lane] + 32,
2615 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2616
2617 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2618 timing_offset++) {
2619 u8 failmask;
2620 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2621 failmask = 0;
2622 for (i = 0; i < 2 && failmask != 0xff; i++) {
2623 flip = !flip;
2624 write_testing(info, totalrank, flip);
2625 failmask |= check_testing(info, totalrank, flip);
2626 }
2627 do_fsm(state, count, failmask, 10, 63, lower_usable,
2628 upper_usable, timing_offset);
2629 }
2630 write_1d0(0, 0x1bb, 6, 1);
2631 dump_timings(info);
2632 if (!validate_state(state))
2633 die("Couldn't discover DRAM timings (1)\n");
2634
2635 for (lane = 0; lane < 8; lane++) {
2636 u8 bias = 0;
2637
2638 if (info->silicon_revision) {
2639 int usable_length;
2640
2641 usable_length = upper_usable[lane] - lower_usable[lane];
2642 if (usable_length >= 20) {
2643 bias = usable_length / 2 - 10;
2644 if (bias >= 2)
2645 bias = 2;
2646 }
2647 }
2648 write_500(info, channel,
2649 info->training.
2650 lane_timings[2][channel][slot][rank][lane] +
2651 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2652 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2653 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2654 info->training.lane_timings[2][channel][slot][rank][lane] +
2655 lower_usable[lane];
2656 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2657 info->training.lane_timings[2][channel][slot][rank][lane] +
2658 upper_usable[lane];
2659 info->training.timing2_offset[channel][slot][rank][lane] =
2660 info->training.lane_timings[2][channel][slot][rank][lane];
2661 }
2662}
2663
2664static u8
2665choose_training(struct raminfo *info, int channel, int slot, int rank,
2666 int lane, timing_bounds_t * timings, u8 center_178)
2667{
2668 u16 central_weight;
2669 u16 side_weight;
2670 unsigned int sum = 0, count = 0;
2671 u8 span;
2672 u8 lower_margin, upper_margin;
2673 u8 reg_178;
2674 u8 result;
2675
2676 span = 12;
2677 central_weight = 20;
2678 side_weight = 20;
2679 if (info->silicon_revision == 1 && channel == 1) {
2680 central_weight = 5;
2681 side_weight = 20;
2682 if ((info->
2683 populated_ranks_mask[1] ^ (info->
2684 populated_ranks_mask[1] >> 2)) &
2685 1)
2686 span = 18;
2687 }
2688 if ((info->populated_ranks_mask[0] & 5) == 5) {
2689 central_weight = 20;
2690 side_weight = 20;
2691 }
2692 if (info->clock_speed_index >= 2
2693 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2694 if (info->silicon_revision == 1) {
2695 switch (channel) {
2696 case 0:
2697 if (lane == 1) {
2698 central_weight = 10;
2699 side_weight = 20;
2700 }
2701 break;
2702 case 1:
2703 if (lane == 6) {
2704 side_weight = 5;
2705 central_weight = 20;
2706 }
2707 break;
2708 }
2709 }
2710 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2711 side_weight = 5;
2712 central_weight = 20;
2713 }
2714 }
2715 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2716 reg_178 += span) {
2717 u8 smallest;
2718 u8 largest;
2719 largest = timings[reg_178][channel][slot][rank][lane].largest;
2720 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2721 if (largest - smallest + 1 >= 5) {
2722 unsigned int weight;
2723 if (reg_178 == center_178)
2724 weight = central_weight;
2725 else
2726 weight = side_weight;
2727 sum += weight * (largest + smallest);
2728 count += weight;
2729 }
2730 }
2731 dump_timings(info);
2732 if (count == 0)
2733 die("Couldn't discover DRAM timings (2)\n");
2734 result = sum / (2 * count);
2735 lower_margin =
2736 result - timings[center_178][channel][slot][rank][lane].smallest;
2737 upper_margin =
2738 timings[center_178][channel][slot][rank][lane].largest - result;
2739 if (upper_margin < 10 && lower_margin > 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002740 result -= MIN(lower_margin - 10, 10 - upper_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002741 if (upper_margin > 10 && lower_margin < 10)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01002742 result += MIN(upper_margin - 10, 10 - lower_margin);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002743 return result;
2744}
2745
2746#define STANDARD_MIN_MARGIN 5
2747
2748static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2749{
2750 u16 margin[64];
2751 int lane, rank, slot, channel;
2752 u8 reg178;
2753 int count = 0, sum = 0;
2754
2755 for (reg178 = reg178_min[info->clock_speed_index];
2756 reg178 < reg178_max[info->clock_speed_index];
2757 reg178 += reg178_step[info->clock_speed_index]) {
2758 margin[reg178] = -1;
2759 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2760 int curmargin =
2761 timings[reg178][channel][slot][rank][lane].largest -
2762 timings[reg178][channel][slot][rank][lane].
2763 smallest + 1;
2764 if (curmargin < margin[reg178])
2765 margin[reg178] = curmargin;
2766 }
2767 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2768 u16 weight;
2769 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2770 sum += weight * reg178;
2771 count += weight;
2772 }
2773 }
2774 dump_timings(info);
2775 if (count == 0)
2776 die("Couldn't discover DRAM timings (3)\n");
2777
2778 u8 threshold;
2779
2780 for (threshold = 30; threshold >= 5; threshold--) {
2781 int usable_length = 0;
2782 int smallest_fount = 0;
2783 for (reg178 = reg178_min[info->clock_speed_index];
2784 reg178 < reg178_max[info->clock_speed_index];
2785 reg178 += reg178_step[info->clock_speed_index])
2786 if (margin[reg178] >= threshold) {
2787 usable_length +=
2788 reg178_step[info->clock_speed_index];
2789 info->training.reg178_largest =
2790 reg178 -
2791 2 * reg178_step[info->clock_speed_index];
2792
2793 if (!smallest_fount) {
2794 smallest_fount = 1;
2795 info->training.reg178_smallest =
2796 reg178 +
2797 reg178_step[info->
2798 clock_speed_index];
2799 }
2800 }
2801 if (usable_length >= 0x21)
2802 break;
2803 }
2804
2805 return sum / count;
2806}
2807
2808static int check_cached_sanity(struct raminfo *info)
2809{
2810 int lane;
2811 int slot, rank;
2812 int channel;
2813
2814 if (!info->cached_training)
2815 return 0;
2816
2817 for (channel = 0; channel < NUM_CHANNELS; channel++)
2818 for (slot = 0; slot < NUM_SLOTS; slot++)
2819 for (rank = 0; rank < NUM_RANKS; rank++)
2820 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2821 u16 cached_value, estimation_value;
2822 cached_value =
2823 info->cached_training->
2824 lane_timings[1][channel][slot][rank]
2825 [lane];
2826 if (cached_value >= 0x18
2827 && cached_value <= 0x1E7) {
2828 estimation_value =
2829 info->training.
2830 lane_timings[1][channel]
2831 [slot][rank][lane];
2832 if (estimation_value <
2833 cached_value - 24)
2834 return 0;
2835 if (estimation_value >
2836 cached_value + 24)
2837 return 0;
2838 }
2839 }
2840 return 1;
2841}
2842
2843static int try_cached_training(struct raminfo *info)
2844{
2845 u8 saved_243[2];
2846 u8 tm;
2847
2848 int channel, slot, rank, lane;
2849 int flip = 1;
2850 int i, j;
2851
2852 if (!check_cached_sanity(info))
2853 return 0;
2854
2855 info->training.reg178_center = info->cached_training->reg178_center;
2856 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2857 info->training.reg178_largest = info->cached_training->reg178_largest;
2858 memcpy(&info->training.timing_bounds,
2859 &info->cached_training->timing_bounds,
2860 sizeof(info->training.timing_bounds));
2861 memcpy(&info->training.timing_offset,
2862 &info->cached_training->timing_offset,
2863 sizeof(info->training.timing_offset));
2864
2865 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002866 saved_243[0] = MCHBAR8(0x243);
2867 saved_243[1] = MCHBAR8(0x643);
2868 MCHBAR8(0x243) = saved_243[0] | 2;
2869 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002870 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002871 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002872 if (read_1d0(0x10b, 6) & 1)
2873 set_10b(info, 0);
2874 for (tm = 0; tm < 2; tm++) {
2875 int totalrank;
2876
2877 set_178(tm ? info->cached_training->reg178_largest : info->
2878 cached_training->reg178_smallest);
2879
2880 totalrank = 0;
2881 /* Check timing ranges. With i == 0 we check smallest one and with
2882 i == 1 the largest bound. With j == 0 we check that on the bound
2883 it still works whereas with j == 1 we check that just outside of
2884 bound we fail.
2885 */
2886 FOR_POPULATED_RANKS_BACKWARDS {
2887 for (i = 0; i < 2; i++) {
2888 for (lane = 0; lane < 8; lane++) {
2889 write_500(info, channel,
2890 info->cached_training->
2891 timing2_bounds[channel][slot]
2892 [rank][lane][i],
2893 get_timing_register_addr(lane,
2894 3,
2895 slot,
2896 rank),
2897 9, 1);
2898
2899 if (!i)
2900 write_500(info, channel,
2901 info->
2902 cached_training->
2903 timing2_offset
2904 [channel][slot][rank]
2905 [lane],
2906 get_timing_register_addr
2907 (lane, 2, slot, rank),
2908 9, 1);
2909 write_500(info, channel,
2910 i ? info->cached_training->
2911 timing_bounds[tm][channel]
2912 [slot][rank][lane].
2913 largest : info->
2914 cached_training->
2915 timing_bounds[tm][channel]
2916 [slot][rank][lane].smallest,
2917 get_timing_register_addr(lane,
2918 0,
2919 slot,
2920 rank),
2921 9, 1);
2922 write_500(info, channel,
2923 info->cached_training->
2924 timing_offset[channel][slot]
2925 [rank][lane] +
2926 (i ? info->cached_training->
2927 timing_bounds[tm][channel]
2928 [slot][rank][lane].
2929 largest : info->
2930 cached_training->
2931 timing_bounds[tm][channel]
2932 [slot][rank][lane].
2933 smallest) - 64,
2934 get_timing_register_addr(lane,
2935 1,
2936 slot,
2937 rank),
2938 9, 1);
2939 }
2940 for (j = 0; j < 2; j++) {
2941 u8 failmask;
2942 u8 expected_failmask;
2943 char reg1b3;
2944
2945 reg1b3 = (j == 1) + 4;
2946 reg1b3 =
2947 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2948 write_1d0(reg1b3, 0x1bb, 6, 1);
2949 write_1d0(reg1b3, 0x1b3, 6, 1);
2950 write_1d0(reg1b3, 0x1a3, 6, 1);
2951
2952 flip = !flip;
2953 write_testing(info, totalrank, flip);
2954 failmask =
2955 check_testing(info, totalrank,
2956 flip);
2957 expected_failmask =
2958 j == 0 ? 0x00 : 0xff;
2959 if (failmask != expected_failmask)
2960 goto fail;
2961 }
2962 }
2963 totalrank++;
2964 }
2965 }
2966
2967 set_178(info->cached_training->reg178_center);
2968 if (info->use_ecc)
2969 set_ecc(1);
2970 write_training_data(info);
2971 write_1d0(0, 322, 3, 1);
2972 info->training = *info->cached_training;
2973
2974 write_1d0(0, 0x1bb, 6, 1);
2975 write_1d0(0, 0x1b3, 6, 1);
2976 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002977 MCHBAR8(0x243) = saved_243[0];
2978 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002979
2980 return 1;
2981
2982fail:
2983 FOR_POPULATED_RANKS {
2984 write_500_timings_type(info, channel, slot, rank, 1);
2985 write_500_timings_type(info, channel, slot, rank, 2);
2986 write_500_timings_type(info, channel, slot, rank, 3);
2987 }
2988
2989 write_1d0(0, 0x1bb, 6, 1);
2990 write_1d0(0, 0x1b3, 6, 1);
2991 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002992 MCHBAR8(0x243) = saved_243[0];
2993 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002994
2995 return 0;
2996}
2997
2998static void do_ram_training(struct raminfo *info)
2999{
3000 u8 saved_243[2];
3001 int totalrank = 0;
3002 u8 reg_178;
3003 int niter;
3004
Matthias Gazzaridfa51252018-05-19 00:44:20 +02003005 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003006 int lane, rank, slot, channel;
3007 u8 reg178_center;
3008
3009 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003010 saved_243[0] = MCHBAR8(0x243);
3011 saved_243[1] = MCHBAR8(0x643);
3012 MCHBAR8(0x243) = saved_243[0] | 2;
3013 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003014 switch (info->clock_speed_index) {
3015 case 0:
3016 niter = 5;
3017 break;
3018 case 1:
3019 niter = 10;
3020 break;
3021 default:
3022 niter = 19;
3023 break;
3024 }
3025 set_ecc(0);
3026
3027 FOR_POPULATED_RANKS_BACKWARDS {
3028 int i;
3029
3030 write_500_timings_type(info, channel, slot, rank, 0);
3031
3032 write_testing(info, totalrank, 0);
3033 for (i = 0; i < niter; i++) {
3034 write_testing_type2(info, totalrank, 2, i, 0);
3035 write_testing_type2(info, totalrank, 3, i, 1);
3036 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003037 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003038 totalrank++;
3039 }
3040
3041 if (reg178_min[info->clock_speed_index] <
3042 reg178_max[info->clock_speed_index])
3043 memset(timings[reg178_min[info->clock_speed_index]], 0,
3044 sizeof(timings[0]) *
3045 (reg178_max[info->clock_speed_index] -
3046 reg178_min[info->clock_speed_index]));
3047 for (reg_178 = reg178_min[info->clock_speed_index];
3048 reg_178 < reg178_max[info->clock_speed_index];
3049 reg_178 += reg178_step[info->clock_speed_index]) {
3050 totalrank = 0;
3051 set_178(reg_178);
3052 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3053 for (slot = 0; slot < NUM_SLOTS; slot++)
3054 for (rank = 0; rank < NUM_RANKS; rank++) {
3055 memset(&timings[reg_178][channel][slot]
3056 [rank][0].smallest, 0, 16);
3057 if (info->
3058 populated_ranks[channel][slot]
3059 [rank]) {
3060 train_ram_at_178(info, channel,
3061 slot, rank,
3062 totalrank,
3063 reg_178, 1,
3064 niter,
3065 timings);
3066 totalrank++;
3067 }
3068 }
3069 }
3070
3071 reg178_center = choose_reg178(info, timings);
3072
3073 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3074 info->training.timing_bounds[0][channel][slot][rank][lane].
3075 smallest =
3076 timings[info->training.
3077 reg178_smallest][channel][slot][rank][lane].
3078 smallest;
3079 info->training.timing_bounds[0][channel][slot][rank][lane].
3080 largest =
3081 timings[info->training.
3082 reg178_smallest][channel][slot][rank][lane].largest;
3083 info->training.timing_bounds[1][channel][slot][rank][lane].
3084 smallest =
3085 timings[info->training.
3086 reg178_largest][channel][slot][rank][lane].smallest;
3087 info->training.timing_bounds[1][channel][slot][rank][lane].
3088 largest =
3089 timings[info->training.
3090 reg178_largest][channel][slot][rank][lane].largest;
3091 info->training.timing_offset[channel][slot][rank][lane] =
3092 info->training.lane_timings[1][channel][slot][rank][lane]
3093 -
3094 info->training.lane_timings[0][channel][slot][rank][lane] +
3095 64;
3096 }
3097
3098 if (info->silicon_revision == 1
3099 && (info->
3100 populated_ranks_mask[1] ^ (info->
3101 populated_ranks_mask[1] >> 2)) & 1) {
3102 int ranks_after_channel1;
3103
3104 totalrank = 0;
3105 for (reg_178 = reg178_center - 18;
3106 reg_178 <= reg178_center + 18; reg_178 += 18) {
3107 totalrank = 0;
3108 set_178(reg_178);
3109 for (slot = 0; slot < NUM_SLOTS; slot++)
3110 for (rank = 0; rank < NUM_RANKS; rank++) {
3111 if (info->
3112 populated_ranks[1][slot][rank]) {
3113 train_ram_at_178(info, 1, slot,
3114 rank,
3115 totalrank,
3116 reg_178, 0,
3117 niter,
3118 timings);
3119 totalrank++;
3120 }
3121 }
3122 }
3123 ranks_after_channel1 = totalrank;
3124
3125 for (reg_178 = reg178_center - 12;
3126 reg_178 <= reg178_center + 12; reg_178 += 12) {
3127 totalrank = ranks_after_channel1;
3128 set_178(reg_178);
3129 for (slot = 0; slot < NUM_SLOTS; slot++)
3130 for (rank = 0; rank < NUM_RANKS; rank++)
3131 if (info->
3132 populated_ranks[0][slot][rank]) {
3133 train_ram_at_178(info, 0, slot,
3134 rank,
3135 totalrank,
3136 reg_178, 0,
3137 niter,
3138 timings);
3139 totalrank++;
3140 }
3141
3142 }
3143 } else {
3144 for (reg_178 = reg178_center - 12;
3145 reg_178 <= reg178_center + 12; reg_178 += 12) {
3146 totalrank = 0;
3147 set_178(reg_178);
3148 FOR_POPULATED_RANKS_BACKWARDS {
3149 train_ram_at_178(info, channel, slot, rank,
3150 totalrank, reg_178, 0, niter,
3151 timings);
3152 totalrank++;
3153 }
3154 }
3155 }
3156
3157 set_178(reg178_center);
3158 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3159 u16 tm0;
3160
3161 tm0 =
3162 choose_training(info, channel, slot, rank, lane, timings,
3163 reg178_center);
3164 write_500(info, channel, tm0,
3165 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3166 write_500(info, channel,
3167 tm0 +
3168 info->training.
3169 lane_timings[1][channel][slot][rank][lane] -
3170 info->training.
3171 lane_timings[0][channel][slot][rank][lane],
3172 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3173 }
3174
3175 totalrank = 0;
3176 FOR_POPULATED_RANKS_BACKWARDS {
3177 try_timing_offsets(info, channel, slot, rank, totalrank);
3178 totalrank++;
3179 }
Felix Held04be2dd2018-07-29 04:53:22 +02003180 MCHBAR8(0x243) = saved_243[0];
3181 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003182 write_1d0(0, 0x142, 3, 1);
3183 info->training.reg178_center = reg178_center;
3184}
3185
3186static void ram_training(struct raminfo *info)
3187{
3188 u16 saved_fc4;
3189
Felix Held04be2dd2018-07-29 04:53:22 +02003190 saved_fc4 = MCHBAR16(0xfc4);
3191 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003192
3193 if (info->revision >= 8)
3194 read_4090(info);
3195
3196 if (!try_cached_training(info))
3197 do_ram_training(info);
3198 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3199 && info->clock_speed_index < 2)
3200 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003201 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003202}
3203
Martin Roth468d02c2019-10-23 21:44:42 -06003204static unsigned int gcd(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003205{
Martin Roth468d02c2019-10-23 21:44:42 -06003206 unsigned int t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003207 if (a > b) {
3208 t = a;
3209 a = b;
3210 b = t;
3211 }
3212 /* invariant a < b. */
3213 while (a) {
3214 t = b % a;
3215 b = a;
3216 a = t;
3217 }
3218 return b;
3219}
3220
3221static inline int div_roundup(int a, int b)
3222{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003223 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003224}
3225
Martin Roth468d02c2019-10-23 21:44:42 -06003226static unsigned int lcm(unsigned int a, unsigned int b)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003227{
3228 return (a * b) / gcd(a, b);
3229}
3230
3231struct stru1 {
3232 u8 freqs_reversed;
3233 u8 freq_diff_reduced;
3234 u8 freq_min_reduced;
3235 u8 divisor_f4_to_fmax;
3236 u8 divisor_f3_to_fmax;
3237 u8 freq4_to_max_remainder;
3238 u8 freq3_to_2_remainder;
3239 u8 freq3_to_2_remaindera;
3240 u8 freq4_to_2_remainder;
3241 int divisor_f3_to_f1, divisor_f4_to_f2;
3242 int common_time_unit_ps;
3243 int freq_max_reduced;
3244};
3245
3246static void
3247compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3248 int num_cycles_2, int num_cycles_1, int round_it,
3249 int add_freqs, struct stru1 *result)
3250{
3251 int g;
3252 int common_time_unit_ps;
3253 int freq1_reduced, freq2_reduced;
3254 int freq_min_reduced;
3255 int freq_max_reduced;
3256 int freq3, freq4;
3257
3258 g = gcd(freq1, freq2);
3259 freq1_reduced = freq1 / g;
3260 freq2_reduced = freq2 / g;
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003261 freq_min_reduced = MIN(freq1_reduced, freq2_reduced);
3262 freq_max_reduced = MAX(freq1_reduced, freq2_reduced);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003263
3264 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3265 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3266 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3267 if (add_freqs) {
3268 freq3 += freq2_reduced;
3269 freq4 += freq1_reduced;
3270 }
3271
3272 if (round_it) {
3273 result->freq3_to_2_remainder = 0;
3274 result->freq3_to_2_remaindera = 0;
3275 result->freq4_to_max_remainder = 0;
3276 result->divisor_f4_to_f2 = 0;
3277 result->divisor_f3_to_f1 = 0;
3278 } else {
3279 if (freq2_reduced < freq1_reduced) {
3280 result->freq3_to_2_remainder =
3281 result->freq3_to_2_remaindera =
3282 freq3 % freq1_reduced - freq1_reduced + 1;
3283 result->freq4_to_max_remainder =
3284 -(freq4 % freq1_reduced);
3285 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3286 result->divisor_f4_to_f2 =
3287 (freq4 -
3288 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3289 result->freq4_to_2_remainder =
3290 -(char)((freq1_reduced - freq2_reduced) +
3291 ((u8) freq4 -
3292 (freq1_reduced -
3293 freq2_reduced)) % (u8) freq2_reduced);
3294 } else {
3295 if (freq2_reduced > freq1_reduced) {
3296 result->freq4_to_max_remainder =
3297 (freq4 % freq2_reduced) - freq2_reduced + 1;
3298 result->freq4_to_2_remainder =
3299 freq4 % freq_max_reduced -
3300 freq_max_reduced + 1;
3301 } else {
3302 result->freq4_to_max_remainder =
3303 -(freq4 % freq2_reduced);
3304 result->freq4_to_2_remainder =
3305 -(char)(freq4 % freq_max_reduced);
3306 }
3307 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3308 result->divisor_f3_to_f1 =
3309 (freq3 -
3310 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3311 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3312 result->freq3_to_2_remaindera =
3313 -(char)((freq_max_reduced - freq_min_reduced) +
3314 (freq3 -
3315 (freq_max_reduced -
3316 freq_min_reduced)) % freq1_reduced);
3317 }
3318 }
3319 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3320 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3321 if (round_it) {
3322 if (freq2_reduced > freq1_reduced) {
3323 if (freq3 % freq_max_reduced)
3324 result->divisor_f3_to_fmax++;
3325 }
3326 if (freq2_reduced < freq1_reduced) {
3327 if (freq4 % freq_max_reduced)
3328 result->divisor_f4_to_fmax++;
3329 }
3330 }
3331 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3332 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3333 result->freq_min_reduced = freq_min_reduced;
3334 result->common_time_unit_ps = common_time_unit_ps;
3335 result->freq_max_reduced = freq_max_reduced;
3336}
3337
3338static void
3339set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3340 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3341 int num_cycles_4, int reverse)
3342{
3343 struct stru1 vv;
3344 char multiplier;
3345
3346 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3347 0, 1, &vv);
3348
3349 multiplier =
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003350 div_roundup(MAX
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003351 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3352 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3353 div_roundup(num_cycles_1,
3354 vv.common_time_unit_ps) +
3355 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3356 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3357
3358 u32 y =
3359 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3360 vv.freq_max_reduced * multiplier)
3361 | (vv.
3362 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3363 multiplier) << 16) | ((u8) (vv.
3364 freq_min_reduced
3365 *
3366 multiplier)
3367 << 24);
3368 u32 x =
3369 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3370 divisor_f3_to_f1
3371 << 16)
3372 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3373 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003374 MCHBAR32(reg) = y;
3375 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003376 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003377 MCHBAR32(reg + 4) = y;
3378 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003379 }
3380}
3381
3382static void
3383set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3384 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3385 int num_cycles_4)
3386{
3387 struct stru1 ratios1;
3388 struct stru1 ratios2;
3389
3390 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3391 0, 1, &ratios2);
3392 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3393 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003394 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003395 ratios1.freq4_to_max_remainder | (ratios2.
3396 freq4_to_max_remainder
3397 << 8)
3398 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3399 divisor_f4_to_fmax
3400 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003401 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3402 (ratios2.freq4_to_max_remainder << 8) |
3403 (ratios1.divisor_f4_to_fmax << 16) |
3404 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003405}
3406
3407static void
3408set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3409 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3410{
3411 struct stru1 ratios;
3412
3413 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3414 round_it, add_freqs, &ratios);
3415 switch (mode) {
3416 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003417 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3418 (ratios.freqs_reversed << 8);
3419 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3420 (ratios.freq4_to_max_remainder << 8) |
3421 (ratios.divisor_f3_to_fmax << 16) |
3422 (ratios.divisor_f4_to_fmax << 20) |
3423 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003424 break;
3425
3426 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003427 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3428 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003429 break;
3430
3431 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003432 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3433 (ratios.freq4_to_max_remainder << 8) |
3434 (ratios.divisor_f3_to_fmax << 16) |
3435 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003436 break;
3437
3438 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003439 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3440 (ratios.divisor_f4_to_fmax << 8) |
3441 (ratios.freqs_reversed << 12) |
3442 (ratios.freq_min_reduced << 16) |
3443 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003444 break;
3445 }
3446}
3447
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003448static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003449{
3450 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3451 0, 1);
3452 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3453 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3454 1);
3455 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3456 frequency_11(info), 1231, 1524, 0, 1);
3457 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3458 frequency_11(info) / 2, 1278, 2008, 0, 1);
3459 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3460 1167, 1539, 0, 1);
3461 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3462 frequency_11(info) / 2, 1403, 1318, 0, 1);
3463 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3464 1);
3465 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3466 1);
3467 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3468 1, 1);
3469 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3470 1);
3471 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3472 frequency_11(info) / 2, 4000, 0, 0, 0);
3473 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3474 frequency_11(info) / 2, 4000, 4000, 0, 0);
3475
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003476 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003477 printk(RAM_SPEW, "[6dc] <= %x\n",
3478 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003479 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003480 } else
3481 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3482 info->delay46_ps[0], 0,
3483 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003484 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3485 frequency_11(info), 2500, 0, 0, 0);
3486 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3487 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003488 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003489 printk(RAM_SPEW, "[6e8] <= %x\n",
3490 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003491 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003492 } else
3493 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3494 info->delay46_ps[1], 0,
3495 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003496 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3497 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3498 470, 0);
3499 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3500 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3501 454, 459, 0);
3502 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3503 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3504 2588, 0);
3505 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3506 2405, 0);
3507 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3508 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3509 480, 0);
3510 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003511 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3512 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003513}
3514
3515static u16 get_max_timing(struct raminfo *info, int channel)
3516{
3517 int slot, rank, lane;
3518 u16 ret = 0;
3519
Felix Held04be2dd2018-07-29 04:53:22 +02003520 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003521 return 384;
3522
3523 if (info->revision < 8)
3524 return 256;
3525
3526 for (slot = 0; slot < NUM_SLOTS; slot++)
3527 for (rank = 0; rank < NUM_RANKS; rank++)
3528 if (info->populated_ranks[channel][slot][rank])
3529 for (lane = 0; lane < 8 + info->use_ecc; lane++)
Elyes HAOUASba9b5042019-12-19 07:47:52 +01003530 ret = MAX(ret, read_500(info, channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003531 get_timing_register_addr
3532 (lane, 0, slot,
3533 rank), 9));
3534 return ret;
3535}
3536
3537static void set_274265(struct raminfo *info)
3538{
3539 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3540 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3541 int delay_e_over_cycle_ps;
3542 int cycletime_ps;
3543 int channel;
3544
3545 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003546 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003547 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3548 cycletime_ps =
3549 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3550 delay_d_ps =
3551 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3552 - info->some_delay_3_ps_rounded + 200;
3553 if (!
3554 ((info->silicon_revision == 0
3555 || info->silicon_revision == 1)
3556 && (info->revision >= 8)))
3557 delay_d_ps += halfcycle_ps(info) * 2;
3558 delay_d_ps +=
3559 halfcycle_ps(info) * (!info->revision_flag_1 +
3560 info->some_delay_2_halfcycles_ceil +
3561 2 * info->some_delay_1_cycle_floor +
3562 info->clock_speed_index +
3563 2 * info->cas_latency - 7 + 11);
3564 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3565
Felix Held04be2dd2018-07-29 04:53:22 +02003566 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3567 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3568 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003569 delay_d_ps += 650;
3570 delay_c_ps = delay_d_ps + 1800;
3571 if (delay_c_ps <= delay_a_ps)
3572 delay_e_ps = 0;
3573 else
3574 delay_e_ps =
3575 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3576 cycletime_ps);
3577
3578 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3579 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3580 delay_f_cycles =
3581 div_roundup(2500 - delay_e_over_cycle_ps,
3582 2 * halfcycle_ps(info));
3583 if (delay_f_cycles > delay_e_cycles) {
3584 info->delay46_ps[channel] = delay_e_ps;
3585 delay_e_cycles = 0;
3586 } else {
3587 info->delay46_ps[channel] =
3588 delay_e_over_cycle_ps +
3589 2 * halfcycle_ps(info) * delay_f_cycles;
3590 delay_e_cycles -= delay_f_cycles;
3591 }
3592
3593 if (info->delay46_ps[channel] < 2500) {
3594 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003595 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003596 }
3597 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3598 if (delay_b_ps <= delay_a_ps)
3599 delay_b_ps = 0;
3600 else
3601 delay_b_ps -= delay_a_ps;
3602 info->delay54_ps[channel] =
3603 cycletime_ps * div_roundup(delay_b_ps,
3604 cycletime_ps) -
3605 2 * halfcycle_ps(info) * delay_e_cycles;
3606 if (info->delay54_ps[channel] < 2500)
3607 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003608 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003609 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3610 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003611 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003612 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003613 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003614 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3615 4 * halfcycle_ps(info)) - 6;
3616 MCHBAR32((channel << 10) + 0x274) =
3617 info->training.reg274265[channel][1] |
3618 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003619 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003620 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3621 4 * halfcycle_ps(info)) + 1;
3622 MCHBAR16((channel << 10) + 0x265) =
3623 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003624 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003625 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003626 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003627 else
Felix Held04be2dd2018-07-29 04:53:22 +02003628 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003629}
3630
3631static void restore_274265(struct raminfo *info)
3632{
3633 int channel;
3634
3635 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003636 MCHBAR32((channel << 10) + 0x274) =
3637 (info->cached_training->reg274265[channel][0] << 16) |
3638 info->cached_training->reg274265[channel][1];
3639 MCHBAR16((channel << 10) + 0x265) =
3640 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003641 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003642 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003643 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003644 else
Felix Held04be2dd2018-07-29 04:53:22 +02003645 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003646}
3647
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003648static void dmi_setup(void)
3649{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003650 gav(read8(DEFAULT_DMIBAR + 0x254));
3651 write8(DEFAULT_DMIBAR + 0x254, 0x1);
3652 write16(DEFAULT_DMIBAR + 0x1b8, 0x18f2);
Felix Heldf83d80b2018-07-29 05:30:30 +02003653 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003654
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003655 write32(DEFAULT_DMIBAR + 0xd68, read32(DEFAULT_DMIBAR + 0xd68) | 0x08000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003656
3657 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3658 DEFAULT_GPIOBASE | 0x38);
3659 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3660}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003661
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003662void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003663{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003664 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003665 u16 ggc;
3666 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003667
Felix Held04be2dd2018-07-29 04:53:22 +02003668 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003669 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3670 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003671 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003672 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003673 }
Felix Held29a9c072018-07-29 01:34:45 +02003674#if 0
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003675 if (!s3resume) {
3676 pre_raminit_3(x2ca8);
3677 }
Vladimir Serbinenkof62669c2014-01-09 10:59:38 +01003678 pre_raminit_4a(x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003679#endif
3680
3681 dmi_setup();
3682
Felix Held04be2dd2018-07-29 04:53:22 +02003683 MCHBAR16(0x1170) = 0xa880;
3684 MCHBAR8(0x11c1) = 0x1;
3685 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003686 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003687
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003688 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3689 /* 0 for 32MB */
3690 gfxsize = 0;
3691 }
3692
3693 ggc = 0xb00 | ((gfxsize + 5) << 4);
3694
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003695 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003696
3697 u16 deven;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003698 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003699
3700 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003701 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003702 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003703 MCHBAR16_OR(0x2c30, 0x200);
3704 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003705 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003706 pci_read_config8(GMA, 0x62); // = 0x2
3707 pci_write_config8(GMA, 0x62, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003708 read8(DEFAULT_RCBA + 0x2318);
3709 write8(DEFAULT_RCBA + 0x2318, 0x47);
3710 read8(DEFAULT_RCBA + 0x2320);
3711 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003712 }
3713
Felix Heldf83d80b2018-07-29 05:30:30 +02003714 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003715
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003716 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003717 gav(read32(DEFAULT_RCBA + 0x3428));
3718 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003719}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003720
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003721void raminit(const int s3resume, const u8 *spd_addrmap)
3722{
Martin Roth468d02c2019-10-23 21:44:42 -06003723 unsigned int channel, slot, lane, rank;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003724 int i;
3725 struct raminfo info;
3726 u8 x2ca8;
3727 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003728 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003729
Felix Held04be2dd2018-07-29 04:53:22 +02003730 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003731
3732 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3733
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003734 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003735
3736 memset(&info, 0x5a, sizeof(info));
3737
3738 info.last_500_command[0] = 0;
3739 info.last_500_command[1] = 0;
3740
3741 info.fsb_frequency = 135 * 2;
3742 info.board_lane_delay[0] = 0x14;
3743 info.board_lane_delay[1] = 0x07;
3744 info.board_lane_delay[2] = 0x07;
3745 info.board_lane_delay[3] = 0x08;
3746 info.board_lane_delay[4] = 0x56;
3747 info.board_lane_delay[5] = 0x04;
3748 info.board_lane_delay[6] = 0x04;
3749 info.board_lane_delay[7] = 0x05;
3750 info.board_lane_delay[8] = 0x10;
3751
3752 info.training.reg_178 = 0;
3753 info.training.reg_10b = 0;
3754
3755 info.heci_bar = 0;
3756 info.memory_reserved_for_heci_mb = 0;
3757
3758 /* before SPD */
3759 timestamp_add_now(101);
3760
Felix Held29a9c072018-07-29 01:34:45 +02003761 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003762 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003763
3764 collect_system_info(&info);
3765
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003766 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3767
3768 info.use_ecc = 1;
3769 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003770 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003771 int v;
3772 int try;
3773 int addr;
3774 const u8 useful_addresses[] = {
3775 DEVICE_TYPE,
3776 MODULE_TYPE,
3777 DENSITY,
3778 RANKS_AND_DQ,
3779 MEMORY_BUS_WIDTH,
3780 TIMEBASE_DIVIDEND,
3781 TIMEBASE_DIVISOR,
3782 CYCLETIME,
3783 CAS_LATENCIES_LSB,
3784 CAS_LATENCIES_MSB,
3785 CAS_LATENCY_TIME,
3786 0x11, 0x12, 0x13, 0x14, 0x15,
3787 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3788 0x1c, 0x1d,
3789 THERMAL_AND_REFRESH,
3790 0x20,
3791 REFERENCE_RAW_CARD_USED,
3792 RANK1_ADDRESS_MAPPING,
3793 0x75, 0x76, 0x77, 0x78,
3794 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3795 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3796 0x85, 0x86, 0x87, 0x88,
3797 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3798 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3799 0x95
3800 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003801 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003802 continue;
3803 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003804 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003805 DEVICE_TYPE);
3806 if (v >= 0)
3807 break;
3808 }
3809 if (v < 0)
3810 continue;
3811 for (addr = 0;
3812 addr <
3813 sizeof(useful_addresses) /
3814 sizeof(useful_addresses[0]); addr++)
3815 gav(info.
3816 spd[channel][0][useful_addresses
3817 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003818 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003819 useful_addresses
3820 [addr]));
3821 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3822 die("Only DDR3 is supported");
3823
3824 v = info.spd[channel][0][RANKS_AND_DQ];
3825 info.populated_ranks[channel][0][0] = 1;
3826 info.populated_ranks[channel][0][1] =
3827 ((v >> 3) & 7);
3828 if (((v >> 3) & 7) > 1)
3829 die("At most 2 ranks are supported");
3830 if ((v & 7) == 0 || (v & 7) > 2)
3831 die("Only x8 and x16 modules are supported");
3832 if ((info.
3833 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3834 && (info.
3835 spd[channel][slot][MODULE_TYPE] & 0xF)
3836 != 3)
3837 die("Registered memory is not supported");
3838 info.is_x16_module[channel][0] = (v & 7) - 1;
3839 info.density[channel][slot] =
3840 info.spd[channel][slot][DENSITY] & 0xF;
3841 if (!
3842 (info.
3843 spd[channel][slot][MEMORY_BUS_WIDTH] &
3844 0x18))
3845 info.use_ecc = 0;
3846 }
3847
3848 gav(0x55);
3849
3850 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3851 int v = 0;
3852 for (slot = 0; slot < NUM_SLOTS; slot++)
3853 for (rank = 0; rank < NUM_RANKS; rank++)
3854 v |= info.
3855 populated_ranks[channel][slot][rank]
3856 << (2 * slot + rank);
3857 info.populated_ranks_mask[channel] = v;
3858 }
3859
3860 gav(0x55);
3861
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003862 gav(pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003863 }
3864
3865 /* after SPD */
3866 timestamp_add_now(102);
3867
Felix Held04be2dd2018-07-29 04:53:22 +02003868 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003869
3870 collect_system_info(&info);
3871 calculate_timings(&info);
3872
Felix Held29a9c072018-07-29 01:34:45 +02003873#if 0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003874 pci_write_config8(NORTHBRIDGE, 0xdf, 0x82);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003875#endif
3876
3877 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003878 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003879 if (x2ca8 == 0 && (reg8 & 0x80)) {
3880 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3881 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3882 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3883 */
3884
3885 /* Clear bit7. */
3886
3887 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3888 (reg8 & ~(1 << 7)));
3889
3890 printk(BIOS_INFO,
3891 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003892 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003893 }
3894 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003895
3896 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003897 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3898 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003899
3900 compute_derived_timings(&info);
3901
3902 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003903 gav(MCHBAR8(0x164));
3904 MCHBAR8(0x164) = 0x26;
3905 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003906 }
3907
Felix Held04be2dd2018-07-29 04:53:22 +02003908 MCHBAR32_OR(0x18b4, 0x210000);
3909 MCHBAR32_OR(0x1890, 0x2000000);
3910 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003911
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003912 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x50)); // !!!!
3913 pci_write_config8(PCI_DEV(0xff, 2, 1), 0x54, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003914
Felix Held04be2dd2018-07-29 04:53:22 +02003915 gav(MCHBAR16(0x2c10));
3916 MCHBAR16(0x2c10) = 0x412;
3917 gav(MCHBAR16(0x2c10));
3918 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003919
Felix Held04be2dd2018-07-29 04:53:22 +02003920 gav(MCHBAR8(0x2ca8)); // !!!!
3921 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003922
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003923 pci_read_config32(PCI_DEV(0xff, 2, 1), 0x6c); // !!!!
3924 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x6c, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003925 gav(MCHBAR32(0x1c04)); // !!!!
3926 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003927
3928 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003929 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003930 }
3931
Felix Held04be2dd2018-07-29 04:53:22 +02003932 MCHBAR32(0x18d8) = 0x120000;
3933 MCHBAR32(0x18dc) = 0x30a484a;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003934 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x0);
3935 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003936 MCHBAR32(0x18d8) = 0x40000;
3937 MCHBAR32(0x18dc) = 0xb000000;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003938 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x60000);
3939 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003940 MCHBAR32(0x18d8) = 0x180000;
3941 MCHBAR32(0x18dc) = 0xc0000142;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003942 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x20000);
3943 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003944 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003945
Felix Held04be2dd2018-07-29 04:53:22 +02003946 gav(MCHBAR32(0x18dc)); // !!!!
3947 MCHBAR32(0x18dc) = 0x3;
3948 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003949
3950 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003951 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003952 }
3953
Felix Held04be2dd2018-07-29 04:53:22 +02003954 MCHBAR32(0x188c) = 0x20bc09;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003955 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xd0, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003956 MCHBAR32(0x1a10) = 0x4200010e;
3957 MCHBAR32_OR(0x18b8, 0x200);
3958 gav(MCHBAR32(0x1918)); // !!!!
3959 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003960
Felix Held04be2dd2018-07-29 04:53:22 +02003961 gav(MCHBAR32(0x18b8)); // !!!!
3962 MCHBAR32(0x18b8) = 0xe00;
3963 gav(MCHBAR32(0x182c)); // !!!!
3964 MCHBAR32(0x182c) = 0x10202;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003965 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x94)); // !!!!
3966 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x94, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003967 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3968 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003969
Felix Held04be2dd2018-07-29 04:53:22 +02003970 MCHBAR32_AND(0x18b4, 0xffff7fff);
3971 gav(MCHBAR32(0x1a68)); // !!!!
3972 MCHBAR32(0x1a68) = 0x343800;
3973 gav(MCHBAR32(0x1e68)); // !!!!
3974 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003975
3976 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003977 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003978 }
3979
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003980 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x048); // !!!!
3981 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x048, 0x140000);
3982 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3983 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x058, 0x64555);
3984 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3985 pci_read_config32(PCI_DEV (0xff, 0, 0), 0xd0); // !!!!
3986 pci_write_config32(PCI_DEV (0xff, 0, 0), 0xd0, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003987 gav(MCHBAR32(0x1af0)); // !!!!
3988 gav(MCHBAR32(0x1af0)); // !!!!
3989 MCHBAR32(0x1af0) = 0x1f020003;
3990 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003991
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003992 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003993 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003994 }
3995
Felix Held04be2dd2018-07-29 04:53:22 +02003996 gav(MCHBAR32(0x1890)); // !!!!
3997 MCHBAR32(0x1890) = 0x80102;
3998 gav(MCHBAR32(0x18b4)); // !!!!
3999 MCHBAR32(0x18b4) = 0x216000;
4000 MCHBAR32(0x18a4) = 0x22222222;
4001 MCHBAR32(0x18a8) = 0x22222222;
4002 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004003
4004 udelay(1000);
4005
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004006 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004007
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004008 if (x2ca8 == 0) {
4009 int j;
4010 if (s3resume && info.cached_training) {
4011 restore_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02004012 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004013 info.cached_training->reg2ca9_bit0);
4014 for (i = 0; i < 2; i++)
4015 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02004016 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004017 i, j, info.cached_training->reg274265[i][j]);
4018 } else {
4019 set_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02004020 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004021 info.training.reg2ca9_bit0);
4022 for (i = 0; i < 2; i++)
4023 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02004024 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004025 i, j, info.training.reg274265[i][j]);
4026 }
4027
4028 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004029
4030 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02004031 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004032 }
4033
4034 udelay(1000);
4035
4036 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02004037 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02004038 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004039 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4040 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4041 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004042
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004043 MCHBAR8(0x1150);
4044 MCHBAR8(0x1151);
4045 MCHBAR8(0x1022);
4046 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004047 MCHBAR32(0x1300) = 0x60606060;
4048 MCHBAR32(0x1304) = 0x60606060;
4049 MCHBAR32(0x1308) = 0x78797a7b;
4050 MCHBAR32(0x130c) = 0x7c7d7e7f;
4051 MCHBAR32(0x1310) = 0x60606060;
4052 MCHBAR32(0x1314) = 0x60606060;
4053 MCHBAR32(0x1318) = 0x60606060;
4054 MCHBAR32(0x131c) = 0x60606060;
4055 MCHBAR32(0x1320) = 0x50515253;
4056 MCHBAR32(0x1324) = 0x54555657;
4057 MCHBAR32(0x1328) = 0x58595a5b;
4058 MCHBAR32(0x132c) = 0x5c5d5e5f;
4059 MCHBAR32(0x1330) = 0x40414243;
4060 MCHBAR32(0x1334) = 0x44454647;
4061 MCHBAR32(0x1338) = 0x48494a4b;
4062 MCHBAR32(0x133c) = 0x4c4d4e4f;
4063 MCHBAR32(0x1340) = 0x30313233;
4064 MCHBAR32(0x1344) = 0x34353637;
4065 MCHBAR32(0x1348) = 0x38393a3b;
4066 MCHBAR32(0x134c) = 0x3c3d3e3f;
4067 MCHBAR32(0x1350) = 0x20212223;
4068 MCHBAR32(0x1354) = 0x24252627;
4069 MCHBAR32(0x1358) = 0x28292a2b;
4070 MCHBAR32(0x135c) = 0x2c2d2e2f;
4071 MCHBAR32(0x1360) = 0x10111213;
4072 MCHBAR32(0x1364) = 0x14151617;
4073 MCHBAR32(0x1368) = 0x18191a1b;
4074 MCHBAR32(0x136c) = 0x1c1d1e1f;
4075 MCHBAR32(0x1370) = 0x10203;
4076 MCHBAR32(0x1374) = 0x4050607;
4077 MCHBAR32(0x1378) = 0x8090a0b;
4078 MCHBAR32(0x137c) = 0xc0d0e0f;
4079 MCHBAR8(0x11cc) = 0x4e;
4080 MCHBAR32(0x1110) = 0x73970404;
4081 MCHBAR32(0x1114) = 0x72960404;
4082 MCHBAR32(0x1118) = 0x6f950404;
4083 MCHBAR32(0x111c) = 0x6d940404;
4084 MCHBAR32(0x1120) = 0x6a930404;
4085 MCHBAR32(0x1124) = 0x68a41404;
4086 MCHBAR32(0x1128) = 0x66a21404;
4087 MCHBAR32(0x112c) = 0x63a01404;
4088 MCHBAR32(0x1130) = 0x609e1404;
4089 MCHBAR32(0x1134) = 0x5f9c1404;
4090 MCHBAR32(0x1138) = 0x5c961404;
4091 MCHBAR32(0x113c) = 0x58a02404;
4092 MCHBAR32(0x1140) = 0x54942404;
4093 MCHBAR32(0x1190) = 0x900080a;
4094 MCHBAR16(0x11c0) = 0xc40b;
4095 MCHBAR16(0x11c2) = 0x303;
4096 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004097 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004098 MCHBAR32(0x11b8) = 0x70c3000;
4099 MCHBAR8(0x11ec) = 0xa;
4100 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004101 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004102 MCHBAR16(0x11ca) = 0xfa;
4103 MCHBAR32(0x11e4) = 0x4e20;
4104 MCHBAR8(0x11bc) = 0xf;
4105 MCHBAR16(0x11da) = 0x19;
4106 MCHBAR16(0x11ba) = 0x470c;
4107 MCHBAR32(0x1680) = 0xe6ffe4ff;
4108 MCHBAR32(0x1684) = 0xdeffdaff;
4109 MCHBAR32(0x1688) = 0xd4ffd0ff;
4110 MCHBAR32(0x168c) = 0xccffc6ff;
4111 MCHBAR32(0x1690) = 0xc0ffbeff;
4112 MCHBAR32(0x1694) = 0xb8ffb0ff;
4113 MCHBAR32(0x1698) = 0xa8ff0000;
4114 MCHBAR32(0x169c) = 0xc00;
4115 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004116 }
4117
Felix Held04be2dd2018-07-29 04:53:22 +02004118 MCHBAR32(0x124c) = 0x15040d00;
4119 MCHBAR32(0x1250) = 0x7f0000;
4120 MCHBAR32(0x1254) = 0x1e220004;
4121 MCHBAR32(0x1258) = 0x4000004;
4122 MCHBAR32(0x1278) = 0x0;
4123 MCHBAR32(0x125c) = 0x0;
4124 MCHBAR32(0x1260) = 0x0;
4125 MCHBAR32(0x1264) = 0x0;
4126 MCHBAR32(0x1268) = 0x0;
4127 MCHBAR32(0x126c) = 0x0;
4128 MCHBAR32(0x1270) = 0x0;
4129 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004130 }
4131
4132 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004133 MCHBAR16(0x1214) = 0x320;
4134 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004135 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4136 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004137 MCHBAR32(0x1400) = 0x13040020;
4138 MCHBAR32(0x1404) = 0xe090120;
4139 MCHBAR32(0x1408) = 0x5120220;
4140 MCHBAR32(0x140c) = 0x5120330;
4141 MCHBAR32(0x1410) = 0xe090220;
4142 MCHBAR32(0x1414) = 0x1010001;
4143 MCHBAR32(0x1418) = 0x1110000;
4144 MCHBAR32(0x141c) = 0x9020020;
4145 MCHBAR32(0x1420) = 0xd090220;
4146 MCHBAR32(0x1424) = 0x2090220;
4147 MCHBAR32(0x1428) = 0x2090330;
4148 MCHBAR32(0x142c) = 0xd090220;
4149 MCHBAR32(0x1430) = 0x1010001;
4150 MCHBAR32(0x1434) = 0x1110000;
4151 MCHBAR32(0x1438) = 0x11040020;
4152 MCHBAR32(0x143c) = 0x4030220;
4153 MCHBAR32(0x1440) = 0x1060220;
4154 MCHBAR32(0x1444) = 0x1060330;
4155 MCHBAR32(0x1448) = 0x4030220;
4156 MCHBAR32(0x144c) = 0x1010001;
4157 MCHBAR32(0x1450) = 0x1110000;
4158 MCHBAR32(0x1454) = 0x4010020;
4159 MCHBAR32(0x1458) = 0xb090220;
4160 MCHBAR32(0x145c) = 0x1090220;
4161 MCHBAR32(0x1460) = 0x1090330;
4162 MCHBAR32(0x1464) = 0xb090220;
4163 MCHBAR32(0x1468) = 0x1010001;
4164 MCHBAR32(0x146c) = 0x1110000;
4165 MCHBAR32(0x1470) = 0xf040020;
4166 MCHBAR32(0x1474) = 0xa090220;
4167 MCHBAR32(0x1478) = 0x1120220;
4168 MCHBAR32(0x147c) = 0x1120330;
4169 MCHBAR32(0x1480) = 0xa090220;
4170 MCHBAR32(0x1484) = 0x1010001;
4171 MCHBAR32(0x1488) = 0x1110000;
4172 MCHBAR32(0x148c) = 0x7020020;
4173 MCHBAR32(0x1490) = 0x1010220;
4174 MCHBAR32(0x1494) = 0x10210;
4175 MCHBAR32(0x1498) = 0x10320;
4176 MCHBAR32(0x149c) = 0x1010220;
4177 MCHBAR32(0x14a0) = 0x1010001;
4178 MCHBAR32(0x14a4) = 0x1110000;
4179 MCHBAR32(0x14a8) = 0xd040020;
4180 MCHBAR32(0x14ac) = 0x8090220;
4181 MCHBAR32(0x14b0) = 0x1111310;
4182 MCHBAR32(0x14b4) = 0x1111420;
4183 MCHBAR32(0x14b8) = 0x8090220;
4184 MCHBAR32(0x14bc) = 0x1010001;
4185 MCHBAR32(0x14c0) = 0x1110000;
4186 MCHBAR32(0x14c4) = 0x3010020;
4187 MCHBAR32(0x14c8) = 0x7090220;
4188 MCHBAR32(0x14cc) = 0x1081310;
4189 MCHBAR32(0x14d0) = 0x1081420;
4190 MCHBAR32(0x14d4) = 0x7090220;
4191 MCHBAR32(0x14d8) = 0x1010001;
4192 MCHBAR32(0x14dc) = 0x1110000;
4193 MCHBAR32(0x14e0) = 0xb040020;
4194 MCHBAR32(0x14e4) = 0x2030220;
4195 MCHBAR32(0x14e8) = 0x1051310;
4196 MCHBAR32(0x14ec) = 0x1051420;
4197 MCHBAR32(0x14f0) = 0x2030220;
4198 MCHBAR32(0x14f4) = 0x1010001;
4199 MCHBAR32(0x14f8) = 0x1110000;
4200 MCHBAR32(0x14fc) = 0x5020020;
4201 MCHBAR32(0x1500) = 0x5090220;
4202 MCHBAR32(0x1504) = 0x2071310;
4203 MCHBAR32(0x1508) = 0x2071420;
4204 MCHBAR32(0x150c) = 0x5090220;
4205 MCHBAR32(0x1510) = 0x1010001;
4206 MCHBAR32(0x1514) = 0x1110000;
4207 MCHBAR32(0x1518) = 0x7040120;
4208 MCHBAR32(0x151c) = 0x2090220;
4209 MCHBAR32(0x1520) = 0x70b1210;
4210 MCHBAR32(0x1524) = 0x70b1310;
4211 MCHBAR32(0x1528) = 0x2090220;
4212 MCHBAR32(0x152c) = 0x1010001;
4213 MCHBAR32(0x1530) = 0x1110000;
4214 MCHBAR32(0x1534) = 0x1010110;
4215 MCHBAR32(0x1538) = 0x1081310;
4216 MCHBAR32(0x153c) = 0x5041200;
4217 MCHBAR32(0x1540) = 0x5041310;
4218 MCHBAR32(0x1544) = 0x1081310;
4219 MCHBAR32(0x1548) = 0x1010001;
4220 MCHBAR32(0x154c) = 0x1110000;
4221 MCHBAR32(0x1550) = 0x1040120;
4222 MCHBAR32(0x1554) = 0x4051210;
4223 MCHBAR32(0x1558) = 0xd051200;
4224 MCHBAR32(0x155c) = 0xd051200;
4225 MCHBAR32(0x1560) = 0x4051210;
4226 MCHBAR32(0x1564) = 0x1010001;
4227 MCHBAR32(0x1568) = 0x1110000;
4228 MCHBAR16(0x1222) = 0x220a;
4229 MCHBAR16(0x123c) = 0x1fc0;
4230 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004231 }
4232
Felix Heldf83d80b2018-07-29 05:30:30 +02004233 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004234 MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004235 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004236
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004237 MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004238
4239 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004240 MCHBAR8_AND(0x2ca8, ~3);
4241 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02004242 /* This issues a CPU reset without resetting the platform */
4243 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02004244 /* Write back the S3 state to PM1_CNT to let the reset CPU
4245 know it also needs to take the s3 path. */
4246 if (s3resume)
4247 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
4248 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02004249 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004250 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004251 }
4252
Felix Held04be2dd2018-07-29 04:53:22 +02004253 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004254 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004255 pci_write_config32(PCI_DEV (0xff, 0, 0), 0x60, 0x20220);
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004256 MCHBAR16(0x2c20); // !!!!
4257 MCHBAR16(0x2c10); // !!!!
4258 MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004259 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004260 udelay(1000);
4261 write_1d0(0, 0x33d, 0, 0);
4262 write_500(&info, 0, 0, 0xb61, 0, 0);
4263 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004264 MCHBAR32(0x1a30) = 0x0;
4265 MCHBAR32(0x1a34) = 0x0;
4266 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4267 (info.populated_ranks[0][0][0] * 0xa0);
4268 MCHBAR16(0x616) = 0x26a;
4269 MCHBAR32(0x134) = 0x856000;
4270 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004271 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4272 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004273 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004274 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4275 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004276 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004277 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004278 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4279 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004280 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4281 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4282 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4283 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4284 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4285 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4286 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4287 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4288 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4289 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004290 }
4291
4292 write_1d0(0x4, 0x151, 4, 1);
4293 write_1d0(0, 0x142, 3, 1);
4294 rdmsr(0x1ac); // !!!!
4295 write_500(&info, 1, 1, 0x6b3, 4, 1);
4296 write_500(&info, 1, 1, 0x6cf, 4, 1);
4297
4298 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4299
4300 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4301 populated_ranks[0]
4302 [0][0]) << 0),
4303 0x1d1, 3, 1);
4304 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004305 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4306 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004307 }
4308
4309 set_334(0);
4310
4311 program_base_timings(&info);
4312
Felix Held04be2dd2018-07-29 04:53:22 +02004313 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004314
4315 write_1d0(0x2, 0x1d5, 2, 1);
4316 write_1d0(0x20, 0x166, 7, 1);
4317 write_1d0(0x0, 0xeb, 3, 1);
4318 write_1d0(0x0, 0xf3, 6, 1);
4319
4320 for (channel = 0; channel < NUM_CHANNELS; channel++)
4321 for (lane = 0; lane < 9; lane++) {
4322 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4323 u8 a;
4324 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4325 write_500(&info, channel, a, addr, 6, 1);
4326 }
4327
4328 udelay(1000);
4329
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004330 if (s3resume) {
4331 if (info.cached_training == NULL) {
4332 u32 reg32;
4333 printk(BIOS_ERR,
4334 "Couldn't find training data. Rebooting\n");
4335 reg32 = inl(DEFAULT_PMBASE + 0x04);
4336 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004337 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004338 }
4339 int tm;
4340 info.training = *info.cached_training;
4341 for (tm = 0; tm < 4; tm++)
4342 for (channel = 0; channel < NUM_CHANNELS; channel++)
4343 for (slot = 0; slot < NUM_SLOTS; slot++)
4344 for (rank = 0; rank < NUM_RANKS; rank++)
4345 for (lane = 0; lane < 9; lane++)
4346 write_500(&info,
4347 channel,
4348 info.training.
4349 lane_timings
4350 [tm][channel]
4351 [slot][rank]
4352 [lane],
4353 get_timing_register_addr
4354 (lane, tm,
4355 slot, rank),
4356 9, 0);
4357 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4358 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4359 }
4360
Felix Heldf83d80b2018-07-29 05:30:30 +02004361 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004362 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004363 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004364 MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004365
4366 program_board_delay(&info);
4367
Felix Held04be2dd2018-07-29 04:53:22 +02004368 MCHBAR8(0x5ff) = 0x0;
4369 MCHBAR8(0x5ff) = 0x80;
4370 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004371
Felix Held04be2dd2018-07-29 04:53:22 +02004372 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004373 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004374 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004375 gav(read_1d0(0x14b, 7)); // = 0x81023100
4376 write_1d0(0x30, 0x14b, 7, 1);
4377 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4378 write_1d0(7, 0xd6, 6, 1);
4379 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4380 write_1d0(7, 0x328, 6, 1);
4381
4382 for (channel = 0; channel < NUM_CHANNELS; channel++)
4383 set_4cf(&info, channel,
4384 info.populated_ranks[channel][0][0] ? 8 : 0);
4385
4386 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4387 write_1d0(2, 0x116, 4, 1);
4388 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4389 write_1d0(0, 0xae, 6, 1);
4390 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4391 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004392 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4393 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004394 MCHBAR32_AND(0x140, ~0x07000000);
4395 MCHBAR32_AND(0x138, ~0x07000000);
4396 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004397 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004398 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004399 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004400
4401 {
4402 u32 t;
4403 u8 val_a1;
4404 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4405 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4406 rmw_1d0(0x320, 0x07,
4407 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4408 rmw_1d0(0x14b, 0x78,
4409 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4410 4), 7,
4411 1);
4412 rmw_1d0(0xce, 0x38,
4413 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4414 4), 6,
4415 1);
4416 }
4417
4418 for (channel = 0; channel < NUM_CHANNELS; channel++)
4419 set_4cf(&info, channel,
4420 info.populated_ranks[channel][0][0] ? 9 : 1);
4421
4422 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004423 MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004424 write_1d0(2, 0xae, 6, 1);
4425 write_1d0(2, 0x300, 6, 1);
4426 write_1d0(2, 0x121, 3, 1);
4427 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4428 write_1d0(4, 0xd6, 6, 1);
4429 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4430 write_1d0(4, 0x328, 6, 1);
4431
4432 for (channel = 0; channel < NUM_CHANNELS; channel++)
4433 set_4cf(&info, channel,
4434 info.populated_ranks[channel][0][0] ? 9 : 0);
4435
Felix Held04be2dd2018-07-29 04:53:22 +02004436 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4437 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004438 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004439 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004440 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4441 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4442 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4443 write_1d0(0, 0x21c, 6, 1);
4444 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4445 write_1d0(0x35, 0x14b, 7, 1);
4446
4447 for (channel = 0; channel < NUM_CHANNELS; channel++)
4448 set_4cf(&info, channel,
4449 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4450
4451 set_334(1);
4452
Felix Held04be2dd2018-07-29 04:53:22 +02004453 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004454
4455 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4456 write_500(&info, channel,
4457 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4458 1);
4459 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4460 }
Felix Held04be2dd2018-07-29 04:53:22 +02004461 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4462 MCHBAR16(0x6c0) = 0x14a0;
4463 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4464 MCHBAR16(0x232) = 0x8;
4465 /* 0x40004 or 0 depending on ? */
4466 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4467 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4468 MCHBAR32(0x128) = 0x2150d05;
4469 MCHBAR8(0x12c) = 0x1f;
4470 MCHBAR8(0x12d) = 0x56;
4471 MCHBAR8(0x12e) = 0x31;
4472 MCHBAR8(0x12f) = 0x0;
4473 MCHBAR8(0x271) = 0x2;
4474 MCHBAR8(0x671) = 0x2;
4475 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004476 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004477 MCHBAR32(0x294 + (channel << 10)) =
4478 (info.populated_ranks_mask[channel] & 3) << 16;
4479 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4480 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004481 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004482 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4483 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004484
4485 if (!s3resume)
4486 jedec_init(&info);
4487
4488 int totalrank = 0;
4489 for (channel = 0; channel < NUM_CHANNELS; channel++)
4490 for (slot = 0; slot < NUM_SLOTS; slot++)
4491 for (rank = 0; rank < NUM_RANKS; rank++)
4492 if (info.populated_ranks[channel][slot][rank]) {
4493 jedec_read(&info, channel, slot, rank,
4494 totalrank, 0xa, 0x400);
4495 totalrank++;
4496 }
4497
Felix Held04be2dd2018-07-29 04:53:22 +02004498 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004499
Felix Heldf83d80b2018-07-29 05:30:30 +02004500 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4501 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004502
4503 if (!s3resume) {
4504 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004505 MCHBAR32(0x294 + (channel << 10)) =
4506 (info.populated_ranks_mask[channel] & 3) << 16;
4507 MCHBAR16(0x298 + (channel << 10)) =
4508 info.populated_ranks[channel][0][0] |
4509 (info.populated_ranks[channel][0][1] << 5);
4510 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004511 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004512 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004513
4514 {
4515 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004516 a = MCHBAR8(0x243);
4517 b = MCHBAR8(0x643);
4518 MCHBAR8(0x243) = a | 2;
4519 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004520 }
4521
4522 write_1d0(7, 0x19b, 3, 1);
4523 write_1d0(7, 0x1c0, 3, 1);
4524 write_1d0(4, 0x1c6, 4, 1);
4525 write_1d0(4, 0x1cc, 4, 1);
4526 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4527 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004528 MCHBAR32(0x584) = 0xfffff;
4529 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004530
4531 for (channel = 0; channel < NUM_CHANNELS; channel++)
4532 for (slot = 0; slot < NUM_SLOTS; slot++)
4533 for (rank = 0; rank < NUM_RANKS; rank++)
4534 if (info.
4535 populated_ranks[channel][slot]
4536 [rank])
4537 config_rank(&info, s3resume,
4538 channel, slot,
4539 rank);
4540
Felix Held04be2dd2018-07-29 04:53:22 +02004541 MCHBAR8(0x243) = 0x1;
4542 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004543 }
4544
4545 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004546 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004547 write_26c(0, 0x820);
4548 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004549 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004550 /* end */
4551
4552 if (s3resume) {
4553 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004554 MCHBAR32(0x294 + (channel << 10)) =
4555 (info.populated_ranks_mask[channel] & 3) << 16;
4556 MCHBAR16(0x298 + (channel << 10)) =
4557 info.populated_ranks[channel][0][0] |
4558 (info.populated_ranks[channel][0][1] << 5);
4559 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004560 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004561 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004562 }
4563
Felix Held04be2dd2018-07-29 04:53:22 +02004564 MCHBAR32_AND(0xfa4, ~0x01000002);
4565 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004566
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004567 /* Before training. */
4568 timestamp_add_now(103);
4569
4570 if (!s3resume)
4571 ram_training(&info);
4572
4573 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004574 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004575
4576 dump_timings(&info);
4577
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004578 program_modules_memory_map(&info, 0);
4579 program_total_memory_map(&info);
4580
4581 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004582 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004583 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004584 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004585 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004586 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004587 else
Felix Held04be2dd2018-07-29 04:53:22 +02004588 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004589
Felix Held04be2dd2018-07-29 04:53:22 +02004590 MCHBAR32_AND(0xfac, ~0x80000000);
4591 MCHBAR32(0xfb4) = 0x4800;
4592 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4593 MCHBAR32(0xe94) = 0x7ffff;
4594 MCHBAR32(0xfc0) = 0x80002040;
4595 MCHBAR32(0xfc4) = 0x701246;
4596 MCHBAR8_AND(0xfc8, ~0x70);
4597 MCHBAR32_OR(0xe5c, 0x1000000);
4598 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4599 MCHBAR32(0x50) = 0x700b0;
4600 MCHBAR32(0x3c) = 0x10;
4601 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4602 MCHBAR8_OR(0xff4, 0x2);
4603 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004604
Felix Held29a9c072018-07-29 01:34:45 +02004605#if 1
Felix Held04be2dd2018-07-29 04:53:22 +02004606 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4607 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4608 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004609
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004610 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4611 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4612 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004613
4614#else
4615 {
4616 u32 eax;
Felix Held04be2dd2018-07-29 04:53:22 +02004617 // = 0xe911714b
4618 eax = read32p(0xffc + (MCHBAR32(0xd00) & ~1)) | 0x08000000;
4619 write32p(0xffc + (MCHBAR32(0xd00) & ~1), eax);
4620 // = 0xe911714b
4621 eax = read32p(0xffc + (MCHBAR32(0xdc0) & ~1)) | 0x40000000;
4622 write32p(0xffc + (MCHBAR32(0xdc0) & ~1), eax);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004623 }
4624#endif
4625
4626 {
4627 u32 eax;
4628
4629 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004630 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4631 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4632 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004633 }
4634
4635 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004636 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004637 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004638 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004639 else
Felix Held04be2dd2018-07-29 04:53:22 +02004640 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004641
Felix Held04be2dd2018-07-29 04:53:22 +02004642 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004643
Felix Held04be2dd2018-07-29 04:53:22 +02004644 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004645 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004646 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004647 else
Felix Held04be2dd2018-07-29 04:53:22 +02004648 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004649 }
4650
Felix Held04be2dd2018-07-29 04:53:22 +02004651 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004652
4653 {
4654 u8 al;
4655 al = 0xd;
4656 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4657 al += 2;
4658 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004659 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004660 }
4661
4662 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004663 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4664 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4665 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4666 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004667 }
4668 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004669 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004670 reg1c = read32p(DEFAULT_EPBAR | 0x01c); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004671 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004672 write32p(DEFAULT_EPBAR | 0x01c, reg1c); // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004673 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004674 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004675 MCHBAR8_OR(0x1210, 2);
4676 MCHBAR32(0x1200) = 0x8800440;
4677 MCHBAR32(0x1204) = 0x53ff0453;
4678 MCHBAR32(0x1208) = 0x19002043;
4679 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004680
4681 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004682 MCHBAR16(0x1214) = 0x220;
4683 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004684 }
4685
Felix Held04be2dd2018-07-29 04:53:22 +02004686 MCHBAR8_OR(0x1214, 0x4);
4687 MCHBAR8(0x120c) = 0x1;
4688 MCHBAR8(0x1218) = 0x3;
4689 MCHBAR8(0x121a) = 0x3;
4690 MCHBAR8(0x121c) = 0x3;
4691 MCHBAR16(0xc14) = 0x0;
4692 MCHBAR16(0xc20) = 0x0;
4693 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004694
4695 /* revision dependent here. */
4696
Felix Held04be2dd2018-07-29 04:53:22 +02004697 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004698
4699 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004700 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004701
Felix Held04be2dd2018-07-29 04:53:22 +02004702 MCHBAR16_OR(0x1230, 0x8000);
4703 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004704
4705 u8 bl, ebpb;
4706 u16 reg_1020;
4707
Felix Held04be2dd2018-07-29 04:53:22 +02004708 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4709 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004710
Felix Held04be2dd2018-07-29 04:53:22 +02004711 MCHBAR32(0x1000) = 0x100;
4712 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004713
4714 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004715 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004716 bl = reg_1020 >> 8;
4717 ebpb = reg_1020 & 0xff;
4718 } else {
4719 ebpb = 0;
4720 bl = 8;
4721 }
4722
4723 rdmsr(0x1a2);
4724
Felix Held04be2dd2018-07-29 04:53:22 +02004725 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004726
Felix Held04be2dd2018-07-29 04:53:22 +02004727 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004728
Felix Held04be2dd2018-07-29 04:53:22 +02004729 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004730
Felix Held04be2dd2018-07-29 04:53:22 +02004731 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004732 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004733 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4734 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004735 }
4736
4737 setup_heci_uma(&info);
4738
4739 if (info.uma_enabled) {
4740 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004741 MCHBAR32_OR(0x11b0, 0x4000);
4742 MCHBAR32_OR(0x11b4, 0x4000);
4743 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004744
Felix Held04be2dd2018-07-29 04:53:22 +02004745 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4746 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4747 MCHBAR16_OR(0x1170, 0x1000);
4748
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004749 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004750
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004751 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004752 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004753 ;
4754 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004755 }
4756
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004757 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4758 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004759 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004760 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004761
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004762 udelay(1000);
4763 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004764 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4765
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004766 if (!s3resume)
4767 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004768 if (s3resume && cbmem_wasnot_inited) {
4769 u32 reg32;
4770 printk(BIOS_ERR, "Failed S3 resume.\n");
4771 ram_check(0x100000, 0x200000);
4772
4773 /* Clear SLP_TYPE. */
4774 reg32 = inl(DEFAULT_PMBASE + 0x04);
4775 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4776
4777 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004778 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004779 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004780}