blob: c887de1d9879e0c57e2c8b9bd39fc96b2bc9c244 [file] [log] [blame]
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013 Vladimir Serbinenko.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010015 */
16
Kyösti Mälkki931c1dc2014-06-30 09:40:19 +030017#include <stdlib.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010018#include <console/console.h>
19#include <string.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010020#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020021#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020022#include <device/pci_ops.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010023#include <cpu/x86/msr.h>
24#include <cbmem.h>
Elyes HAOUASd45f3382019-04-28 18:04:35 +020025#include <cf9_reset.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010026#include <arch/cbfs.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010027#include <ip_checksum.h>
28#include <pc80/mc146818rtc.h>
29#include <device/pci_def.h>
Patrick Rudolph266a1f72016-06-09 18:13:34 +020030#include <device/device.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010031#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010032#include <spd.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010033#include <timestamp.h>
34#include <cpu/x86/mtrr.h>
35#include <cpu/intel/speedstep.h>
36#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010037#include <mrc_cache.h>
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020038#include <southbridge/intel/ibexpeak/me.h>
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];
210 unsigned total_memory_mb;
211 unsigned interleaved_part_mb;
212 unsigned non_interleaved_part_mb;
213
214 u32 heci_bar;
215 u64 heci_uma_addr;
216 unsigned memory_reserved_for_heci_mb;
217
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{
552 unsigned cycletime;
553 unsigned cas_latency_time;
554 unsigned supported_cas_latencies;
555 unsigned channel, slot;
556 unsigned clock_speed_index;
557 unsigned min_cas_latency;
558 unsigned cas_latency;
559 unsigned max_clock_index;
560
561 /* Find common CAS latency */
562 supported_cas_latencies = 0x3fe;
563 for (channel = 0; channel < NUM_CHANNELS; channel++)
564 for (slot = 0; slot < NUM_SLOTS; slot++)
565 if (info->populated_ranks[channel][slot][0])
566 supported_cas_latencies &=
567 2 *
568 (info->
569 spd[channel][slot][CAS_LATENCIES_LSB] |
570 (info->
571 spd[channel][slot][CAS_LATENCIES_MSB] <<
572 8));
573
574 max_clock_index = min(3, info->max_supported_clock_speed_index);
575
576 cycletime = min_cycletime[max_clock_index];
577 cas_latency_time = min_cas_latency_time[max_clock_index];
578
579 for (channel = 0; channel < NUM_CHANNELS; channel++)
580 for (slot = 0; slot < NUM_SLOTS; slot++)
581 if (info->populated_ranks[channel][slot][0]) {
582 unsigned timebase;
583 timebase =
584 1000 *
585 info->
586 spd[channel][slot][TIMEBASE_DIVIDEND] /
587 info->spd[channel][slot][TIMEBASE_DIVISOR];
588 cycletime =
589 max(cycletime,
590 timebase *
591 info->spd[channel][slot][CYCLETIME]);
592 cas_latency_time =
593 max(cas_latency_time,
594 timebase *
595 info->
596 spd[channel][slot][CAS_LATENCY_TIME]);
597 }
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{
630 unsigned channel;
631 unsigned slot, rank, lane;
632 unsigned extended_silicon_revision;
633 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. */
793static unsigned frequency_11(struct raminfo *info)
794{
795 return (info->clock_speed_index + 3) * 120;
796}
797
798/* Frequency in 0.1 MHz units. */
799static unsigned frequency_01(struct raminfo *info)
800{
801 return 100 * frequency_11(info) / 9;
802}
803
804static unsigned ps_to_halfcycles(struct raminfo *info, unsigned int ps)
805{
806 return (frequency_11(info) * 2) * ps / 900000;
807}
808
809static unsigned ns_to_cycles(struct raminfo *info, unsigned int ns)
810{
811 return (frequency_11(info)) * ns / 900;
812}
813
814static void compute_derived_timings(struct raminfo *info)
815{
816 unsigned channel, slot, rank;
817 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;
823 int some_delay_3_halfcycles;
824 int some_delay_3_ps_rounded;
825 int some_delay_1_cycle_ceil;
826 int some_delay_1_cycle_floor;
827
828 some_delay_3_halfcycles = 0;
829 some_delay_3_ps_rounded = 0;
830 extended_silicon_revision = info->silicon_revision;
831 if (!info->silicon_revision)
832 for (channel = 0; channel < NUM_CHANNELS; channel++)
833 for (slot = 0; slot < NUM_SLOTS; slot++)
834 if ((info->
835 spd[channel][slot][MODULE_TYPE] & 0xF) ==
836 3)
837 extended_silicon_revision = 4;
838 if (info->board_lane_delay[7] < 5)
839 info->board_lane_delay[7] = 5;
840 info->revision_flag_1 = 2;
841 if (info->silicon_revision == 2 || info->silicon_revision == 3)
842 info->revision_flag_1 = 0;
843 if (info->revision < 16)
844 info->revision_flag_1 = 0;
845
846 if (info->revision < 8)
847 info->revision_flag_1 = 0;
848 if (info->revision >= 8 && (info->silicon_revision == 0
849 || info->silicon_revision == 1))
850 some_delay_2_ps = 735;
851 else
852 some_delay_2_ps = 750;
853
854 if (info->revision >= 0x10 && (info->silicon_revision == 0
855 || info->silicon_revision == 1))
856 some_delay_1_ps = 3929;
857 else
858 some_delay_1_ps = 3490;
859
860 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
861 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
862 if (some_delay_1_ps % cycle_ps(info))
863 some_delay_1_cycle_ceil++;
864 else
865 some_delay_1_cycle_floor--;
866 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
867 if (info->revision_flag_1)
868 some_delay_2_ps = halfcycle_ps(info) >> 6;
869 some_delay_2_ps +=
870 max(some_delay_1_ps - 30,
871 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
872 375;
873 some_delay_3_ps =
874 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
875 if (info->revision_flag_1) {
876 if (some_delay_3_ps < 150)
877 some_delay_3_halfcycles = 0;
878 else
879 some_delay_3_halfcycles =
880 (some_delay_3_ps << 6) / halfcycle_ps(info);
881 some_delay_3_ps_rounded =
882 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
883 }
884 some_delay_2_halfcycles_ceil =
885 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
886 2 * (some_delay_1_cycle_ceil - 1);
887 if (info->revision_flag_1 && some_delay_3_ps < 150)
888 some_delay_2_halfcycles_ceil++;
889 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
890 if (info->revision < 0x10)
891 some_delay_2_halfcycles_floor =
892 some_delay_2_halfcycles_ceil - 1;
893 if (!info->revision_flag_1)
894 some_delay_2_halfcycles_floor++;
895 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
896 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
897 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
898 || (info->populated_ranks[1][0][0]
899 && info->populated_ranks[1][1][0]))
900 info->max_slots_used_in_channel = 2;
901 else
902 info->max_slots_used_in_channel = 1;
903 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200904 MCHBAR32(0x244 + (channel << 10)) =
905 ((info->revision < 8) ? 1 : 0x200) |
906 ((2 - info->max_slots_used_in_channel) << 17) |
907 (channel << 21) |
908 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100909 if (info->max_slots_used_in_channel == 1) {
910 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
911 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
912 } else {
913 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 */
914 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
915 || (count_ranks_in_channel(info, 1) ==
916 2)) ? 2 : 3;
917 }
918 for (channel = 0; channel < NUM_CHANNELS; channel++) {
919 int max_of_unk;
920 int min_of_unk_2;
921
922 int i, count;
923 int sum;
924
925 if (!info->populated_ranks_mask[channel])
926 continue;
927
928 max_of_unk = 0;
929 min_of_unk_2 = 32767;
930
931 sum = 0;
932 count = 0;
933 for (i = 0; i < 3; i++) {
934 int unk1;
935 if (info->revision < 8)
936 unk1 =
937 u8_FFFD1891[0][channel][info->
938 clock_speed_index]
939 [i];
940 else if (!
941 (info->revision >= 0x10
942 || info->revision_flag_1))
943 unk1 =
944 u8_FFFD1891[1][channel][info->
945 clock_speed_index]
946 [i];
947 else
948 unk1 = 0;
949 for (slot = 0; slot < NUM_SLOTS; slot++)
950 for (rank = 0; rank < NUM_RANKS; rank++) {
951 int a = 0;
952 int b = 0;
953
954 if (!info->
955 populated_ranks[channel][slot]
956 [rank])
957 continue;
958 if (extended_silicon_revision == 4
959 && (info->
960 populated_ranks_mask[channel] &
961 5) != 5) {
962 if ((info->
963 spd[channel][slot]
964 [REFERENCE_RAW_CARD_USED] &
965 0x1F) == 3) {
966 a = u16_ffd1178[0]
967 [info->
968 clock_speed_index];
969 b = u16_fe0eb8[0][info->
970 clock_speed_index];
971 } else
972 if ((info->
973 spd[channel][slot]
974 [REFERENCE_RAW_CARD_USED]
975 & 0x1F) == 5) {
976 a = u16_ffd1178[1]
977 [info->
978 clock_speed_index];
979 b = u16_fe0eb8[1][info->
980 clock_speed_index];
981 }
982 }
983 min_of_unk_2 = min(min_of_unk_2, a);
984 min_of_unk_2 = min(min_of_unk_2, b);
985 if (rank == 0) {
986 sum += a;
987 count++;
988 }
989 {
990 int t;
991 t = b +
992 u8_FFFD0EF8[channel]
993 [extended_silicon_revision]
994 [info->
995 mode4030[channel]][info->
996 clock_speed_index];
997 if (unk1 >= t)
998 max_of_unk =
999 max(max_of_unk,
1000 unk1 - t);
1001 }
1002 }
1003 {
1004 int t =
1005 u8_FFFD17E0[channel]
1006 [extended_silicon_revision][info->
1007 mode4030
1008 [channel]]
1009 [info->clock_speed_index] + min_of_unk_2;
1010 if (unk1 >= t)
1011 max_of_unk = max(max_of_unk, unk1 - t);
1012 }
1013 }
1014
Jacob Garber64fb4a32019-06-10 17:29:18 -06001015 if (count == 0)
1016 die("No memory ranks found for channel %u\n", channel);
1017
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001018 info->avg4044[channel] = sum / count;
1019 info->max4048[channel] = max_of_unk;
1020 }
1021}
1022
1023static void jedec_read(struct raminfo *info,
1024 int channel, int slot, int rank,
1025 int total_rank, u8 addr3, unsigned int value)
1026{
1027 /* Handle mirrored mapping. */
1028 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001029 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1030 ((addr3 >> 1) & 0x10);
1031 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1032 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001033
1034 /* Handle mirrored mapping. */
1035 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1036 value =
1037 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1038 << 1);
1039
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001040 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001041
Felix Held04be2dd2018-07-29 04:53:22 +02001042 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1043 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001044
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001045 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001046}
1047
1048enum {
1049 MR1_RZQ12 = 512,
1050 MR1_RZQ2 = 64,
1051 MR1_RZQ4 = 4,
1052 MR1_ODS34OHM = 2
1053};
1054
1055enum {
1056 MR0_BT_INTERLEAVED = 8,
1057 MR0_DLL_RESET_ON = 256
1058};
1059
1060enum {
1061 MR2_RTT_WR_DISABLED = 0,
1062 MR2_RZQ2 = 1 << 10
1063};
1064
1065static void jedec_init(struct raminfo *info)
1066{
1067 int write_recovery;
1068 int channel, slot, rank;
1069 int total_rank;
1070 int dll_on;
1071 int self_refresh_temperature;
1072 int auto_self_refresh;
1073
1074 auto_self_refresh = 1;
1075 self_refresh_temperature = 1;
1076 if (info->board_lane_delay[3] <= 10) {
1077 if (info->board_lane_delay[3] <= 8)
1078 write_recovery = info->board_lane_delay[3] - 4;
1079 else
1080 write_recovery = 5;
1081 } else {
1082 write_recovery = 6;
1083 }
1084 FOR_POPULATED_RANKS {
1085 auto_self_refresh &=
1086 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1087 self_refresh_temperature &=
1088 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1089 }
1090 if (auto_self_refresh == 1)
1091 self_refresh_temperature = 0;
1092
1093 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1094 || (info->populated_ranks[0][0][0]
1095 && info->populated_ranks[0][1][0])
1096 || (info->populated_ranks[1][0][0]
1097 && info->populated_ranks[1][1][0]));
1098
1099 total_rank = 0;
1100
1101 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1102 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1103 int rzq_reg58e;
1104
1105 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1106 rzq_reg58e = 64;
1107 rtt = MR1_RZQ2;
1108 if (info->clock_speed_index != 0) {
1109 rzq_reg58e = 4;
1110 if (info->populated_ranks_mask[channel] == 3)
1111 rtt = MR1_RZQ4;
1112 }
1113 } else {
1114 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1115 rtt = MR1_RZQ12;
1116 rzq_reg58e = 64;
1117 rtt_wr = MR2_RZQ2;
1118 } else {
1119 rzq_reg58e = 4;
1120 rtt = MR1_RZQ4;
1121 }
1122 }
1123
Felix Held04be2dd2018-07-29 04:53:22 +02001124 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1125 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1126 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1127 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1128 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001129
1130 for (slot = 0; slot < NUM_SLOTS; slot++)
1131 for (rank = 0; rank < NUM_RANKS; rank++)
1132 if (info->populated_ranks[channel][slot][rank]) {
1133 jedec_read(info, channel, slot, rank,
1134 total_rank, 0x28,
1135 rtt_wr | (info->
1136 clock_speed_index
1137 << 3)
1138 | (auto_self_refresh << 6) |
1139 (self_refresh_temperature <<
1140 7));
1141 jedec_read(info, channel, slot, rank,
1142 total_rank, 0x38, 0);
1143 jedec_read(info, channel, slot, rank,
1144 total_rank, 0x18,
1145 rtt | MR1_ODS34OHM);
1146 jedec_read(info, channel, slot, rank,
1147 total_rank, 6,
1148 (dll_on << 12) |
1149 (write_recovery << 9)
1150 | ((info->cas_latency - 4) <<
1151 4) | MR0_BT_INTERLEAVED |
1152 MR0_DLL_RESET_ON);
1153 total_rank++;
1154 }
1155 }
1156}
1157
1158static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1159{
1160 unsigned channel, slot, rank;
1161 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1162 unsigned int channel_0_non_interleaved;
1163
1164 FOR_ALL_RANKS {
1165 if (info->populated_ranks[channel][slot][rank]) {
1166 total_mb[channel] +=
1167 pre_jedec ? 256 : (256 << info->
1168 density[channel][slot] >> info->
1169 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001170 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1171 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1172 (info->is_x16_module[channel][slot] |
1173 ((info->density[channel][slot] + 1) << 1))) |
1174 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001175 }
Felix Held04be2dd2018-07-29 04:53:22 +02001176 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1177 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001178 }
1179
1180 info->total_memory_mb = total_mb[0] + total_mb[1];
1181
1182 info->interleaved_part_mb =
1183 pre_jedec ? 0 : 2 * min(total_mb[0], total_mb[1]);
1184 info->non_interleaved_part_mb =
1185 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1186 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001187 MCHBAR32(0x100) = channel_0_non_interleaved |
1188 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001189 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001190 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001191}
1192
1193static void program_board_delay(struct raminfo *info)
1194{
1195 int cas_latency_shift;
1196 int some_delay_ns;
1197 int some_delay_3_half_cycles;
1198
1199 unsigned channel, i;
1200 int high_multiplier;
1201 int lane_3_delay;
1202 int cas_latency_derived;
1203
1204 high_multiplier = 0;
1205 some_delay_ns = 200;
1206 some_delay_3_half_cycles = 4;
1207 cas_latency_shift = info->silicon_revision == 0
1208 || info->silicon_revision == 1 ? 1 : 0;
1209 if (info->revision < 8) {
1210 some_delay_ns = 600;
1211 cas_latency_shift = 0;
1212 }
1213 {
1214 int speed_bit;
1215 speed_bit =
1216 ((info->clock_speed_index > 1
1217 || (info->silicon_revision != 2
1218 && info->silicon_revision != 3))) ^ (info->revision >=
1219 0x10);
1220 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1221 3, 1);
1222 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1223 3, 1);
1224 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1225 && (info->silicon_revision == 2
1226 || info->silicon_revision == 3))
1227 rmw_1d0(0x116, 5, 2, 4, 1);
1228 }
Felix Held04be2dd2018-07-29 04:53:22 +02001229 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1230 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001231
Felix Held04be2dd2018-07-29 04:53:22 +02001232 MCHBAR8(0x124) = info->board_lane_delay[4] +
1233 ((frequency_01(info) + 999) / 1000);
1234 MCHBAR16(0x125) = 0x1360;
1235 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001236 if (info->fsb_frequency < frequency_11(info) / 2) {
1237 unsigned some_delay_2_half_cycles;
1238 high_multiplier = 1;
1239 some_delay_2_half_cycles = ps_to_halfcycles(info,
1240 ((3 *
1241 fsbcycle_ps(info))
1242 >> 1) +
1243 (halfcycle_ps(info)
1244 *
1245 reg178_min[info->
1246 clock_speed_index]
1247 >> 6)
1248 +
1249 4 *
1250 halfcycle_ps(info)
1251 + 2230);
1252 some_delay_3_half_cycles =
1253 min((some_delay_2_half_cycles +
1254 (frequency_11(info) * 2) * (28 -
1255 some_delay_2_half_cycles) /
1256 (frequency_11(info) * 2 -
1257 4 * (info->fsb_frequency))) >> 3, 7);
1258 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001259 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001260 some_delay_3_half_cycles = 3;
1261 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001262 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1263 MCHBAR32(0x224 + (channel << 10)) =
1264 (info->max_slots_used_in_channel - 1) |
1265 ((info->cas_latency - 5 - info->clock_speed_index)
1266 << 21) | ((info->max_slots_used_in_channel +
1267 info->cas_latency - cas_latency_shift - 4) << 16) |
1268 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1269 ((info->cas_latency - info->clock_speed_index +
1270 info->max_slots_used_in_channel - 6) << 8);
1271 MCHBAR32(0x228 + (channel << 10)) =
1272 info->max_slots_used_in_channel;
1273 MCHBAR8(0x239 + (channel << 10)) = 32;
1274 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1275 (some_delay_3_half_cycles << 25) | 0x840000;
1276 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1277 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1278 MCHBAR32(0x24c + (channel << 10)) =
1279 ((!!info->clock_speed_index) << 17) |
1280 (((2 + info->clock_speed_index -
1281 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001282
Felix Held04be2dd2018-07-29 04:53:22 +02001283 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1284 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1285 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001286
1287 write_500(info, channel,
1288 ((!info->populated_ranks[channel][1][1])
1289 | (!info->populated_ranks[channel][1][0] << 1)
1290 | (!info->populated_ranks[channel][0][1] << 2)
1291 | (!info->populated_ranks[channel][0][0] << 3)),
1292 0x4c9, 4, 1);
1293 }
1294
Felix Held22ca8cb2018-07-29 05:09:44 +02001295 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001296 {
1297 u8 freq_divisor = 2;
1298 if (info->fsb_frequency == frequency_11(info))
1299 freq_divisor = 3;
1300 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1301 freq_divisor = 1;
1302 else
1303 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001304 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001305 }
1306
1307 if (info->board_lane_delay[3] <= 10) {
1308 if (info->board_lane_delay[3] <= 8)
1309 lane_3_delay = info->board_lane_delay[3];
1310 else
1311 lane_3_delay = 10;
1312 } else {
1313 lane_3_delay = 12;
1314 }
1315 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1316 if (info->clock_speed_index > 1)
1317 cas_latency_derived++;
1318 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001319 MCHBAR32(0x240 + (channel << 10)) =
1320 ((info->clock_speed_index == 0) * 0x11000) |
1321 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1322 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001323 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1324 0x609, 6, 1);
1325 write_500(info, channel,
1326 info->clock_speed_index + 2 * info->cas_latency - 7,
1327 0x601, 6, 1);
1328
Felix Held04be2dd2018-07-29 04:53:22 +02001329 MCHBAR32(0x250 + (channel << 10)) =
1330 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1331 (info->board_lane_delay[7] << 2) |
1332 (info->board_lane_delay[4] << 16) |
1333 (info->board_lane_delay[1] << 25) |
1334 (info->board_lane_delay[1] << 29) | 1;
1335 MCHBAR32(0x254 + (channel << 10)) =
1336 (info->board_lane_delay[1] >> 3) |
1337 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1338 0x80 | (info->board_lane_delay[6] << 1) |
1339 (info->board_lane_delay[2] << 28) |
1340 (cas_latency_derived << 16) | 0x4700000;
1341 MCHBAR32(0x258 + (channel << 10)) =
1342 ((info->board_lane_delay[5] + info->clock_speed_index +
1343 9) << 12) | ((info->clock_speed_index -
1344 info->cas_latency + 12) << 8) |
1345 (info->board_lane_delay[2] << 17) |
1346 (info->board_lane_delay[4] << 24) | 0x47;
1347 MCHBAR32(0x25c + (channel << 10)) =
1348 (info->board_lane_delay[1] << 1) |
1349 (info->board_lane_delay[0] << 8) | 0x1da50000;
1350 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1351 MCHBAR8(0x5f8 + (channel << 10)) =
1352 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001353 }
1354
1355 program_modules_memory_map(info, 1);
1356
Felix Held04be2dd2018-07-29 04:53:22 +02001357 MCHBAR16(0x610) = (min(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
1358 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1359 MCHBAR16_OR(0x612, 0x100);
1360 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001361 for (i = 0; i < 8; i++) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001362 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0x80 + 4 * i,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001363 (info->total_memory_mb - 64) | !i | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001364 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0xc0 + 4 * i, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001365 }
1366}
1367
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001368#define DEFAULT_PCI_MMIO_SIZE 2048
1369#define HOST_BRIDGE PCI_DEVFN(0, 0)
1370
1371static unsigned int get_mmio_size(void)
1372{
1373 const struct device *dev;
1374 const struct northbridge_intel_nehalem_config *cfg = NULL;
1375
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001376 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001377 if (dev)
1378 cfg = dev->chip_info;
1379
1380 /* If this is zero, it just means devicetree.cb didn't set it */
1381 if (!cfg || cfg->pci_mmio_size == 0)
1382 return DEFAULT_PCI_MMIO_SIZE;
1383 else
1384 return cfg->pci_mmio_size;
1385}
1386
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001387#define BETTER_MEMORY_MAP 0
1388
1389static void program_total_memory_map(struct raminfo *info)
1390{
1391 unsigned int TOM, TOLUD, TOUUD;
1392 unsigned int quickpath_reserved;
1393 unsigned int REMAPbase;
1394 unsigned int uma_base_igd;
1395 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001396 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001397 int memory_remap;
1398 unsigned int memory_map[8];
1399 int i;
1400 unsigned int current_limit;
1401 unsigned int tseg_base;
1402 int uma_size_igd = 0, uma_size_gtt = 0;
1403
1404 memset(memory_map, 0, sizeof(memory_map));
1405
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001406 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001407 u16 t = pci_read_config16(NORTHBRIDGE, D0F0_GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001408 gav(t);
1409 const int uma_sizes_gtt[16] =
1410 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1411 /* Igd memory */
1412 const int uma_sizes_igd[16] = {
1413 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1414 256, 512
1415 };
1416
1417 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1418 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1419 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001420
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001421 mmio_size = get_mmio_size();
1422
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001423 TOM = info->total_memory_mb;
1424 if (TOM == 4096)
1425 TOM = 4032;
1426 TOUUD = ALIGN_DOWN(TOM - info->memory_reserved_for_heci_mb, 64);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001427 TOLUD = ALIGN_DOWN(min(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
Elyes HAOUASa342f392018-10-17 10:56:26 +02001428 , TOUUD), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001429 memory_remap = 0;
1430 if (TOUUD - TOLUD > 64) {
1431 memory_remap = 1;
1432 REMAPbase = max(4096, TOUUD);
1433 TOUUD = TOUUD - TOLUD + 4096;
1434 }
1435 if (TOUUD > 4096)
1436 memory_map[2] = TOUUD | 1;
1437 quickpath_reserved = 0;
1438
Jacob Garber975a7e32019-06-10 16:32:47 -06001439 u32 t = pci_read_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 0x68);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001440
Jacob Garber975a7e32019-06-10 16:32:47 -06001441 gav(t);
1442
1443 if (t & 0x800) {
1444 u32 shift = t >> 20;
1445 if (shift == 0)
1446 die("Quickpath value is 0\n");
1447 quickpath_reserved = (u32)1 << find_lowest_bit_set32(shift);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001448 }
Jacob Garber975a7e32019-06-10 16:32:47 -06001449
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001450 if (memory_remap)
1451 TOUUD -= quickpath_reserved;
1452
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001453 uma_base_igd = TOLUD - uma_size_igd;
1454 uma_base_gtt = uma_base_igd - uma_size_gtt;
1455 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1456 if (!memory_remap)
1457 tseg_base -= quickpath_reserved;
1458 tseg_base = ALIGN_DOWN(tseg_base, 8);
1459
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001460 pci_write_config16(NORTHBRIDGE, D0F0_TOLUD, TOLUD << 4);
1461 pci_write_config16(NORTHBRIDGE, D0F0_TOM, TOM >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001462 if (memory_remap) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001463 pci_write_config16(NORTHBRIDGE, D0F0_REMAPBASE, REMAPbase >> 6);
1464 pci_write_config16(NORTHBRIDGE, D0F0_REMAPLIMIT, (TOUUD - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001465 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001466 pci_write_config16(NORTHBRIDGE, D0F0_TOUUD, TOUUD);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001467
1468 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001469 pci_write_config32(NORTHBRIDGE, D0F0_IGD_BASE, uma_base_igd << 20);
1470 pci_write_config32(NORTHBRIDGE, D0F0_GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001471 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001472 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001473
1474 current_limit = 0;
1475 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1476 memory_map[1] = 4096;
1477 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
1478 current_limit = max(current_limit, memory_map[i] & ~1);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001479 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0x80,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001480 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1481 1, 64) | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001482 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0xc0, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001483 }
1484}
1485
1486static void collect_system_info(struct raminfo *info)
1487{
1488 u32 capid0[3];
1489 int i;
1490 unsigned channel;
1491
1492 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001493 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1494 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001495
1496 if (!info->heci_bar)
1497 gav(info->heci_bar =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001498 pci_read_config32(HECIDEV, HECIBAR) & 0xFFFFFFF8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001499 if (!info->memory_reserved_for_heci_mb) {
1500 /* Wait for ME to be ready */
1501 intel_early_me_init();
1502 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1503 }
1504
1505 for (i = 0; i < 3; i++)
1506 gav(capid0[i] =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001507 pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 | (i << 2)));
1508 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001509 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1510
1511 if ((capid0[1] >> 11) & 1)
1512 info->uma_enabled = 0;
1513 else
1514 gav(info->uma_enabled =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001515 pci_read_config8(NORTHBRIDGE, D0F0_DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001516 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1517 info->silicon_revision = 0;
1518
1519 if (capid0[2] & 2) {
1520 info->silicon_revision = 0;
1521 info->max_supported_clock_speed_index = 2;
1522 for (channel = 0; channel < NUM_CHANNELS; channel++)
1523 if (info->populated_ranks[channel][0][0]
1524 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1525 3) {
1526 info->silicon_revision = 2;
1527 info->max_supported_clock_speed_index = 1;
1528 }
1529 } else {
1530 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1531 case 1:
1532 case 2:
1533 info->silicon_revision = 3;
1534 break;
1535 case 3:
1536 info->silicon_revision = 0;
1537 break;
1538 case 0:
1539 info->silicon_revision = 2;
1540 break;
1541 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001542 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001543 case 0x40:
1544 info->silicon_revision = 0;
1545 break;
1546 case 0x48:
1547 info->silicon_revision = 1;
1548 break;
1549 }
1550 }
1551}
1552
1553static void write_training_data(struct raminfo *info)
1554{
1555 int tm, channel, slot, rank, lane;
1556 if (info->revision < 8)
1557 return;
1558
1559 for (tm = 0; tm < 4; tm++)
1560 for (channel = 0; channel < NUM_CHANNELS; channel++)
1561 for (slot = 0; slot < NUM_SLOTS; slot++)
1562 for (rank = 0; rank < NUM_RANKS; rank++)
1563 for (lane = 0; lane < 9; lane++)
1564 write_500(info, channel,
1565 info->
1566 cached_training->
1567 lane_timings[tm]
1568 [channel][slot][rank]
1569 [lane],
1570 get_timing_register_addr
1571 (lane, tm, slot,
1572 rank), 9, 0);
1573 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1574 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1575}
1576
1577static void dump_timings(struct raminfo *info)
1578{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001579 int channel, slot, rank, lane, i;
Arthur Heymansc892db62019-10-14 19:05:14 +02001580 printk(RAM_SPEW, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001581 FOR_POPULATED_RANKS {
Arthur Heymansc892db62019-10-14 19:05:14 +02001582 printk(RAM_SPEW, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001583 slot, rank);
1584 for (lane = 0; lane < 9; lane++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001585 printk(RAM_SPEW, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001586 for (i = 0; i < 4; i++) {
Arthur Heymansc892db62019-10-14 19:05:14 +02001587 printk(RAM_SPEW, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001588 read_500(info, channel,
1589 get_timing_register_addr
1590 (lane, i, slot, rank),
1591 9),
1592 info->training.
1593 lane_timings[i][channel][slot][rank]
1594 [lane]);
1595 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001596 printk(RAM_SPEW, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001597 }
1598 }
Arthur Heymansc892db62019-10-14 19:05:14 +02001599 printk(RAM_SPEW, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001600 info->training.reg_178);
Arthur Heymansc892db62019-10-14 19:05:14 +02001601 printk(RAM_SPEW, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001602 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001603}
1604
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001605/* Read timings and other registers that need to be restored verbatim and
1606 put them to CBMEM.
1607 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001608static void save_timings(struct raminfo *info)
1609{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001610 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001611 int channel, slot, rank, lane, i;
1612
1613 train = info->training;
1614 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1615 for (i = 0; i < 4; i++)
1616 train.lane_timings[i][channel][slot][rank][lane] =
1617 read_500(info, channel,
1618 get_timing_register_addr(lane, i, slot,
1619 rank), 9);
1620 train.reg_178 = read_1d0(0x178, 7);
1621 train.reg_10b = read_1d0(0x10b, 6);
1622
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001623 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1624 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001625 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001626 train.reg274265[channel][0] = reg32 >> 16;
1627 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001628 train.reg274265[channel][2] =
1629 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001630 }
Felix Held04be2dd2018-07-29 04:53:22 +02001631 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1632 train.reg_6dc = MCHBAR32(0x6dc);
1633 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001634
Arthur Heymansb3282092019-04-14 17:53:28 +02001635 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1636 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001637
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001638 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001639 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1640 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001641}
1642
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001643static const struct ram_training *get_cached_training(void)
1644{
Arthur Heymansdc71e252018-01-29 10:14:48 +01001645 struct region_device rdev;
1646 if (mrc_cache_get_current(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1647 &rdev))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001648 return 0;
Arthur Heymansdc71e252018-01-29 10:14:48 +01001649 return (void *)rdev_mmap_full(&rdev);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001650}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001651
1652/* FIXME: add timeout. */
1653static void wait_heci_ready(void)
1654{
Felix Held04be2dd2018-07-29 04:53:22 +02001655 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1656 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001657 write32((DEFAULT_HECIBAR + 0x4),
1658 (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001659}
1660
1661/* FIXME: add timeout. */
1662static void wait_heci_cb_avail(int len)
1663{
1664 union {
1665 struct mei_csr csr;
1666 u32 raw;
1667 } csr;
1668
Felix Held22ca8cb2018-07-29 05:09:44 +02001669 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1670 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001671
1672 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001673 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001674 while (len >
1675 csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
Felix Held22ca8cb2018-07-29 05:09:44 +02001676 csr.csr.buffer_read_ptr))
1677 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001678}
1679
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001680static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001681{
1682 int len = (head->length + 3) / 4;
1683 int i;
1684
1685 wait_heci_cb_avail(len + 1);
1686
1687 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001688 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001689 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001690 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001691
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001692 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1693 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001694}
1695
1696static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001697send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001698{
1699 struct mei_header head;
1700 int maxlen;
1701
1702 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001703 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001704
1705 while (len) {
1706 int cur = len;
1707 if (cur > maxlen) {
1708 cur = maxlen;
1709 head.is_complete = 0;
1710 } else
1711 head.is_complete = 1;
1712 head.length = cur;
1713 head.reserved = 0;
1714 head.client_address = clientaddress;
1715 head.host_address = hostaddress;
1716 send_heci_packet(&head, (u32 *) msg);
1717 len -= cur;
1718 msg += cur;
1719 }
1720}
1721
1722/* FIXME: Add timeout. */
1723static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001724recv_heci_packet(struct raminfo *info, struct mei_header *head, u32 *packet,
1725 u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001726{
1727 union {
1728 struct mei_csr csr;
1729 u32 raw;
1730 } csr;
1731 int i = 0;
1732
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001733 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001734 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001735 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001736 }
Felix Held04be2dd2018-07-29 04:53:22 +02001737 while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr)
1738 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001739 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001740 if (!head->length) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001741 write32(DEFAULT_HECIBAR + 0x4,
1742 read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001743 *packet_size = 0;
1744 return 0;
1745 }
1746 if (head->length + 4 > 4 * csr.csr.buffer_depth
1747 || head->length > *packet_size) {
1748 *packet_size = 0;
1749 return -1;
1750 }
1751
1752 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001753 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Felix Held22ca8cb2018-07-29 05:09:44 +02001754 while (((head->length + 3) >> 2) >
1755 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr))
1756 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001757
1758 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001759 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001760 *packet_size = head->length;
1761 if (!csr.csr.ready)
1762 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001763 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001764 return 0;
1765}
1766
1767/* FIXME: Add timeout. */
1768static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001769recv_heci_message(struct raminfo *info, u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001770{
1771 struct mei_header head;
1772 int current_position;
1773
1774 current_position = 0;
1775 while (1) {
1776 u32 current_size;
1777 current_size = *message_size - current_position;
1778 if (recv_heci_packet
1779 (info, &head, message + (current_position >> 2),
1780 &current_size) == -1)
1781 break;
1782 if (!current_size)
1783 break;
1784 current_position += current_size;
1785 if (head.is_complete) {
1786 *message_size = current_position;
1787 return 0;
1788 }
1789
1790 if (current_position >= *message_size)
1791 break;
1792 }
1793 *message_size = 0;
1794 return -1;
1795}
1796
1797static void send_heci_uma_message(struct raminfo *info)
1798{
1799 struct uma_reply {
1800 u8 group_id;
1801 u8 command;
1802 u8 reserved;
1803 u8 result;
1804 u8 field2;
1805 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001806 } __packed reply;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001807 struct uma_message {
1808 u8 group_id;
1809 u8 cmd;
1810 u8 reserved;
1811 u8 result;
1812 u32 c2;
1813 u64 heci_uma_addr;
1814 u32 memory_reserved_for_heci_mb;
1815 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001816 } __packed msg = {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001817 0, MKHI_SET_UMA, 0, 0,
1818 0x82,
1819 info->heci_uma_addr, info->memory_reserved_for_heci_mb, 0};
1820 u32 reply_size;
1821
1822 send_heci_message((u8 *) & msg, sizeof(msg), 0, 7);
1823
1824 reply_size = sizeof(reply);
1825 if (recv_heci_message(info, (u32 *) & reply, &reply_size) == -1)
1826 return;
1827
1828 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1829 die("HECI init failed\n");
1830}
1831
1832static void setup_heci_uma(struct raminfo *info)
1833{
1834 u32 reg44;
1835
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001836 reg44 = pci_read_config32(HECIDEV, 0x44); // = 0x80010020
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001837 info->memory_reserved_for_heci_mb = 0;
1838 info->heci_uma_addr = 0;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001839 if (!((reg44 & 0x10000) && !(pci_read_config32(HECIDEV, 0x40) & 0x20)))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001840 return;
1841
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001842 info->heci_bar = pci_read_config32(HECIDEV, 0x10) & 0xFFFFFFF0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001843 info->memory_reserved_for_heci_mb = reg44 & 0x3f;
1844 info->heci_uma_addr =
1845 ((u64)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001846 ((((u64) pci_read_config16(NORTHBRIDGE, D0F0_TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001847 info->memory_reserved_for_heci_mb)) << 20;
1848
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001849 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001850 if (info->memory_reserved_for_heci_mb) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001851 write32(DEFAULT_DMIBAR + 0x14,
1852 read32(DEFAULT_DMIBAR + 0x14) & ~0x80);
1853 write32(DEFAULT_RCBA + 0x14,
1854 read32(DEFAULT_RCBA + 0x14) & ~0x80);
1855 write32(DEFAULT_DMIBAR + 0x20,
1856 read32(DEFAULT_DMIBAR + 0x20) & ~0x80);
1857 write32(DEFAULT_RCBA + 0x20,
1858 read32(DEFAULT_RCBA + 0x20) & ~0x80);
1859 write32(DEFAULT_DMIBAR + 0x2c,
1860 read32(DEFAULT_DMIBAR + 0x2c) & ~0x80);
1861 write32(DEFAULT_RCBA + 0x30,
1862 read32(DEFAULT_RCBA + 0x30) & ~0x80);
1863 write32(DEFAULT_DMIBAR + 0x38,
1864 read32(DEFAULT_DMIBAR + 0x38) & ~0x80);
1865 write32(DEFAULT_RCBA + 0x40,
1866 read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001867
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001868 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
1869 write32(DEFAULT_DMIBAR + 0x38, 0x87000080); // OK
Felix Held04be2dd2018-07-29 04:53:22 +02001870 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
1871 read16(DEFAULT_DMIBAR + 0x3e) & 2)
1872 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001873 }
1874
Felix Held04be2dd2018-07-29 04:53:22 +02001875 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001876
1877 send_heci_uma_message(info);
1878
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001879 pci_write_config32(HECIDEV, 0x10, 0x0);
1880 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001881
1882}
1883
1884static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1885{
1886 int ranks_in_channel;
1887 ranks_in_channel = info->populated_ranks[channel][0][0]
1888 + info->populated_ranks[channel][0][1]
1889 + info->populated_ranks[channel][1][0]
1890 + info->populated_ranks[channel][1][1];
1891
1892 /* empty channel */
1893 if (ranks_in_channel == 0)
1894 return 1;
1895
1896 if (ranks_in_channel != ranks)
1897 return 0;
1898 /* single slot */
1899 if (info->populated_ranks[channel][0][0] !=
1900 info->populated_ranks[channel][1][0])
1901 return 1;
1902 if (info->populated_ranks[channel][0][1] !=
1903 info->populated_ranks[channel][1][1])
1904 return 1;
1905 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1906 return 0;
1907 if (info->density[channel][0] != info->density[channel][1])
1908 return 0;
1909 return 1;
1910}
1911
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001912static void read_4090(struct raminfo *info)
1913{
1914 int i, channel, slot, rank, lane;
1915 for (i = 0; i < 2; i++)
1916 for (slot = 0; slot < NUM_SLOTS; slot++)
1917 for (rank = 0; rank < NUM_RANKS; rank++)
1918 for (lane = 0; lane < 9; lane++)
1919 info->training.
1920 lane_timings[0][i][slot][rank][lane]
1921 = 32;
1922
1923 for (i = 1; i < 4; i++)
1924 for (channel = 0; channel < NUM_CHANNELS; channel++)
1925 for (slot = 0; slot < NUM_SLOTS; slot++)
1926 for (rank = 0; rank < NUM_RANKS; rank++)
1927 for (lane = 0; lane < 9; lane++) {
1928 info->training.
1929 lane_timings[i][channel]
1930 [slot][rank][lane] =
1931 read_500(info, channel,
1932 get_timing_register_addr
1933 (lane, i, slot,
1934 rank), 9)
1935 + (i == 1) * 11; // !!!!
1936 }
1937
1938}
1939
1940static u32 get_etalon2(int flip, u32 addr)
1941{
1942 const u16 invmask[] = {
1943 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1944 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1945 };
1946 u32 ret;
1947 u32 comp4 = addr / 480;
1948 addr %= 480;
1949 u32 comp1 = addr & 0xf;
1950 u32 comp2 = (addr >> 4) & 1;
1951 u32 comp3 = addr >> 5;
1952
1953 if (comp4)
1954 ret = 0x1010101 << (comp4 - 1);
1955 else
1956 ret = 0;
1957 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1958 ret = ~ret;
1959
1960 return ret;
1961}
1962
1963static void disable_cache(void)
1964{
1965 msr_t msr = {.lo = 0, .hi = 0 };
1966
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001967 wrmsr(MTRR_PHYS_BASE(3), msr);
1968 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001969}
1970
1971static void enable_cache(unsigned int base, unsigned int size)
1972{
1973 msr_t msr;
1974 msr.lo = base | MTRR_TYPE_WRPROT;
1975 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001976 wrmsr(MTRR_PHYS_BASE(3), msr);
1977 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001978 & 0xffffffff);
1979 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001980 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001981}
1982
1983static void flush_cache(u32 start, u32 size)
1984{
1985 u32 end;
1986 u32 addr;
1987
1988 end = start + (ALIGN_DOWN(size + 4096, 4096));
1989 for (addr = start; addr < end; addr += 64)
1990 clflush(addr);
1991}
1992
1993static void clear_errors(void)
1994{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001995 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001996}
1997
1998static void write_testing(struct raminfo *info, int totalrank, int flip)
1999{
2000 int nwrites = 0;
2001 /* in 8-byte units. */
2002 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002003 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002004
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002005 base = (u8 *)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002006 for (offset = 0; offset < 9 * 480; offset += 2) {
2007 write32(base + offset * 8, get_etalon2(flip, offset));
2008 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
2009 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
2010 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
2011 nwrites += 4;
2012 if (nwrites >= 320) {
2013 clear_errors();
2014 nwrites = 0;
2015 }
2016 }
2017}
2018
2019static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
2020{
2021 u8 failmask = 0;
2022 int i;
2023 int comp1, comp2, comp3;
2024 u32 failxor[2] = { 0, 0 };
2025
2026 enable_cache((total_rank << 28), 1728 * 5 * 4);
2027
2028 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
2029 for (comp1 = 0; comp1 < 4; comp1++)
2030 for (comp2 = 0; comp2 < 60; comp2++) {
2031 u32 re[4];
2032 u32 curroffset =
2033 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
2034 read128((total_rank << 28) | (curroffset << 3),
2035 (u64 *) re);
2036 failxor[0] |=
2037 get_etalon2(flip, curroffset) ^ re[0];
2038 failxor[1] |=
2039 get_etalon2(flip, curroffset) ^ re[1];
2040 failxor[0] |=
2041 get_etalon2(flip, curroffset | 1) ^ re[2];
2042 failxor[1] |=
2043 get_etalon2(flip, curroffset | 1) ^ re[3];
2044 }
2045 for (i = 0; i < 8; i++)
2046 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2047 failmask |= 1 << i;
2048 }
2049 disable_cache();
2050 flush_cache((total_rank << 28), 1728 * 5 * 4);
2051 return failmask;
2052}
2053
2054const u32 seed1[0x18] = {
2055 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2056 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2057 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2058 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2059 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2060 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2061};
2062
2063static u32 get_seed2(int a, int b)
2064{
2065 const u32 seed2[5] = {
2066 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2067 0x5b6db6db,
2068 };
2069 u32 r;
2070 r = seed2[(a + (a >= 10)) / 5];
2071 return b ? ~r : r;
2072}
2073
2074static int make_shift(int comp2, int comp5, int x)
2075{
2076 const u8 seed3[32] = {
2077 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2078 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2079 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2080 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2081 };
2082
2083 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2084}
2085
2086static u32 get_etalon(int flip, u32 addr)
2087{
2088 u32 mask_byte = 0;
2089 int comp1 = (addr >> 1) & 1;
2090 int comp2 = (addr >> 3) & 0x1f;
2091 int comp3 = (addr >> 8) & 0xf;
2092 int comp4 = (addr >> 12) & 0xf;
2093 int comp5 = (addr >> 16) & 0x1f;
2094 u32 mask_bit = ~(0x10001 << comp3);
2095 u32 part1;
2096 u32 part2;
2097 int byte;
2098
2099 part2 =
2100 ((seed1[comp5] >>
2101 make_shift(comp2, comp5,
2102 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2103 part1 =
2104 ((seed1[comp5] >>
2105 make_shift(comp2, comp5,
2106 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2107
2108 for (byte = 0; byte < 4; byte++)
2109 if ((get_seed2(comp5, comp4) >>
2110 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2111 mask_byte |= 0xff << (8 * byte);
2112
2113 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2114 (comp3 + 16));
2115}
2116
2117static void
2118write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2119 char flip)
2120{
2121 int i;
2122 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002123 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2124 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002125}
2126
2127static u8
2128check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2129 char flip)
2130{
2131 u8 failmask = 0;
2132 u32 failxor[2];
2133 int i;
2134 int comp1, comp2, comp3;
2135
2136 failxor[0] = 0;
2137 failxor[1] = 0;
2138
2139 enable_cache(totalrank << 28, 134217728);
2140 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2141 for (comp1 = 0; comp1 < 16; comp1++)
2142 for (comp2 = 0; comp2 < 64; comp2++) {
2143 u32 addr =
2144 (totalrank << 28) | (region << 25) | (block
2145 << 16)
2146 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2147 2);
2148 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002149 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002150 }
2151 for (i = 0; i < 8; i++)
2152 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2153 failmask |= 1 << i;
2154 }
2155 disable_cache();
2156 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2157 return failmask;
2158}
2159
2160static int check_bounded(unsigned short *vals, u16 bound)
2161{
2162 int i;
2163
2164 for (i = 0; i < 8; i++)
2165 if (vals[i] < bound)
2166 return 0;
2167 return 1;
2168}
2169
2170enum state {
2171 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2172};
2173
2174static int validate_state(enum state *in)
2175{
2176 int i;
2177 for (i = 0; i < 8; i++)
2178 if (in[i] != COMPLETE)
2179 return 0;
2180 return 1;
2181}
2182
2183static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002184do_fsm(enum state *state, u16 *counter,
2185 u8 fail_mask, int margin, int uplimit,
2186 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002187{
2188 int lane;
2189
2190 for (lane = 0; lane < 8; lane++) {
2191 int is_fail = (fail_mask >> lane) & 1;
2192 switch (state[lane]) {
2193 case BEFORE_USABLE:
2194 if (!is_fail) {
2195 counter[lane] = 1;
2196 state[lane] = AT_USABLE;
2197 break;
2198 }
2199 counter[lane] = 0;
2200 state[lane] = BEFORE_USABLE;
2201 break;
2202 case AT_USABLE:
2203 if (!is_fail) {
2204 ++counter[lane];
2205 if (counter[lane] >= margin) {
2206 state[lane] = AT_MARGIN;
2207 res_low[lane] = val - margin + 1;
2208 break;
2209 }
2210 state[lane] = 1;
2211 break;
2212 }
2213 counter[lane] = 0;
2214 state[lane] = BEFORE_USABLE;
2215 break;
2216 case AT_MARGIN:
2217 if (is_fail) {
2218 state[lane] = COMPLETE;
2219 res_high[lane] = val - 1;
2220 } else {
2221 counter[lane]++;
2222 state[lane] = AT_MARGIN;
2223 if (val == uplimit) {
2224 state[lane] = COMPLETE;
2225 res_high[lane] = uplimit;
2226 }
2227 }
2228 break;
2229 case COMPLETE:
2230 break;
2231 }
2232 }
2233}
2234
2235static void
2236train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2237 u8 total_rank, u8 reg_178, int first_run, int niter,
2238 timing_bounds_t * timings)
2239{
2240 int lane;
2241 enum state state[8];
2242 u16 count[8];
2243 u8 lower_usable[8];
2244 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002245 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002246 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002247 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002248
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002249 for (i = 0; i < 8; i++)
2250 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002251
2252 if (!first_run) {
2253 int is_all_ok = 1;
2254 for (lane = 0; lane < 8; lane++)
2255 if (timings[reg_178][channel][slot][rank][lane].
2256 smallest ==
2257 timings[reg_178][channel][slot][rank][lane].
2258 largest) {
2259 timings[reg_178][channel][slot][rank][lane].
2260 smallest = 0;
2261 timings[reg_178][channel][slot][rank][lane].
2262 largest = 0;
2263 is_all_ok = 0;
2264 }
2265 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002266 for (i = 0; i < 8; i++)
2267 state[i] = COMPLETE;
2268 }
2269 }
2270
2271 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2272 u8 failmask = 0;
2273 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2274 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2275 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002276 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002277 do_fsm(state, count, failmask, 5, 47, lower_usable,
2278 upper_usable, reg1b3);
2279 }
2280
2281 if (reg1b3) {
2282 write_1d0(0, 0x1b3, 6, 1);
2283 write_1d0(0, 0x1a3, 6, 1);
2284 for (lane = 0; lane < 8; lane++) {
2285 if (state[lane] == COMPLETE) {
2286 timings[reg_178][channel][slot][rank][lane].
2287 smallest =
2288 lower_usable[lane] +
2289 (info->training.
2290 lane_timings[0][channel][slot][rank][lane]
2291 & 0x3F) - 32;
2292 timings[reg_178][channel][slot][rank][lane].
2293 largest =
2294 upper_usable[lane] +
2295 (info->training.
2296 lane_timings[0][channel][slot][rank][lane]
2297 & 0x3F) - 32;
2298 }
2299 }
2300 }
2301
2302 if (!first_run) {
2303 for (lane = 0; lane < 8; lane++)
2304 if (state[lane] == COMPLETE) {
2305 write_500(info, channel,
2306 timings[reg_178][channel][slot][rank]
2307 [lane].smallest,
2308 get_timing_register_addr(lane, 0,
2309 slot, rank),
2310 9, 1);
2311 write_500(info, channel,
2312 timings[reg_178][channel][slot][rank]
2313 [lane].smallest +
2314 info->training.
2315 lane_timings[1][channel][slot][rank]
2316 [lane]
2317 -
2318 info->training.
2319 lane_timings[0][channel][slot][rank]
2320 [lane], get_timing_register_addr(lane,
2321 1,
2322 slot,
2323 rank),
2324 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002325 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002326 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002327 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002328
2329 do {
2330 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002331 for (i = 0; i < niter; i++) {
2332 if (failmask == 0xFF)
2333 break;
2334 failmask |=
2335 check_testing_type2(info, total_rank, 2, i,
2336 0);
2337 failmask |=
2338 check_testing_type2(info, total_rank, 3, i,
2339 1);
2340 }
Felix Held04be2dd2018-07-29 04:53:22 +02002341 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002342 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002343 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002344 if ((1 << lane) & failmask) {
2345 if (timings[reg_178][channel]
2346 [slot][rank][lane].
2347 largest <=
2348 timings[reg_178][channel]
2349 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002350 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002351 [lane] = -1;
2352 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002353 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002354 [lane] = 0;
2355 timings[reg_178]
2356 [channel][slot]
2357 [rank][lane].
2358 smallest++;
2359 write_500(info, channel,
2360 timings
2361 [reg_178]
2362 [channel]
2363 [slot][rank]
2364 [lane].
2365 smallest,
2366 get_timing_register_addr
2367 (lane, 0,
2368 slot, rank),
2369 9, 1);
2370 write_500(info, channel,
2371 timings
2372 [reg_178]
2373 [channel]
2374 [slot][rank]
2375 [lane].
2376 smallest +
2377 info->
2378 training.
2379 lane_timings
2380 [1][channel]
2381 [slot][rank]
2382 [lane]
2383 -
2384 info->
2385 training.
2386 lane_timings
2387 [0][channel]
2388 [slot][rank]
2389 [lane],
2390 get_timing_register_addr
2391 (lane, 1,
2392 slot, rank),
2393 9, 1);
2394 }
2395 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002396 num_successfully_checked[lane]
2397 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002398 }
2399 }
Felix Held04be2dd2018-07-29 04:53:22 +02002400 while (!check_bounded(num_successfully_checked, 2))
2401 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002402
2403 for (lane = 0; lane < 8; lane++)
2404 if (state[lane] == COMPLETE) {
2405 write_500(info, channel,
2406 timings[reg_178][channel][slot][rank]
2407 [lane].largest,
2408 get_timing_register_addr(lane, 0,
2409 slot, rank),
2410 9, 1);
2411 write_500(info, channel,
2412 timings[reg_178][channel][slot][rank]
2413 [lane].largest +
2414 info->training.
2415 lane_timings[1][channel][slot][rank]
2416 [lane]
2417 -
2418 info->training.
2419 lane_timings[0][channel][slot][rank]
2420 [lane], get_timing_register_addr(lane,
2421 1,
2422 slot,
2423 rank),
2424 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002425 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002426 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002427 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002428
2429 do {
2430 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002431 for (i = 0; i < niter; i++) {
2432 if (failmask == 0xFF)
2433 break;
2434 failmask |=
2435 check_testing_type2(info, total_rank, 2, i,
2436 0);
2437 failmask |=
2438 check_testing_type2(info, total_rank, 3, i,
2439 1);
2440 }
2441
Felix Held04be2dd2018-07-29 04:53:22 +02002442 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002443 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002444 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002445 if ((1 << lane) & failmask) {
2446 if (timings[reg_178][channel]
2447 [slot][rank][lane].
2448 largest <=
2449 timings[reg_178][channel]
2450 [slot][rank][lane].
2451 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002452 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002453 [lane] = -1;
2454 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002455 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002456 [lane] = 0;
2457 timings[reg_178]
2458 [channel][slot]
2459 [rank][lane].
2460 largest--;
2461 write_500(info, channel,
2462 timings
2463 [reg_178]
2464 [channel]
2465 [slot][rank]
2466 [lane].
2467 largest,
2468 get_timing_register_addr
2469 (lane, 0,
2470 slot, rank),
2471 9, 1);
2472 write_500(info, channel,
2473 timings
2474 [reg_178]
2475 [channel]
2476 [slot][rank]
2477 [lane].
2478 largest +
2479 info->
2480 training.
2481 lane_timings
2482 [1][channel]
2483 [slot][rank]
2484 [lane]
2485 -
2486 info->
2487 training.
2488 lane_timings
2489 [0][channel]
2490 [slot][rank]
2491 [lane],
2492 get_timing_register_addr
2493 (lane, 1,
2494 slot, rank),
2495 9, 1);
2496 }
2497 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002498 num_successfully_checked[lane]
2499 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002500 }
2501 }
2502 }
Felix Held04be2dd2018-07-29 04:53:22 +02002503 while (!check_bounded(num_successfully_checked, 3))
2504 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002505
2506 for (lane = 0; lane < 8; lane++) {
2507 write_500(info, channel,
2508 info->training.
2509 lane_timings[0][channel][slot][rank][lane],
2510 get_timing_register_addr(lane, 0, slot, rank),
2511 9, 1);
2512 write_500(info, channel,
2513 info->training.
2514 lane_timings[1][channel][slot][rank][lane],
2515 get_timing_register_addr(lane, 1, slot, rank),
2516 9, 1);
2517 if (timings[reg_178][channel][slot][rank][lane].
2518 largest <=
2519 timings[reg_178][channel][slot][rank][lane].
2520 smallest) {
2521 timings[reg_178][channel][slot][rank][lane].
2522 largest = 0;
2523 timings[reg_178][channel][slot][rank][lane].
2524 smallest = 0;
2525 }
2526 }
2527 }
2528}
2529
2530static void set_10b(struct raminfo *info, u8 val)
2531{
2532 int channel;
2533 int slot, rank;
2534 int lane;
2535
2536 if (read_1d0(0x10b, 6) == val)
2537 return;
2538
2539 write_1d0(val, 0x10b, 6, 1);
2540
2541 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2542 u16 reg_500;
2543 reg_500 = read_500(info, channel,
2544 get_timing_register_addr(lane, 0, slot,
2545 rank), 9);
2546 if (val == 1) {
2547 if (lut16[info->clock_speed_index] <= reg_500)
2548 reg_500 -= lut16[info->clock_speed_index];
2549 else
2550 reg_500 = 0;
2551 } else {
2552 reg_500 += lut16[info->clock_speed_index];
2553 }
2554 write_500(info, channel, reg_500,
2555 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2556 }
2557}
2558
2559static void set_ecc(int onoff)
2560{
2561 int channel;
2562 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2563 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002564 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002565 if (onoff)
2566 t |= 1;
2567 else
2568 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002569 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002570 }
2571}
2572
2573static void set_178(u8 val)
2574{
2575 if (val >= 31)
2576 val = val - 31;
2577 else
2578 val = 63 - val;
2579
2580 write_1d0(2 * val, 0x178, 7, 1);
2581}
2582
2583static void
2584write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2585 int type)
2586{
2587 int lane;
2588
2589 for (lane = 0; lane < 8; lane++)
2590 write_500(info, channel,
2591 info->training.
2592 lane_timings[type][channel][slot][rank][lane],
2593 get_timing_register_addr(lane, type, slot, rank), 9,
2594 0);
2595}
2596
2597static void
2598try_timing_offsets(struct raminfo *info, int channel,
2599 int slot, int rank, int totalrank)
2600{
2601 u16 count[8];
2602 enum state state[8];
2603 u8 lower_usable[8], upper_usable[8];
2604 int lane;
2605 int i;
2606 int flip = 1;
2607 int timing_offset;
2608
2609 for (i = 0; i < 8; i++)
2610 state[i] = BEFORE_USABLE;
2611
2612 memset(count, 0, sizeof(count));
2613
2614 for (lane = 0; lane < 8; lane++)
2615 write_500(info, channel,
2616 info->training.
2617 lane_timings[2][channel][slot][rank][lane] + 32,
2618 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2619
2620 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2621 timing_offset++) {
2622 u8 failmask;
2623 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2624 failmask = 0;
2625 for (i = 0; i < 2 && failmask != 0xff; i++) {
2626 flip = !flip;
2627 write_testing(info, totalrank, flip);
2628 failmask |= check_testing(info, totalrank, flip);
2629 }
2630 do_fsm(state, count, failmask, 10, 63, lower_usable,
2631 upper_usable, timing_offset);
2632 }
2633 write_1d0(0, 0x1bb, 6, 1);
2634 dump_timings(info);
2635 if (!validate_state(state))
2636 die("Couldn't discover DRAM timings (1)\n");
2637
2638 for (lane = 0; lane < 8; lane++) {
2639 u8 bias = 0;
2640
2641 if (info->silicon_revision) {
2642 int usable_length;
2643
2644 usable_length = upper_usable[lane] - lower_usable[lane];
2645 if (usable_length >= 20) {
2646 bias = usable_length / 2 - 10;
2647 if (bias >= 2)
2648 bias = 2;
2649 }
2650 }
2651 write_500(info, channel,
2652 info->training.
2653 lane_timings[2][channel][slot][rank][lane] +
2654 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2655 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2656 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2657 info->training.lane_timings[2][channel][slot][rank][lane] +
2658 lower_usable[lane];
2659 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2660 info->training.lane_timings[2][channel][slot][rank][lane] +
2661 upper_usable[lane];
2662 info->training.timing2_offset[channel][slot][rank][lane] =
2663 info->training.lane_timings[2][channel][slot][rank][lane];
2664 }
2665}
2666
2667static u8
2668choose_training(struct raminfo *info, int channel, int slot, int rank,
2669 int lane, timing_bounds_t * timings, u8 center_178)
2670{
2671 u16 central_weight;
2672 u16 side_weight;
2673 unsigned int sum = 0, count = 0;
2674 u8 span;
2675 u8 lower_margin, upper_margin;
2676 u8 reg_178;
2677 u8 result;
2678
2679 span = 12;
2680 central_weight = 20;
2681 side_weight = 20;
2682 if (info->silicon_revision == 1 && channel == 1) {
2683 central_weight = 5;
2684 side_weight = 20;
2685 if ((info->
2686 populated_ranks_mask[1] ^ (info->
2687 populated_ranks_mask[1] >> 2)) &
2688 1)
2689 span = 18;
2690 }
2691 if ((info->populated_ranks_mask[0] & 5) == 5) {
2692 central_weight = 20;
2693 side_weight = 20;
2694 }
2695 if (info->clock_speed_index >= 2
2696 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2697 if (info->silicon_revision == 1) {
2698 switch (channel) {
2699 case 0:
2700 if (lane == 1) {
2701 central_weight = 10;
2702 side_weight = 20;
2703 }
2704 break;
2705 case 1:
2706 if (lane == 6) {
2707 side_weight = 5;
2708 central_weight = 20;
2709 }
2710 break;
2711 }
2712 }
2713 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2714 side_weight = 5;
2715 central_weight = 20;
2716 }
2717 }
2718 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2719 reg_178 += span) {
2720 u8 smallest;
2721 u8 largest;
2722 largest = timings[reg_178][channel][slot][rank][lane].largest;
2723 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2724 if (largest - smallest + 1 >= 5) {
2725 unsigned int weight;
2726 if (reg_178 == center_178)
2727 weight = central_weight;
2728 else
2729 weight = side_weight;
2730 sum += weight * (largest + smallest);
2731 count += weight;
2732 }
2733 }
2734 dump_timings(info);
2735 if (count == 0)
2736 die("Couldn't discover DRAM timings (2)\n");
2737 result = sum / (2 * count);
2738 lower_margin =
2739 result - timings[center_178][channel][slot][rank][lane].smallest;
2740 upper_margin =
2741 timings[center_178][channel][slot][rank][lane].largest - result;
2742 if (upper_margin < 10 && lower_margin > 10)
2743 result -= min(lower_margin - 10, 10 - upper_margin);
2744 if (upper_margin > 10 && lower_margin < 10)
2745 result += min(upper_margin - 10, 10 - lower_margin);
2746 return result;
2747}
2748
2749#define STANDARD_MIN_MARGIN 5
2750
2751static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2752{
2753 u16 margin[64];
2754 int lane, rank, slot, channel;
2755 u8 reg178;
2756 int count = 0, sum = 0;
2757
2758 for (reg178 = reg178_min[info->clock_speed_index];
2759 reg178 < reg178_max[info->clock_speed_index];
2760 reg178 += reg178_step[info->clock_speed_index]) {
2761 margin[reg178] = -1;
2762 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2763 int curmargin =
2764 timings[reg178][channel][slot][rank][lane].largest -
2765 timings[reg178][channel][slot][rank][lane].
2766 smallest + 1;
2767 if (curmargin < margin[reg178])
2768 margin[reg178] = curmargin;
2769 }
2770 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2771 u16 weight;
2772 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2773 sum += weight * reg178;
2774 count += weight;
2775 }
2776 }
2777 dump_timings(info);
2778 if (count == 0)
2779 die("Couldn't discover DRAM timings (3)\n");
2780
2781 u8 threshold;
2782
2783 for (threshold = 30; threshold >= 5; threshold--) {
2784 int usable_length = 0;
2785 int smallest_fount = 0;
2786 for (reg178 = reg178_min[info->clock_speed_index];
2787 reg178 < reg178_max[info->clock_speed_index];
2788 reg178 += reg178_step[info->clock_speed_index])
2789 if (margin[reg178] >= threshold) {
2790 usable_length +=
2791 reg178_step[info->clock_speed_index];
2792 info->training.reg178_largest =
2793 reg178 -
2794 2 * reg178_step[info->clock_speed_index];
2795
2796 if (!smallest_fount) {
2797 smallest_fount = 1;
2798 info->training.reg178_smallest =
2799 reg178 +
2800 reg178_step[info->
2801 clock_speed_index];
2802 }
2803 }
2804 if (usable_length >= 0x21)
2805 break;
2806 }
2807
2808 return sum / count;
2809}
2810
2811static int check_cached_sanity(struct raminfo *info)
2812{
2813 int lane;
2814 int slot, rank;
2815 int channel;
2816
2817 if (!info->cached_training)
2818 return 0;
2819
2820 for (channel = 0; channel < NUM_CHANNELS; channel++)
2821 for (slot = 0; slot < NUM_SLOTS; slot++)
2822 for (rank = 0; rank < NUM_RANKS; rank++)
2823 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2824 u16 cached_value, estimation_value;
2825 cached_value =
2826 info->cached_training->
2827 lane_timings[1][channel][slot][rank]
2828 [lane];
2829 if (cached_value >= 0x18
2830 && cached_value <= 0x1E7) {
2831 estimation_value =
2832 info->training.
2833 lane_timings[1][channel]
2834 [slot][rank][lane];
2835 if (estimation_value <
2836 cached_value - 24)
2837 return 0;
2838 if (estimation_value >
2839 cached_value + 24)
2840 return 0;
2841 }
2842 }
2843 return 1;
2844}
2845
2846static int try_cached_training(struct raminfo *info)
2847{
2848 u8 saved_243[2];
2849 u8 tm;
2850
2851 int channel, slot, rank, lane;
2852 int flip = 1;
2853 int i, j;
2854
2855 if (!check_cached_sanity(info))
2856 return 0;
2857
2858 info->training.reg178_center = info->cached_training->reg178_center;
2859 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2860 info->training.reg178_largest = info->cached_training->reg178_largest;
2861 memcpy(&info->training.timing_bounds,
2862 &info->cached_training->timing_bounds,
2863 sizeof(info->training.timing_bounds));
2864 memcpy(&info->training.timing_offset,
2865 &info->cached_training->timing_offset,
2866 sizeof(info->training.timing_offset));
2867
2868 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002869 saved_243[0] = MCHBAR8(0x243);
2870 saved_243[1] = MCHBAR8(0x643);
2871 MCHBAR8(0x243) = saved_243[0] | 2;
2872 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002873 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002874 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002875 if (read_1d0(0x10b, 6) & 1)
2876 set_10b(info, 0);
2877 for (tm = 0; tm < 2; tm++) {
2878 int totalrank;
2879
2880 set_178(tm ? info->cached_training->reg178_largest : info->
2881 cached_training->reg178_smallest);
2882
2883 totalrank = 0;
2884 /* Check timing ranges. With i == 0 we check smallest one and with
2885 i == 1 the largest bound. With j == 0 we check that on the bound
2886 it still works whereas with j == 1 we check that just outside of
2887 bound we fail.
2888 */
2889 FOR_POPULATED_RANKS_BACKWARDS {
2890 for (i = 0; i < 2; i++) {
2891 for (lane = 0; lane < 8; lane++) {
2892 write_500(info, channel,
2893 info->cached_training->
2894 timing2_bounds[channel][slot]
2895 [rank][lane][i],
2896 get_timing_register_addr(lane,
2897 3,
2898 slot,
2899 rank),
2900 9, 1);
2901
2902 if (!i)
2903 write_500(info, channel,
2904 info->
2905 cached_training->
2906 timing2_offset
2907 [channel][slot][rank]
2908 [lane],
2909 get_timing_register_addr
2910 (lane, 2, slot, rank),
2911 9, 1);
2912 write_500(info, channel,
2913 i ? info->cached_training->
2914 timing_bounds[tm][channel]
2915 [slot][rank][lane].
2916 largest : info->
2917 cached_training->
2918 timing_bounds[tm][channel]
2919 [slot][rank][lane].smallest,
2920 get_timing_register_addr(lane,
2921 0,
2922 slot,
2923 rank),
2924 9, 1);
2925 write_500(info, channel,
2926 info->cached_training->
2927 timing_offset[channel][slot]
2928 [rank][lane] +
2929 (i ? info->cached_training->
2930 timing_bounds[tm][channel]
2931 [slot][rank][lane].
2932 largest : info->
2933 cached_training->
2934 timing_bounds[tm][channel]
2935 [slot][rank][lane].
2936 smallest) - 64,
2937 get_timing_register_addr(lane,
2938 1,
2939 slot,
2940 rank),
2941 9, 1);
2942 }
2943 for (j = 0; j < 2; j++) {
2944 u8 failmask;
2945 u8 expected_failmask;
2946 char reg1b3;
2947
2948 reg1b3 = (j == 1) + 4;
2949 reg1b3 =
2950 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2951 write_1d0(reg1b3, 0x1bb, 6, 1);
2952 write_1d0(reg1b3, 0x1b3, 6, 1);
2953 write_1d0(reg1b3, 0x1a3, 6, 1);
2954
2955 flip = !flip;
2956 write_testing(info, totalrank, flip);
2957 failmask =
2958 check_testing(info, totalrank,
2959 flip);
2960 expected_failmask =
2961 j == 0 ? 0x00 : 0xff;
2962 if (failmask != expected_failmask)
2963 goto fail;
2964 }
2965 }
2966 totalrank++;
2967 }
2968 }
2969
2970 set_178(info->cached_training->reg178_center);
2971 if (info->use_ecc)
2972 set_ecc(1);
2973 write_training_data(info);
2974 write_1d0(0, 322, 3, 1);
2975 info->training = *info->cached_training;
2976
2977 write_1d0(0, 0x1bb, 6, 1);
2978 write_1d0(0, 0x1b3, 6, 1);
2979 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002980 MCHBAR8(0x243) = saved_243[0];
2981 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002982
2983 return 1;
2984
2985fail:
2986 FOR_POPULATED_RANKS {
2987 write_500_timings_type(info, channel, slot, rank, 1);
2988 write_500_timings_type(info, channel, slot, rank, 2);
2989 write_500_timings_type(info, channel, slot, rank, 3);
2990 }
2991
2992 write_1d0(0, 0x1bb, 6, 1);
2993 write_1d0(0, 0x1b3, 6, 1);
2994 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002995 MCHBAR8(0x243) = saved_243[0];
2996 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002997
2998 return 0;
2999}
3000
3001static void do_ram_training(struct raminfo *info)
3002{
3003 u8 saved_243[2];
3004 int totalrank = 0;
3005 u8 reg_178;
3006 int niter;
3007
Matthias Gazzaridfa51252018-05-19 00:44:20 +02003008 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003009 int lane, rank, slot, channel;
3010 u8 reg178_center;
3011
3012 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003013 saved_243[0] = MCHBAR8(0x243);
3014 saved_243[1] = MCHBAR8(0x643);
3015 MCHBAR8(0x243) = saved_243[0] | 2;
3016 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003017 switch (info->clock_speed_index) {
3018 case 0:
3019 niter = 5;
3020 break;
3021 case 1:
3022 niter = 10;
3023 break;
3024 default:
3025 niter = 19;
3026 break;
3027 }
3028 set_ecc(0);
3029
3030 FOR_POPULATED_RANKS_BACKWARDS {
3031 int i;
3032
3033 write_500_timings_type(info, channel, slot, rank, 0);
3034
3035 write_testing(info, totalrank, 0);
3036 for (i = 0; i < niter; i++) {
3037 write_testing_type2(info, totalrank, 2, i, 0);
3038 write_testing_type2(info, totalrank, 3, i, 1);
3039 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003040 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003041 totalrank++;
3042 }
3043
3044 if (reg178_min[info->clock_speed_index] <
3045 reg178_max[info->clock_speed_index])
3046 memset(timings[reg178_min[info->clock_speed_index]], 0,
3047 sizeof(timings[0]) *
3048 (reg178_max[info->clock_speed_index] -
3049 reg178_min[info->clock_speed_index]));
3050 for (reg_178 = reg178_min[info->clock_speed_index];
3051 reg_178 < reg178_max[info->clock_speed_index];
3052 reg_178 += reg178_step[info->clock_speed_index]) {
3053 totalrank = 0;
3054 set_178(reg_178);
3055 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3056 for (slot = 0; slot < NUM_SLOTS; slot++)
3057 for (rank = 0; rank < NUM_RANKS; rank++) {
3058 memset(&timings[reg_178][channel][slot]
3059 [rank][0].smallest, 0, 16);
3060 if (info->
3061 populated_ranks[channel][slot]
3062 [rank]) {
3063 train_ram_at_178(info, channel,
3064 slot, rank,
3065 totalrank,
3066 reg_178, 1,
3067 niter,
3068 timings);
3069 totalrank++;
3070 }
3071 }
3072 }
3073
3074 reg178_center = choose_reg178(info, timings);
3075
3076 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3077 info->training.timing_bounds[0][channel][slot][rank][lane].
3078 smallest =
3079 timings[info->training.
3080 reg178_smallest][channel][slot][rank][lane].
3081 smallest;
3082 info->training.timing_bounds[0][channel][slot][rank][lane].
3083 largest =
3084 timings[info->training.
3085 reg178_smallest][channel][slot][rank][lane].largest;
3086 info->training.timing_bounds[1][channel][slot][rank][lane].
3087 smallest =
3088 timings[info->training.
3089 reg178_largest][channel][slot][rank][lane].smallest;
3090 info->training.timing_bounds[1][channel][slot][rank][lane].
3091 largest =
3092 timings[info->training.
3093 reg178_largest][channel][slot][rank][lane].largest;
3094 info->training.timing_offset[channel][slot][rank][lane] =
3095 info->training.lane_timings[1][channel][slot][rank][lane]
3096 -
3097 info->training.lane_timings[0][channel][slot][rank][lane] +
3098 64;
3099 }
3100
3101 if (info->silicon_revision == 1
3102 && (info->
3103 populated_ranks_mask[1] ^ (info->
3104 populated_ranks_mask[1] >> 2)) & 1) {
3105 int ranks_after_channel1;
3106
3107 totalrank = 0;
3108 for (reg_178 = reg178_center - 18;
3109 reg_178 <= reg178_center + 18; reg_178 += 18) {
3110 totalrank = 0;
3111 set_178(reg_178);
3112 for (slot = 0; slot < NUM_SLOTS; slot++)
3113 for (rank = 0; rank < NUM_RANKS; rank++) {
3114 if (info->
3115 populated_ranks[1][slot][rank]) {
3116 train_ram_at_178(info, 1, slot,
3117 rank,
3118 totalrank,
3119 reg_178, 0,
3120 niter,
3121 timings);
3122 totalrank++;
3123 }
3124 }
3125 }
3126 ranks_after_channel1 = totalrank;
3127
3128 for (reg_178 = reg178_center - 12;
3129 reg_178 <= reg178_center + 12; reg_178 += 12) {
3130 totalrank = ranks_after_channel1;
3131 set_178(reg_178);
3132 for (slot = 0; slot < NUM_SLOTS; slot++)
3133 for (rank = 0; rank < NUM_RANKS; rank++)
3134 if (info->
3135 populated_ranks[0][slot][rank]) {
3136 train_ram_at_178(info, 0, slot,
3137 rank,
3138 totalrank,
3139 reg_178, 0,
3140 niter,
3141 timings);
3142 totalrank++;
3143 }
3144
3145 }
3146 } else {
3147 for (reg_178 = reg178_center - 12;
3148 reg_178 <= reg178_center + 12; reg_178 += 12) {
3149 totalrank = 0;
3150 set_178(reg_178);
3151 FOR_POPULATED_RANKS_BACKWARDS {
3152 train_ram_at_178(info, channel, slot, rank,
3153 totalrank, reg_178, 0, niter,
3154 timings);
3155 totalrank++;
3156 }
3157 }
3158 }
3159
3160 set_178(reg178_center);
3161 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3162 u16 tm0;
3163
3164 tm0 =
3165 choose_training(info, channel, slot, rank, lane, timings,
3166 reg178_center);
3167 write_500(info, channel, tm0,
3168 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3169 write_500(info, channel,
3170 tm0 +
3171 info->training.
3172 lane_timings[1][channel][slot][rank][lane] -
3173 info->training.
3174 lane_timings[0][channel][slot][rank][lane],
3175 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3176 }
3177
3178 totalrank = 0;
3179 FOR_POPULATED_RANKS_BACKWARDS {
3180 try_timing_offsets(info, channel, slot, rank, totalrank);
3181 totalrank++;
3182 }
Felix Held04be2dd2018-07-29 04:53:22 +02003183 MCHBAR8(0x243) = saved_243[0];
3184 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003185 write_1d0(0, 0x142, 3, 1);
3186 info->training.reg178_center = reg178_center;
3187}
3188
3189static void ram_training(struct raminfo *info)
3190{
3191 u16 saved_fc4;
3192
Felix Held04be2dd2018-07-29 04:53:22 +02003193 saved_fc4 = MCHBAR16(0xfc4);
3194 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003195
3196 if (info->revision >= 8)
3197 read_4090(info);
3198
3199 if (!try_cached_training(info))
3200 do_ram_training(info);
3201 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3202 && info->clock_speed_index < 2)
3203 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003204 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003205}
3206
3207static unsigned gcd(unsigned a, unsigned b)
3208{
3209 unsigned t;
3210 if (a > b) {
3211 t = a;
3212 a = b;
3213 b = t;
3214 }
3215 /* invariant a < b. */
3216 while (a) {
3217 t = b % a;
3218 b = a;
3219 a = t;
3220 }
3221 return b;
3222}
3223
3224static inline int div_roundup(int a, int b)
3225{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003226 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003227}
3228
3229static unsigned lcm(unsigned a, unsigned b)
3230{
3231 return (a * b) / gcd(a, b);
3232}
3233
3234struct stru1 {
3235 u8 freqs_reversed;
3236 u8 freq_diff_reduced;
3237 u8 freq_min_reduced;
3238 u8 divisor_f4_to_fmax;
3239 u8 divisor_f3_to_fmax;
3240 u8 freq4_to_max_remainder;
3241 u8 freq3_to_2_remainder;
3242 u8 freq3_to_2_remaindera;
3243 u8 freq4_to_2_remainder;
3244 int divisor_f3_to_f1, divisor_f4_to_f2;
3245 int common_time_unit_ps;
3246 int freq_max_reduced;
3247};
3248
3249static void
3250compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3251 int num_cycles_2, int num_cycles_1, int round_it,
3252 int add_freqs, struct stru1 *result)
3253{
3254 int g;
3255 int common_time_unit_ps;
3256 int freq1_reduced, freq2_reduced;
3257 int freq_min_reduced;
3258 int freq_max_reduced;
3259 int freq3, freq4;
3260
3261 g = gcd(freq1, freq2);
3262 freq1_reduced = freq1 / g;
3263 freq2_reduced = freq2 / g;
3264 freq_min_reduced = min(freq1_reduced, freq2_reduced);
3265 freq_max_reduced = max(freq1_reduced, freq2_reduced);
3266
3267 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3268 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3269 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3270 if (add_freqs) {
3271 freq3 += freq2_reduced;
3272 freq4 += freq1_reduced;
3273 }
3274
3275 if (round_it) {
3276 result->freq3_to_2_remainder = 0;
3277 result->freq3_to_2_remaindera = 0;
3278 result->freq4_to_max_remainder = 0;
3279 result->divisor_f4_to_f2 = 0;
3280 result->divisor_f3_to_f1 = 0;
3281 } else {
3282 if (freq2_reduced < freq1_reduced) {
3283 result->freq3_to_2_remainder =
3284 result->freq3_to_2_remaindera =
3285 freq3 % freq1_reduced - freq1_reduced + 1;
3286 result->freq4_to_max_remainder =
3287 -(freq4 % freq1_reduced);
3288 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3289 result->divisor_f4_to_f2 =
3290 (freq4 -
3291 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3292 result->freq4_to_2_remainder =
3293 -(char)((freq1_reduced - freq2_reduced) +
3294 ((u8) freq4 -
3295 (freq1_reduced -
3296 freq2_reduced)) % (u8) freq2_reduced);
3297 } else {
3298 if (freq2_reduced > freq1_reduced) {
3299 result->freq4_to_max_remainder =
3300 (freq4 % freq2_reduced) - freq2_reduced + 1;
3301 result->freq4_to_2_remainder =
3302 freq4 % freq_max_reduced -
3303 freq_max_reduced + 1;
3304 } else {
3305 result->freq4_to_max_remainder =
3306 -(freq4 % freq2_reduced);
3307 result->freq4_to_2_remainder =
3308 -(char)(freq4 % freq_max_reduced);
3309 }
3310 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3311 result->divisor_f3_to_f1 =
3312 (freq3 -
3313 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3314 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3315 result->freq3_to_2_remaindera =
3316 -(char)((freq_max_reduced - freq_min_reduced) +
3317 (freq3 -
3318 (freq_max_reduced -
3319 freq_min_reduced)) % freq1_reduced);
3320 }
3321 }
3322 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3323 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3324 if (round_it) {
3325 if (freq2_reduced > freq1_reduced) {
3326 if (freq3 % freq_max_reduced)
3327 result->divisor_f3_to_fmax++;
3328 }
3329 if (freq2_reduced < freq1_reduced) {
3330 if (freq4 % freq_max_reduced)
3331 result->divisor_f4_to_fmax++;
3332 }
3333 }
3334 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3335 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3336 result->freq_min_reduced = freq_min_reduced;
3337 result->common_time_unit_ps = common_time_unit_ps;
3338 result->freq_max_reduced = freq_max_reduced;
3339}
3340
3341static void
3342set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3343 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3344 int num_cycles_4, int reverse)
3345{
3346 struct stru1 vv;
3347 char multiplier;
3348
3349 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3350 0, 1, &vv);
3351
3352 multiplier =
3353 div_roundup(max
3354 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3355 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3356 div_roundup(num_cycles_1,
3357 vv.common_time_unit_ps) +
3358 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3359 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3360
3361 u32 y =
3362 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3363 vv.freq_max_reduced * multiplier)
3364 | (vv.
3365 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3366 multiplier) << 16) | ((u8) (vv.
3367 freq_min_reduced
3368 *
3369 multiplier)
3370 << 24);
3371 u32 x =
3372 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3373 divisor_f3_to_f1
3374 << 16)
3375 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3376 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003377 MCHBAR32(reg) = y;
3378 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003379 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003380 MCHBAR32(reg + 4) = y;
3381 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003382 }
3383}
3384
3385static void
3386set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3387 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3388 int num_cycles_4)
3389{
3390 struct stru1 ratios1;
3391 struct stru1 ratios2;
3392
3393 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3394 0, 1, &ratios2);
3395 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3396 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003397 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003398 ratios1.freq4_to_max_remainder | (ratios2.
3399 freq4_to_max_remainder
3400 << 8)
3401 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3402 divisor_f4_to_fmax
3403 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003404 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3405 (ratios2.freq4_to_max_remainder << 8) |
3406 (ratios1.divisor_f4_to_fmax << 16) |
3407 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003408}
3409
3410static void
3411set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3412 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3413{
3414 struct stru1 ratios;
3415
3416 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3417 round_it, add_freqs, &ratios);
3418 switch (mode) {
3419 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003420 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3421 (ratios.freqs_reversed << 8);
3422 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3423 (ratios.freq4_to_max_remainder << 8) |
3424 (ratios.divisor_f3_to_fmax << 16) |
3425 (ratios.divisor_f4_to_fmax << 20) |
3426 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003427 break;
3428
3429 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003430 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3431 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003432 break;
3433
3434 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003435 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3436 (ratios.freq4_to_max_remainder << 8) |
3437 (ratios.divisor_f3_to_fmax << 16) |
3438 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003439 break;
3440
3441 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003442 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3443 (ratios.divisor_f4_to_fmax << 8) |
3444 (ratios.freqs_reversed << 12) |
3445 (ratios.freq_min_reduced << 16) |
3446 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003447 break;
3448 }
3449}
3450
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003451static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003452{
3453 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3454 0, 1);
3455 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3456 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3457 1);
3458 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3459 frequency_11(info), 1231, 1524, 0, 1);
3460 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3461 frequency_11(info) / 2, 1278, 2008, 0, 1);
3462 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3463 1167, 1539, 0, 1);
3464 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3465 frequency_11(info) / 2, 1403, 1318, 0, 1);
3466 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3467 1);
3468 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3469 1);
3470 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3471 1, 1);
3472 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3473 1);
3474 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3475 frequency_11(info) / 2, 4000, 0, 0, 0);
3476 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3477 frequency_11(info) / 2, 4000, 4000, 0, 0);
3478
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003479 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003480 printk(RAM_SPEW, "[6dc] <= %x\n",
3481 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003482 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003483 } else
3484 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3485 info->delay46_ps[0], 0,
3486 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003487 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3488 frequency_11(info), 2500, 0, 0, 0);
3489 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3490 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003491 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003492 printk(RAM_SPEW, "[6e8] <= %x\n",
3493 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003494 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003495 } else
3496 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3497 info->delay46_ps[1], 0,
3498 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003499 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3500 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3501 470, 0);
3502 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3503 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3504 454, 459, 0);
3505 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3506 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3507 2588, 0);
3508 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3509 2405, 0);
3510 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3511 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3512 480, 0);
3513 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003514 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3515 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003516}
3517
3518static u16 get_max_timing(struct raminfo *info, int channel)
3519{
3520 int slot, rank, lane;
3521 u16 ret = 0;
3522
Felix Held04be2dd2018-07-29 04:53:22 +02003523 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003524 return 384;
3525
3526 if (info->revision < 8)
3527 return 256;
3528
3529 for (slot = 0; slot < NUM_SLOTS; slot++)
3530 for (rank = 0; rank < NUM_RANKS; rank++)
3531 if (info->populated_ranks[channel][slot][rank])
3532 for (lane = 0; lane < 8 + info->use_ecc; lane++)
3533 ret = max(ret, read_500(info, channel,
3534 get_timing_register_addr
3535 (lane, 0, slot,
3536 rank), 9));
3537 return ret;
3538}
3539
3540static void set_274265(struct raminfo *info)
3541{
3542 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3543 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3544 int delay_e_over_cycle_ps;
3545 int cycletime_ps;
3546 int channel;
3547
3548 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003549 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003550 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3551 cycletime_ps =
3552 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3553 delay_d_ps =
3554 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3555 - info->some_delay_3_ps_rounded + 200;
3556 if (!
3557 ((info->silicon_revision == 0
3558 || info->silicon_revision == 1)
3559 && (info->revision >= 8)))
3560 delay_d_ps += halfcycle_ps(info) * 2;
3561 delay_d_ps +=
3562 halfcycle_ps(info) * (!info->revision_flag_1 +
3563 info->some_delay_2_halfcycles_ceil +
3564 2 * info->some_delay_1_cycle_floor +
3565 info->clock_speed_index +
3566 2 * info->cas_latency - 7 + 11);
3567 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3568
Felix Held04be2dd2018-07-29 04:53:22 +02003569 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3570 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3571 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003572 delay_d_ps += 650;
3573 delay_c_ps = delay_d_ps + 1800;
3574 if (delay_c_ps <= delay_a_ps)
3575 delay_e_ps = 0;
3576 else
3577 delay_e_ps =
3578 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3579 cycletime_ps);
3580
3581 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3582 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3583 delay_f_cycles =
3584 div_roundup(2500 - delay_e_over_cycle_ps,
3585 2 * halfcycle_ps(info));
3586 if (delay_f_cycles > delay_e_cycles) {
3587 info->delay46_ps[channel] = delay_e_ps;
3588 delay_e_cycles = 0;
3589 } else {
3590 info->delay46_ps[channel] =
3591 delay_e_over_cycle_ps +
3592 2 * halfcycle_ps(info) * delay_f_cycles;
3593 delay_e_cycles -= delay_f_cycles;
3594 }
3595
3596 if (info->delay46_ps[channel] < 2500) {
3597 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003598 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003599 }
3600 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3601 if (delay_b_ps <= delay_a_ps)
3602 delay_b_ps = 0;
3603 else
3604 delay_b_ps -= delay_a_ps;
3605 info->delay54_ps[channel] =
3606 cycletime_ps * div_roundup(delay_b_ps,
3607 cycletime_ps) -
3608 2 * halfcycle_ps(info) * delay_e_cycles;
3609 if (info->delay54_ps[channel] < 2500)
3610 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003611 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003612 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3613 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003614 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003615 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003616 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003617 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3618 4 * halfcycle_ps(info)) - 6;
3619 MCHBAR32((channel << 10) + 0x274) =
3620 info->training.reg274265[channel][1] |
3621 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003622 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003623 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3624 4 * halfcycle_ps(info)) + 1;
3625 MCHBAR16((channel << 10) + 0x265) =
3626 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003627 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003628 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003629 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003630 else
Felix Held04be2dd2018-07-29 04:53:22 +02003631 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003632}
3633
3634static void restore_274265(struct raminfo *info)
3635{
3636 int channel;
3637
3638 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003639 MCHBAR32((channel << 10) + 0x274) =
3640 (info->cached_training->reg274265[channel][0] << 16) |
3641 info->cached_training->reg274265[channel][1];
3642 MCHBAR16((channel << 10) + 0x265) =
3643 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003644 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003645 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003646 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003647 else
Felix Held04be2dd2018-07-29 04:53:22 +02003648 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003649}
3650
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003651static void dmi_setup(void)
3652{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003653 gav(read8(DEFAULT_DMIBAR + 0x254));
3654 write8(DEFAULT_DMIBAR + 0x254, 0x1);
3655 write16(DEFAULT_DMIBAR + 0x1b8, 0x18f2);
Felix Heldf83d80b2018-07-29 05:30:30 +02003656 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003657
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003658 write32(DEFAULT_DMIBAR + 0xd68, read32(DEFAULT_DMIBAR + 0xd68) | 0x08000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003659
3660 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3661 DEFAULT_GPIOBASE | 0x38);
3662 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3663}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003664
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003665void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003666{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003667 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003668 u16 ggc;
3669 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003670
Felix Held04be2dd2018-07-29 04:53:22 +02003671 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003672 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3673 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003674 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003675 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003676 }
Felix Held29a9c072018-07-29 01:34:45 +02003677#if 0
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003678 if (!s3resume) {
3679 pre_raminit_3(x2ca8);
3680 }
Vladimir Serbinenkof62669c2014-01-09 10:59:38 +01003681 pre_raminit_4a(x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003682#endif
3683
3684 dmi_setup();
3685
Felix Held04be2dd2018-07-29 04:53:22 +02003686 MCHBAR16(0x1170) = 0xa880;
3687 MCHBAR8(0x11c1) = 0x1;
3688 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003689 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003690
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003691 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3692 /* 0 for 32MB */
3693 gfxsize = 0;
3694 }
3695
3696 ggc = 0xb00 | ((gfxsize + 5) << 4);
3697
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003698 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003699
3700 u16 deven;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003701 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003702
3703 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003704 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003705 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003706 MCHBAR16_OR(0x2c30, 0x200);
3707 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003708 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003709 pci_read_config8(GMA, 0x62); // = 0x2
3710 pci_write_config8(GMA, 0x62, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003711 read8(DEFAULT_RCBA + 0x2318);
3712 write8(DEFAULT_RCBA + 0x2318, 0x47);
3713 read8(DEFAULT_RCBA + 0x2320);
3714 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003715 }
3716
Felix Heldf83d80b2018-07-29 05:30:30 +02003717 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003718
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003719 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003720 gav(read32(DEFAULT_RCBA + 0x3428));
3721 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003722}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003723
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003724void raminit(const int s3resume, const u8 *spd_addrmap)
3725{
3726 unsigned channel, slot, lane, rank;
3727 int i;
3728 struct raminfo info;
3729 u8 x2ca8;
3730 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003731 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003732
Felix Held04be2dd2018-07-29 04:53:22 +02003733 x2ca8 = MCHBAR8(0x2ca8);
Arthur Heymansb572c9d2019-10-14 18:18:46 +02003734
3735 printk(RAM_DEBUG, "Scratchpad MCHBAR8(0x2ca8): 0x%04x\n", x2ca8);
3736
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003737 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003738
3739 memset(&info, 0x5a, sizeof(info));
3740
3741 info.last_500_command[0] = 0;
3742 info.last_500_command[1] = 0;
3743
3744 info.fsb_frequency = 135 * 2;
3745 info.board_lane_delay[0] = 0x14;
3746 info.board_lane_delay[1] = 0x07;
3747 info.board_lane_delay[2] = 0x07;
3748 info.board_lane_delay[3] = 0x08;
3749 info.board_lane_delay[4] = 0x56;
3750 info.board_lane_delay[5] = 0x04;
3751 info.board_lane_delay[6] = 0x04;
3752 info.board_lane_delay[7] = 0x05;
3753 info.board_lane_delay[8] = 0x10;
3754
3755 info.training.reg_178 = 0;
3756 info.training.reg_10b = 0;
3757
3758 info.heci_bar = 0;
3759 info.memory_reserved_for_heci_mb = 0;
3760
3761 /* before SPD */
3762 timestamp_add_now(101);
3763
Felix Held29a9c072018-07-29 01:34:45 +02003764 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003765 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003766
3767 collect_system_info(&info);
3768
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003769 /* Enable SMBUS. */
3770 enable_smbus();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003771
3772 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3773
3774 info.use_ecc = 1;
3775 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003776 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003777 int v;
3778 int try;
3779 int addr;
3780 const u8 useful_addresses[] = {
3781 DEVICE_TYPE,
3782 MODULE_TYPE,
3783 DENSITY,
3784 RANKS_AND_DQ,
3785 MEMORY_BUS_WIDTH,
3786 TIMEBASE_DIVIDEND,
3787 TIMEBASE_DIVISOR,
3788 CYCLETIME,
3789 CAS_LATENCIES_LSB,
3790 CAS_LATENCIES_MSB,
3791 CAS_LATENCY_TIME,
3792 0x11, 0x12, 0x13, 0x14, 0x15,
3793 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3794 0x1c, 0x1d,
3795 THERMAL_AND_REFRESH,
3796 0x20,
3797 REFERENCE_RAW_CARD_USED,
3798 RANK1_ADDRESS_MAPPING,
3799 0x75, 0x76, 0x77, 0x78,
3800 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3801 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3802 0x85, 0x86, 0x87, 0x88,
3803 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3804 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3805 0x95
3806 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003807 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003808 continue;
3809 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003810 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003811 DEVICE_TYPE);
3812 if (v >= 0)
3813 break;
3814 }
3815 if (v < 0)
3816 continue;
3817 for (addr = 0;
3818 addr <
3819 sizeof(useful_addresses) /
3820 sizeof(useful_addresses[0]); addr++)
3821 gav(info.
3822 spd[channel][0][useful_addresses
3823 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003824 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003825 useful_addresses
3826 [addr]));
3827 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3828 die("Only DDR3 is supported");
3829
3830 v = info.spd[channel][0][RANKS_AND_DQ];
3831 info.populated_ranks[channel][0][0] = 1;
3832 info.populated_ranks[channel][0][1] =
3833 ((v >> 3) & 7);
3834 if (((v >> 3) & 7) > 1)
3835 die("At most 2 ranks are supported");
3836 if ((v & 7) == 0 || (v & 7) > 2)
3837 die("Only x8 and x16 modules are supported");
3838 if ((info.
3839 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3840 && (info.
3841 spd[channel][slot][MODULE_TYPE] & 0xF)
3842 != 3)
3843 die("Registered memory is not supported");
3844 info.is_x16_module[channel][0] = (v & 7) - 1;
3845 info.density[channel][slot] =
3846 info.spd[channel][slot][DENSITY] & 0xF;
3847 if (!
3848 (info.
3849 spd[channel][slot][MEMORY_BUS_WIDTH] &
3850 0x18))
3851 info.use_ecc = 0;
3852 }
3853
3854 gav(0x55);
3855
3856 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3857 int v = 0;
3858 for (slot = 0; slot < NUM_SLOTS; slot++)
3859 for (rank = 0; rank < NUM_RANKS; rank++)
3860 v |= info.
3861 populated_ranks[channel][slot][rank]
3862 << (2 * slot + rank);
3863 info.populated_ranks_mask[channel] = v;
3864 }
3865
3866 gav(0x55);
3867
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003868 gav(pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003869 }
3870
3871 /* after SPD */
3872 timestamp_add_now(102);
3873
Felix Held04be2dd2018-07-29 04:53:22 +02003874 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003875
3876 collect_system_info(&info);
3877 calculate_timings(&info);
3878
Felix Held29a9c072018-07-29 01:34:45 +02003879#if 0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003880 pci_write_config8(NORTHBRIDGE, 0xdf, 0x82);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003881#endif
3882
3883 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003884 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003885 if (x2ca8 == 0 && (reg8 & 0x80)) {
3886 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3887 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3888 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3889 */
3890
3891 /* Clear bit7. */
3892
3893 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3894 (reg8 & ~(1 << 7)));
3895
3896 printk(BIOS_INFO,
3897 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003898 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003899 }
3900 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003901
3902 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003903 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3904 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003905
3906 compute_derived_timings(&info);
3907
3908 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003909 gav(MCHBAR8(0x164));
3910 MCHBAR8(0x164) = 0x26;
3911 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003912 }
3913
Felix Held04be2dd2018-07-29 04:53:22 +02003914 MCHBAR32_OR(0x18b4, 0x210000);
3915 MCHBAR32_OR(0x1890, 0x2000000);
3916 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003917
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003918 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x50)); // !!!!
3919 pci_write_config8(PCI_DEV(0xff, 2, 1), 0x54, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003920
Felix Held04be2dd2018-07-29 04:53:22 +02003921 gav(MCHBAR16(0x2c10));
3922 MCHBAR16(0x2c10) = 0x412;
3923 gav(MCHBAR16(0x2c10));
3924 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003925
Felix Held04be2dd2018-07-29 04:53:22 +02003926 gav(MCHBAR8(0x2ca8)); // !!!!
3927 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003928
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003929 pci_read_config32(PCI_DEV(0xff, 2, 1), 0x6c); // !!!!
3930 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x6c, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003931 gav(MCHBAR32(0x1c04)); // !!!!
3932 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003933
3934 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003935 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003936 }
3937
Felix Held04be2dd2018-07-29 04:53:22 +02003938 MCHBAR32(0x18d8) = 0x120000;
3939 MCHBAR32(0x18dc) = 0x30a484a;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003940 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x0);
3941 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003942 MCHBAR32(0x18d8) = 0x40000;
3943 MCHBAR32(0x18dc) = 0xb000000;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003944 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x60000);
3945 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003946 MCHBAR32(0x18d8) = 0x180000;
3947 MCHBAR32(0x18dc) = 0xc0000142;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003948 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x20000);
3949 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003950 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003951
Felix Held04be2dd2018-07-29 04:53:22 +02003952 gav(MCHBAR32(0x18dc)); // !!!!
3953 MCHBAR32(0x18dc) = 0x3;
3954 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003955
3956 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003957 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003958 }
3959
Felix Held04be2dd2018-07-29 04:53:22 +02003960 MCHBAR32(0x188c) = 0x20bc09;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003961 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xd0, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003962 MCHBAR32(0x1a10) = 0x4200010e;
3963 MCHBAR32_OR(0x18b8, 0x200);
3964 gav(MCHBAR32(0x1918)); // !!!!
3965 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003966
Felix Held04be2dd2018-07-29 04:53:22 +02003967 gav(MCHBAR32(0x18b8)); // !!!!
3968 MCHBAR32(0x18b8) = 0xe00;
3969 gav(MCHBAR32(0x182c)); // !!!!
3970 MCHBAR32(0x182c) = 0x10202;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003971 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x94)); // !!!!
3972 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x94, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003973 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3974 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003975
Felix Held04be2dd2018-07-29 04:53:22 +02003976 MCHBAR32_AND(0x18b4, 0xffff7fff);
3977 gav(MCHBAR32(0x1a68)); // !!!!
3978 MCHBAR32(0x1a68) = 0x343800;
3979 gav(MCHBAR32(0x1e68)); // !!!!
3980 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003981
3982 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003983 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003984 }
3985
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003986 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x048); // !!!!
3987 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x048, 0x140000);
3988 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3989 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x058, 0x64555);
3990 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3991 pci_read_config32(PCI_DEV (0xff, 0, 0), 0xd0); // !!!!
3992 pci_write_config32(PCI_DEV (0xff, 0, 0), 0xd0, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003993 gav(MCHBAR32(0x1af0)); // !!!!
3994 gav(MCHBAR32(0x1af0)); // !!!!
3995 MCHBAR32(0x1af0) = 0x1f020003;
3996 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003997
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003998 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003999 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004000 }
4001
Felix Held04be2dd2018-07-29 04:53:22 +02004002 gav(MCHBAR32(0x1890)); // !!!!
4003 MCHBAR32(0x1890) = 0x80102;
4004 gav(MCHBAR32(0x18b4)); // !!!!
4005 MCHBAR32(0x18b4) = 0x216000;
4006 MCHBAR32(0x18a4) = 0x22222222;
4007 MCHBAR32(0x18a8) = 0x22222222;
4008 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004009
4010 udelay(1000);
4011
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004012 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004013
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004014 if (x2ca8 == 0) {
4015 int j;
4016 if (s3resume && info.cached_training) {
4017 restore_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02004018 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004019 info.cached_training->reg2ca9_bit0);
4020 for (i = 0; i < 2; i++)
4021 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02004022 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004023 i, j, info.cached_training->reg274265[i][j]);
4024 } else {
4025 set_274265(&info);
Arthur Heymansc892db62019-10-14 19:05:14 +02004026 printk(RAM_SPEW, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004027 info.training.reg2ca9_bit0);
4028 for (i = 0; i < 2; i++)
4029 for (j = 0; j < 3; j++)
Arthur Heymansc892db62019-10-14 19:05:14 +02004030 printk(RAM_SPEW, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004031 i, j, info.training.reg274265[i][j]);
4032 }
4033
4034 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004035
4036 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02004037 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004038 }
4039
4040 udelay(1000);
4041
4042 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02004043 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02004044 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004045 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4046 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4047 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004048
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004049 MCHBAR8(0x1150);
4050 MCHBAR8(0x1151);
4051 MCHBAR8(0x1022);
4052 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004053 MCHBAR32(0x1300) = 0x60606060;
4054 MCHBAR32(0x1304) = 0x60606060;
4055 MCHBAR32(0x1308) = 0x78797a7b;
4056 MCHBAR32(0x130c) = 0x7c7d7e7f;
4057 MCHBAR32(0x1310) = 0x60606060;
4058 MCHBAR32(0x1314) = 0x60606060;
4059 MCHBAR32(0x1318) = 0x60606060;
4060 MCHBAR32(0x131c) = 0x60606060;
4061 MCHBAR32(0x1320) = 0x50515253;
4062 MCHBAR32(0x1324) = 0x54555657;
4063 MCHBAR32(0x1328) = 0x58595a5b;
4064 MCHBAR32(0x132c) = 0x5c5d5e5f;
4065 MCHBAR32(0x1330) = 0x40414243;
4066 MCHBAR32(0x1334) = 0x44454647;
4067 MCHBAR32(0x1338) = 0x48494a4b;
4068 MCHBAR32(0x133c) = 0x4c4d4e4f;
4069 MCHBAR32(0x1340) = 0x30313233;
4070 MCHBAR32(0x1344) = 0x34353637;
4071 MCHBAR32(0x1348) = 0x38393a3b;
4072 MCHBAR32(0x134c) = 0x3c3d3e3f;
4073 MCHBAR32(0x1350) = 0x20212223;
4074 MCHBAR32(0x1354) = 0x24252627;
4075 MCHBAR32(0x1358) = 0x28292a2b;
4076 MCHBAR32(0x135c) = 0x2c2d2e2f;
4077 MCHBAR32(0x1360) = 0x10111213;
4078 MCHBAR32(0x1364) = 0x14151617;
4079 MCHBAR32(0x1368) = 0x18191a1b;
4080 MCHBAR32(0x136c) = 0x1c1d1e1f;
4081 MCHBAR32(0x1370) = 0x10203;
4082 MCHBAR32(0x1374) = 0x4050607;
4083 MCHBAR32(0x1378) = 0x8090a0b;
4084 MCHBAR32(0x137c) = 0xc0d0e0f;
4085 MCHBAR8(0x11cc) = 0x4e;
4086 MCHBAR32(0x1110) = 0x73970404;
4087 MCHBAR32(0x1114) = 0x72960404;
4088 MCHBAR32(0x1118) = 0x6f950404;
4089 MCHBAR32(0x111c) = 0x6d940404;
4090 MCHBAR32(0x1120) = 0x6a930404;
4091 MCHBAR32(0x1124) = 0x68a41404;
4092 MCHBAR32(0x1128) = 0x66a21404;
4093 MCHBAR32(0x112c) = 0x63a01404;
4094 MCHBAR32(0x1130) = 0x609e1404;
4095 MCHBAR32(0x1134) = 0x5f9c1404;
4096 MCHBAR32(0x1138) = 0x5c961404;
4097 MCHBAR32(0x113c) = 0x58a02404;
4098 MCHBAR32(0x1140) = 0x54942404;
4099 MCHBAR32(0x1190) = 0x900080a;
4100 MCHBAR16(0x11c0) = 0xc40b;
4101 MCHBAR16(0x11c2) = 0x303;
4102 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004103 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004104 MCHBAR32(0x11b8) = 0x70c3000;
4105 MCHBAR8(0x11ec) = 0xa;
4106 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004107 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004108 MCHBAR16(0x11ca) = 0xfa;
4109 MCHBAR32(0x11e4) = 0x4e20;
4110 MCHBAR8(0x11bc) = 0xf;
4111 MCHBAR16(0x11da) = 0x19;
4112 MCHBAR16(0x11ba) = 0x470c;
4113 MCHBAR32(0x1680) = 0xe6ffe4ff;
4114 MCHBAR32(0x1684) = 0xdeffdaff;
4115 MCHBAR32(0x1688) = 0xd4ffd0ff;
4116 MCHBAR32(0x168c) = 0xccffc6ff;
4117 MCHBAR32(0x1690) = 0xc0ffbeff;
4118 MCHBAR32(0x1694) = 0xb8ffb0ff;
4119 MCHBAR32(0x1698) = 0xa8ff0000;
4120 MCHBAR32(0x169c) = 0xc00;
4121 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004122 }
4123
Felix Held04be2dd2018-07-29 04:53:22 +02004124 MCHBAR32(0x124c) = 0x15040d00;
4125 MCHBAR32(0x1250) = 0x7f0000;
4126 MCHBAR32(0x1254) = 0x1e220004;
4127 MCHBAR32(0x1258) = 0x4000004;
4128 MCHBAR32(0x1278) = 0x0;
4129 MCHBAR32(0x125c) = 0x0;
4130 MCHBAR32(0x1260) = 0x0;
4131 MCHBAR32(0x1264) = 0x0;
4132 MCHBAR32(0x1268) = 0x0;
4133 MCHBAR32(0x126c) = 0x0;
4134 MCHBAR32(0x1270) = 0x0;
4135 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004136 }
4137
4138 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004139 MCHBAR16(0x1214) = 0x320;
4140 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004141 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4142 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004143 MCHBAR32(0x1400) = 0x13040020;
4144 MCHBAR32(0x1404) = 0xe090120;
4145 MCHBAR32(0x1408) = 0x5120220;
4146 MCHBAR32(0x140c) = 0x5120330;
4147 MCHBAR32(0x1410) = 0xe090220;
4148 MCHBAR32(0x1414) = 0x1010001;
4149 MCHBAR32(0x1418) = 0x1110000;
4150 MCHBAR32(0x141c) = 0x9020020;
4151 MCHBAR32(0x1420) = 0xd090220;
4152 MCHBAR32(0x1424) = 0x2090220;
4153 MCHBAR32(0x1428) = 0x2090330;
4154 MCHBAR32(0x142c) = 0xd090220;
4155 MCHBAR32(0x1430) = 0x1010001;
4156 MCHBAR32(0x1434) = 0x1110000;
4157 MCHBAR32(0x1438) = 0x11040020;
4158 MCHBAR32(0x143c) = 0x4030220;
4159 MCHBAR32(0x1440) = 0x1060220;
4160 MCHBAR32(0x1444) = 0x1060330;
4161 MCHBAR32(0x1448) = 0x4030220;
4162 MCHBAR32(0x144c) = 0x1010001;
4163 MCHBAR32(0x1450) = 0x1110000;
4164 MCHBAR32(0x1454) = 0x4010020;
4165 MCHBAR32(0x1458) = 0xb090220;
4166 MCHBAR32(0x145c) = 0x1090220;
4167 MCHBAR32(0x1460) = 0x1090330;
4168 MCHBAR32(0x1464) = 0xb090220;
4169 MCHBAR32(0x1468) = 0x1010001;
4170 MCHBAR32(0x146c) = 0x1110000;
4171 MCHBAR32(0x1470) = 0xf040020;
4172 MCHBAR32(0x1474) = 0xa090220;
4173 MCHBAR32(0x1478) = 0x1120220;
4174 MCHBAR32(0x147c) = 0x1120330;
4175 MCHBAR32(0x1480) = 0xa090220;
4176 MCHBAR32(0x1484) = 0x1010001;
4177 MCHBAR32(0x1488) = 0x1110000;
4178 MCHBAR32(0x148c) = 0x7020020;
4179 MCHBAR32(0x1490) = 0x1010220;
4180 MCHBAR32(0x1494) = 0x10210;
4181 MCHBAR32(0x1498) = 0x10320;
4182 MCHBAR32(0x149c) = 0x1010220;
4183 MCHBAR32(0x14a0) = 0x1010001;
4184 MCHBAR32(0x14a4) = 0x1110000;
4185 MCHBAR32(0x14a8) = 0xd040020;
4186 MCHBAR32(0x14ac) = 0x8090220;
4187 MCHBAR32(0x14b0) = 0x1111310;
4188 MCHBAR32(0x14b4) = 0x1111420;
4189 MCHBAR32(0x14b8) = 0x8090220;
4190 MCHBAR32(0x14bc) = 0x1010001;
4191 MCHBAR32(0x14c0) = 0x1110000;
4192 MCHBAR32(0x14c4) = 0x3010020;
4193 MCHBAR32(0x14c8) = 0x7090220;
4194 MCHBAR32(0x14cc) = 0x1081310;
4195 MCHBAR32(0x14d0) = 0x1081420;
4196 MCHBAR32(0x14d4) = 0x7090220;
4197 MCHBAR32(0x14d8) = 0x1010001;
4198 MCHBAR32(0x14dc) = 0x1110000;
4199 MCHBAR32(0x14e0) = 0xb040020;
4200 MCHBAR32(0x14e4) = 0x2030220;
4201 MCHBAR32(0x14e8) = 0x1051310;
4202 MCHBAR32(0x14ec) = 0x1051420;
4203 MCHBAR32(0x14f0) = 0x2030220;
4204 MCHBAR32(0x14f4) = 0x1010001;
4205 MCHBAR32(0x14f8) = 0x1110000;
4206 MCHBAR32(0x14fc) = 0x5020020;
4207 MCHBAR32(0x1500) = 0x5090220;
4208 MCHBAR32(0x1504) = 0x2071310;
4209 MCHBAR32(0x1508) = 0x2071420;
4210 MCHBAR32(0x150c) = 0x5090220;
4211 MCHBAR32(0x1510) = 0x1010001;
4212 MCHBAR32(0x1514) = 0x1110000;
4213 MCHBAR32(0x1518) = 0x7040120;
4214 MCHBAR32(0x151c) = 0x2090220;
4215 MCHBAR32(0x1520) = 0x70b1210;
4216 MCHBAR32(0x1524) = 0x70b1310;
4217 MCHBAR32(0x1528) = 0x2090220;
4218 MCHBAR32(0x152c) = 0x1010001;
4219 MCHBAR32(0x1530) = 0x1110000;
4220 MCHBAR32(0x1534) = 0x1010110;
4221 MCHBAR32(0x1538) = 0x1081310;
4222 MCHBAR32(0x153c) = 0x5041200;
4223 MCHBAR32(0x1540) = 0x5041310;
4224 MCHBAR32(0x1544) = 0x1081310;
4225 MCHBAR32(0x1548) = 0x1010001;
4226 MCHBAR32(0x154c) = 0x1110000;
4227 MCHBAR32(0x1550) = 0x1040120;
4228 MCHBAR32(0x1554) = 0x4051210;
4229 MCHBAR32(0x1558) = 0xd051200;
4230 MCHBAR32(0x155c) = 0xd051200;
4231 MCHBAR32(0x1560) = 0x4051210;
4232 MCHBAR32(0x1564) = 0x1010001;
4233 MCHBAR32(0x1568) = 0x1110000;
4234 MCHBAR16(0x1222) = 0x220a;
4235 MCHBAR16(0x123c) = 0x1fc0;
4236 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004237 }
4238
Felix Heldf83d80b2018-07-29 05:30:30 +02004239 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004240 MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004241 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004242
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004243 MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004244
4245 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004246 MCHBAR8_AND(0x2ca8, ~3);
4247 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
Arthur Heymansb572c9d2019-10-14 18:18:46 +02004248 /* This issues a CPU reset without resetting the platform */
4249 printk(BIOS_DEBUG, "Issuing a CPU reset\n");
Arthur Heymans2878c0b2019-10-14 18:42:00 +02004250 /* Write back the S3 state to PM1_CNT to let the reset CPU
4251 know it also needs to take the s3 path. */
4252 if (s3resume)
4253 write_pmbase32(PM1_CNT, read_pmbase32(PM1_CNT)
4254 | (SLP_TYP_S3 << 10));
Felix Held04be2dd2018-07-29 04:53:22 +02004255 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004256 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004257 }
4258
Felix Held04be2dd2018-07-29 04:53:22 +02004259 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004260 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004261 pci_write_config32(PCI_DEV (0xff, 0, 0), 0x60, 0x20220);
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004262 MCHBAR16(0x2c20); // !!!!
4263 MCHBAR16(0x2c10); // !!!!
4264 MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004265 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004266 udelay(1000);
4267 write_1d0(0, 0x33d, 0, 0);
4268 write_500(&info, 0, 0, 0xb61, 0, 0);
4269 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004270 MCHBAR32(0x1a30) = 0x0;
4271 MCHBAR32(0x1a34) = 0x0;
4272 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4273 (info.populated_ranks[0][0][0] * 0xa0);
4274 MCHBAR16(0x616) = 0x26a;
4275 MCHBAR32(0x134) = 0x856000;
4276 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004277 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4278 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004279 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004280 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4281 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004282 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004283 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004284 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4285 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004286 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4287 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4288 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4289 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4290 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4291 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4292 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4293 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4294 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4295 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004296 }
4297
4298 write_1d0(0x4, 0x151, 4, 1);
4299 write_1d0(0, 0x142, 3, 1);
4300 rdmsr(0x1ac); // !!!!
4301 write_500(&info, 1, 1, 0x6b3, 4, 1);
4302 write_500(&info, 1, 1, 0x6cf, 4, 1);
4303
4304 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4305
4306 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4307 populated_ranks[0]
4308 [0][0]) << 0),
4309 0x1d1, 3, 1);
4310 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004311 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4312 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004313 }
4314
4315 set_334(0);
4316
4317 program_base_timings(&info);
4318
Felix Held04be2dd2018-07-29 04:53:22 +02004319 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004320
4321 write_1d0(0x2, 0x1d5, 2, 1);
4322 write_1d0(0x20, 0x166, 7, 1);
4323 write_1d0(0x0, 0xeb, 3, 1);
4324 write_1d0(0x0, 0xf3, 6, 1);
4325
4326 for (channel = 0; channel < NUM_CHANNELS; channel++)
4327 for (lane = 0; lane < 9; lane++) {
4328 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4329 u8 a;
4330 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4331 write_500(&info, channel, a, addr, 6, 1);
4332 }
4333
4334 udelay(1000);
4335
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004336 if (s3resume) {
4337 if (info.cached_training == NULL) {
4338 u32 reg32;
4339 printk(BIOS_ERR,
4340 "Couldn't find training data. Rebooting\n");
4341 reg32 = inl(DEFAULT_PMBASE + 0x04);
4342 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004343 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004344 }
4345 int tm;
4346 info.training = *info.cached_training;
4347 for (tm = 0; tm < 4; tm++)
4348 for (channel = 0; channel < NUM_CHANNELS; channel++)
4349 for (slot = 0; slot < NUM_SLOTS; slot++)
4350 for (rank = 0; rank < NUM_RANKS; rank++)
4351 for (lane = 0; lane < 9; lane++)
4352 write_500(&info,
4353 channel,
4354 info.training.
4355 lane_timings
4356 [tm][channel]
4357 [slot][rank]
4358 [lane],
4359 get_timing_register_addr
4360 (lane, tm,
4361 slot, rank),
4362 9, 0);
4363 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4364 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4365 }
4366
Felix Heldf83d80b2018-07-29 05:30:30 +02004367 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004368 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004369 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004370 MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004371
4372 program_board_delay(&info);
4373
Felix Held04be2dd2018-07-29 04:53:22 +02004374 MCHBAR8(0x5ff) = 0x0;
4375 MCHBAR8(0x5ff) = 0x80;
4376 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004377
Felix Held04be2dd2018-07-29 04:53:22 +02004378 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004379 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004380 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004381 gav(read_1d0(0x14b, 7)); // = 0x81023100
4382 write_1d0(0x30, 0x14b, 7, 1);
4383 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4384 write_1d0(7, 0xd6, 6, 1);
4385 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4386 write_1d0(7, 0x328, 6, 1);
4387
4388 for (channel = 0; channel < NUM_CHANNELS; channel++)
4389 set_4cf(&info, channel,
4390 info.populated_ranks[channel][0][0] ? 8 : 0);
4391
4392 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4393 write_1d0(2, 0x116, 4, 1);
4394 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4395 write_1d0(0, 0xae, 6, 1);
4396 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4397 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004398 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4399 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004400 MCHBAR32_AND(0x140, ~0x07000000);
4401 MCHBAR32_AND(0x138, ~0x07000000);
4402 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004403 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004404 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004405 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004406
4407 {
4408 u32 t;
4409 u8 val_a1;
4410 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4411 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4412 rmw_1d0(0x320, 0x07,
4413 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4414 rmw_1d0(0x14b, 0x78,
4415 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4416 4), 7,
4417 1);
4418 rmw_1d0(0xce, 0x38,
4419 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4420 4), 6,
4421 1);
4422 }
4423
4424 for (channel = 0; channel < NUM_CHANNELS; channel++)
4425 set_4cf(&info, channel,
4426 info.populated_ranks[channel][0][0] ? 9 : 1);
4427
4428 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004429 MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004430 write_1d0(2, 0xae, 6, 1);
4431 write_1d0(2, 0x300, 6, 1);
4432 write_1d0(2, 0x121, 3, 1);
4433 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4434 write_1d0(4, 0xd6, 6, 1);
4435 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4436 write_1d0(4, 0x328, 6, 1);
4437
4438 for (channel = 0; channel < NUM_CHANNELS; channel++)
4439 set_4cf(&info, channel,
4440 info.populated_ranks[channel][0][0] ? 9 : 0);
4441
Felix Held04be2dd2018-07-29 04:53:22 +02004442 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4443 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004444 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004445 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004446 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4447 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4448 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4449 write_1d0(0, 0x21c, 6, 1);
4450 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4451 write_1d0(0x35, 0x14b, 7, 1);
4452
4453 for (channel = 0; channel < NUM_CHANNELS; channel++)
4454 set_4cf(&info, channel,
4455 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4456
4457 set_334(1);
4458
Felix Held04be2dd2018-07-29 04:53:22 +02004459 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004460
4461 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4462 write_500(&info, channel,
4463 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4464 1);
4465 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4466 }
Felix Held04be2dd2018-07-29 04:53:22 +02004467 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4468 MCHBAR16(0x6c0) = 0x14a0;
4469 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4470 MCHBAR16(0x232) = 0x8;
4471 /* 0x40004 or 0 depending on ? */
4472 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4473 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4474 MCHBAR32(0x128) = 0x2150d05;
4475 MCHBAR8(0x12c) = 0x1f;
4476 MCHBAR8(0x12d) = 0x56;
4477 MCHBAR8(0x12e) = 0x31;
4478 MCHBAR8(0x12f) = 0x0;
4479 MCHBAR8(0x271) = 0x2;
4480 MCHBAR8(0x671) = 0x2;
4481 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004482 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004483 MCHBAR32(0x294 + (channel << 10)) =
4484 (info.populated_ranks_mask[channel] & 3) << 16;
4485 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4486 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004487 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004488 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4489 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004490
4491 if (!s3resume)
4492 jedec_init(&info);
4493
4494 int totalrank = 0;
4495 for (channel = 0; channel < NUM_CHANNELS; channel++)
4496 for (slot = 0; slot < NUM_SLOTS; slot++)
4497 for (rank = 0; rank < NUM_RANKS; rank++)
4498 if (info.populated_ranks[channel][slot][rank]) {
4499 jedec_read(&info, channel, slot, rank,
4500 totalrank, 0xa, 0x400);
4501 totalrank++;
4502 }
4503
Felix Held04be2dd2018-07-29 04:53:22 +02004504 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004505
Felix Heldf83d80b2018-07-29 05:30:30 +02004506 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4507 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004508
4509 if (!s3resume) {
4510 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004511 MCHBAR32(0x294 + (channel << 10)) =
4512 (info.populated_ranks_mask[channel] & 3) << 16;
4513 MCHBAR16(0x298 + (channel << 10)) =
4514 info.populated_ranks[channel][0][0] |
4515 (info.populated_ranks[channel][0][1] << 5);
4516 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004517 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004518 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004519
4520 {
4521 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004522 a = MCHBAR8(0x243);
4523 b = MCHBAR8(0x643);
4524 MCHBAR8(0x243) = a | 2;
4525 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004526 }
4527
4528 write_1d0(7, 0x19b, 3, 1);
4529 write_1d0(7, 0x1c0, 3, 1);
4530 write_1d0(4, 0x1c6, 4, 1);
4531 write_1d0(4, 0x1cc, 4, 1);
4532 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4533 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004534 MCHBAR32(0x584) = 0xfffff;
4535 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004536
4537 for (channel = 0; channel < NUM_CHANNELS; channel++)
4538 for (slot = 0; slot < NUM_SLOTS; slot++)
4539 for (rank = 0; rank < NUM_RANKS; rank++)
4540 if (info.
4541 populated_ranks[channel][slot]
4542 [rank])
4543 config_rank(&info, s3resume,
4544 channel, slot,
4545 rank);
4546
Felix Held04be2dd2018-07-29 04:53:22 +02004547 MCHBAR8(0x243) = 0x1;
4548 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004549 }
4550
4551 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004552 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004553 write_26c(0, 0x820);
4554 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004555 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004556 /* end */
4557
4558 if (s3resume) {
4559 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004560 MCHBAR32(0x294 + (channel << 10)) =
4561 (info.populated_ranks_mask[channel] & 3) << 16;
4562 MCHBAR16(0x298 + (channel << 10)) =
4563 info.populated_ranks[channel][0][0] |
4564 (info.populated_ranks[channel][0][1] << 5);
4565 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004566 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004567 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004568 }
4569
Felix Held04be2dd2018-07-29 04:53:22 +02004570 MCHBAR32_AND(0xfa4, ~0x01000002);
4571 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004572
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004573 /* Before training. */
4574 timestamp_add_now(103);
4575
4576 if (!s3resume)
4577 ram_training(&info);
4578
4579 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004580 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004581
4582 dump_timings(&info);
4583
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004584 program_modules_memory_map(&info, 0);
4585 program_total_memory_map(&info);
4586
4587 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004588 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004589 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004590 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004591 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004592 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004593 else
Felix Held04be2dd2018-07-29 04:53:22 +02004594 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004595
Felix Held04be2dd2018-07-29 04:53:22 +02004596 MCHBAR32_AND(0xfac, ~0x80000000);
4597 MCHBAR32(0xfb4) = 0x4800;
4598 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4599 MCHBAR32(0xe94) = 0x7ffff;
4600 MCHBAR32(0xfc0) = 0x80002040;
4601 MCHBAR32(0xfc4) = 0x701246;
4602 MCHBAR8_AND(0xfc8, ~0x70);
4603 MCHBAR32_OR(0xe5c, 0x1000000);
4604 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4605 MCHBAR32(0x50) = 0x700b0;
4606 MCHBAR32(0x3c) = 0x10;
4607 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4608 MCHBAR8_OR(0xff4, 0x2);
4609 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004610
Felix Held29a9c072018-07-29 01:34:45 +02004611#if 1
Felix Held04be2dd2018-07-29 04:53:22 +02004612 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4613 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4614 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004615
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004616 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4617 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4618 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004619
4620#else
4621 {
4622 u32 eax;
Felix Held04be2dd2018-07-29 04:53:22 +02004623 // = 0xe911714b
4624 eax = read32p(0xffc + (MCHBAR32(0xd00) & ~1)) | 0x08000000;
4625 write32p(0xffc + (MCHBAR32(0xd00) & ~1), eax);
4626 // = 0xe911714b
4627 eax = read32p(0xffc + (MCHBAR32(0xdc0) & ~1)) | 0x40000000;
4628 write32p(0xffc + (MCHBAR32(0xdc0) & ~1), eax);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004629 }
4630#endif
4631
4632 {
4633 u32 eax;
4634
4635 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004636 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4637 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4638 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004639 }
4640
4641 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004642 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004643 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004644 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004645 else
Felix Held04be2dd2018-07-29 04:53:22 +02004646 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004647
Felix Held04be2dd2018-07-29 04:53:22 +02004648 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004649
Felix Held04be2dd2018-07-29 04:53:22 +02004650 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004651 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004652 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004653 else
Felix Held04be2dd2018-07-29 04:53:22 +02004654 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004655 }
4656
Felix Held04be2dd2018-07-29 04:53:22 +02004657 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004658
4659 {
4660 u8 al;
4661 al = 0xd;
4662 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4663 al += 2;
4664 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004665 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004666 }
4667
4668 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004669 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4670 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4671 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4672 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004673 }
4674 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004675 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004676 reg1c = read32p(DEFAULT_EPBAR | 0x01c); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004677 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004678 write32p(DEFAULT_EPBAR | 0x01c, reg1c); // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004679 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004680 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004681 MCHBAR8_OR(0x1210, 2);
4682 MCHBAR32(0x1200) = 0x8800440;
4683 MCHBAR32(0x1204) = 0x53ff0453;
4684 MCHBAR32(0x1208) = 0x19002043;
4685 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004686
4687 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004688 MCHBAR16(0x1214) = 0x220;
4689 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004690 }
4691
Felix Held04be2dd2018-07-29 04:53:22 +02004692 MCHBAR8_OR(0x1214, 0x4);
4693 MCHBAR8(0x120c) = 0x1;
4694 MCHBAR8(0x1218) = 0x3;
4695 MCHBAR8(0x121a) = 0x3;
4696 MCHBAR8(0x121c) = 0x3;
4697 MCHBAR16(0xc14) = 0x0;
4698 MCHBAR16(0xc20) = 0x0;
4699 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004700
4701 /* revision dependent here. */
4702
Felix Held04be2dd2018-07-29 04:53:22 +02004703 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004704
4705 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004706 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004707
Felix Held04be2dd2018-07-29 04:53:22 +02004708 MCHBAR16_OR(0x1230, 0x8000);
4709 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004710
4711 u8 bl, ebpb;
4712 u16 reg_1020;
4713
Felix Held04be2dd2018-07-29 04:53:22 +02004714 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4715 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004716
Felix Held04be2dd2018-07-29 04:53:22 +02004717 MCHBAR32(0x1000) = 0x100;
4718 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004719
4720 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004721 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004722 bl = reg_1020 >> 8;
4723 ebpb = reg_1020 & 0xff;
4724 } else {
4725 ebpb = 0;
4726 bl = 8;
4727 }
4728
4729 rdmsr(0x1a2);
4730
Felix Held04be2dd2018-07-29 04:53:22 +02004731 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004732
Felix Held04be2dd2018-07-29 04:53:22 +02004733 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004734
Felix Held04be2dd2018-07-29 04:53:22 +02004735 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004736
Felix Held04be2dd2018-07-29 04:53:22 +02004737 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004738 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004739 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4740 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004741 }
4742
4743 setup_heci_uma(&info);
4744
4745 if (info.uma_enabled) {
4746 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004747 MCHBAR32_OR(0x11b0, 0x4000);
4748 MCHBAR32_OR(0x11b4, 0x4000);
4749 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004750
Felix Held04be2dd2018-07-29 04:53:22 +02004751 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4752 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4753 MCHBAR16_OR(0x1170, 0x1000);
4754
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004755 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004756
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004757 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004758 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004759 ;
4760 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004761 }
4762
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004763 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4764 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004765 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004766 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004767
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004768 udelay(1000);
4769 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004770 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4771
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004772 if (!s3resume)
4773 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004774 if (s3resume && cbmem_wasnot_inited) {
4775 u32 reg32;
4776 printk(BIOS_ERR, "Failed S3 resume.\n");
4777 ram_check(0x100000, 0x200000);
4778
4779 /* Clear SLP_TYPE. */
4780 reg32 = inl(DEFAULT_PMBASE + 0x04);
4781 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4782
4783 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004784 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004785 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004786}