blob: 0b5f44c73ff138febe521c52203b99722a1804c1 [file] [log] [blame]
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013 Vladimir Serbinenko.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010015 */
16
Kyösti Mälkki931c1dc2014-06-30 09:40:19 +030017#include <stdlib.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010018#include <console/console.h>
19#include <string.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010020#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020021#include <device/mmio.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020022#include <device/pci_ops.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010023#include <cpu/x86/msr.h>
24#include <cbmem.h>
Elyes HAOUASd45f3382019-04-28 18:04:35 +020025#include <cf9_reset.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010026#include <arch/cbfs.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010027#include <ip_checksum.h>
28#include <pc80/mc146818rtc.h>
29#include <device/pci_def.h>
Patrick Rudolph266a1f72016-06-09 18:13:34 +020030#include <device/device.h>
Patrick Georgi546953c2014-11-29 10:38:17 +010031#include <halt.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010032#include <spd.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010033#include <timestamp.h>
34#include <cpu/x86/mtrr.h>
35#include <cpu/intel/speedstep.h>
36#include <cpu/intel/turbo.h>
Arthur Heymansdc71e252018-01-29 10:14:48 +010037#include <mrc_cache.h>
Elyes HAOUAS21b71ce62018-06-16 18:43:52 +020038#include <southbridge/intel/ibexpeak/me.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010039#include <delay.h>
Elyes HAOUAS51401c32019-05-15 21:09:30 +020040#include <types.h>
41
42#include "chip.h"
43#include "nehalem.h"
44#include "raminit.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010045
46#define NORTHBRIDGE PCI_DEV(0, 0, 0)
47#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
48#define GMA PCI_DEV (0, 0x2, 0x0)
49#define HECIDEV PCI_DEV(0, 0x16, 0)
50#define HECIBAR 0x10
51
52#define FOR_ALL_RANKS \
53 for (channel = 0; channel < NUM_CHANNELS; channel++) \
54 for (slot = 0; slot < NUM_SLOTS; slot++) \
55 for (rank = 0; rank < NUM_RANKS; rank++)
56
57#define FOR_POPULATED_RANKS \
58 for (channel = 0; channel < NUM_CHANNELS; channel++) \
59 for (slot = 0; slot < NUM_SLOTS; slot++) \
60 for (rank = 0; rank < NUM_RANKS; rank++) \
61 if (info->populated_ranks[channel][slot][rank])
62
63#define FOR_POPULATED_RANKS_BACKWARDS \
64 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) \
65 for (slot = 0; slot < NUM_SLOTS; slot++) \
66 for (rank = 0; rank < NUM_RANKS; rank++) \
67 if (info->populated_ranks[channel][slot][rank])
68
69/* [REG_178][CHANNEL][2 * SLOT + RANK][LANE] */
70typedef struct {
71 u8 smallest;
72 u8 largest;
73} timing_bounds_t[2][2][2][9];
74
Arthur Heymansdc71e252018-01-29 10:14:48 +010075#define MRC_CACHE_VERSION 1
76
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010077struct ram_training {
78 /* [TM][CHANNEL][SLOT][RANK][LANE] */
79 u16 lane_timings[4][2][2][2][9];
80 u16 reg_178;
81 u16 reg_10b;
82
83 u8 reg178_center;
84 u8 reg178_smallest;
85 u8 reg178_largest;
86 timing_bounds_t timing_bounds[2];
87 u16 timing_offset[2][2][2][9];
88 u16 timing2_offset[2][2][2][9];
89 u16 timing2_bounds[2][2][2][9][2];
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +010090 u8 reg274265[2][3]; /* [CHANNEL][REGISTER] */
91 u8 reg2ca9_bit0;
92 u32 reg_6dc;
93 u32 reg_6e8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010094};
95
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010096#include <lib.h> /* Prototypes */
97
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010098
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010099static void clflush(u32 addr)
100{
101 asm volatile ("clflush (%0)"::"r" (addr));
102}
103
104typedef struct _u128 {
105 u64 lo;
106 u64 hi;
107} u128;
108
109static void read128(u32 addr, u64 * out)
110{
111 u128 ret;
112 u128 stor;
113 asm volatile ("movdqu %%xmm0, %0\n"
114 "movdqa (%2), %%xmm0\n"
115 "movdqu %%xmm0, %1\n"
116 "movdqu %0, %%xmm0":"+m" (stor), "=m"(ret):"r"(addr));
117 out[0] = ret.lo;
118 out[1] = ret.hi;
119}
120
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100121/* OK */
122static void write_1d0(u32 val, u16 addr, int bits, int flag)
123{
Felix Held04be2dd2018-07-29 04:53:22 +0200124 MCHBAR32(0x1d0) = 0;
125 while (MCHBAR32(0x1d0) & 0x800000)
126 ;
127 MCHBAR32(0x1d4) =
128 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
129 MCHBAR32(0x1d0) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200130 while (MCHBAR32(0x1d0) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200131 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100132}
133
134/* OK */
135static u16 read_1d0(u16 addr, int split)
136{
137 u32 val;
Felix Held04be2dd2018-07-29 04:53:22 +0200138 MCHBAR32(0x1d0) = 0;
139 while (MCHBAR32(0x1d0) & 0x800000)
140 ;
141 MCHBAR32(0x1d0) =
142 0x80000000 | (((MCHBAR8(0x246) >> 2) & 3) + 0x361 - addr);
143 while (MCHBAR32(0x1d0) & 0x800000)
144 ;
145 val = MCHBAR32(0x1d8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100146 write_1d0(0, 0x33d, 0, 0);
147 write_1d0(0, 0x33d, 0, 0);
148 val &= ((1 << split) - 1);
149 // printk (BIOS_ERR, "R1D0C [%x] => %x\n", addr, val);
150 return val;
151}
152
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800153static void write32p(uintptr_t addr, uint32_t val)
154{
155 write32((void *)addr, val);
156}
157
158static uint32_t read32p(uintptr_t addr)
159{
160 return read32((void *)addr);
161}
162
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100163static void sfence(void)
164{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100165 asm volatile ("sfence");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100166}
167
168static inline u16 get_lane_offset(int slot, int rank, int lane)
169{
170 return 0x124 * lane + ((lane & 4) ? 0x23e : 0) + 11 * rank + 22 * slot -
171 0x452 * (lane == 8);
172}
173
174static inline u16 get_timing_register_addr(int lane, int tm, int slot, int rank)
175{
176 const u16 offs[] = { 0x1d, 0xa8, 0xe6, 0x5c };
177 return get_lane_offset(slot, rank, lane) + offs[(tm + 3) % 4];
178}
179
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100180static u32 gav_real(int line, u32 in)
181{
182 // printk (BIOS_DEBUG, "%d: GAV: %x\n", line, in);
183 return in;
184}
185
186#define gav(x) gav_real (__LINE__, (x))
Felix Held29a9c072018-07-29 01:34:45 +0200187
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100188struct raminfo {
189 u16 clock_speed_index; /* clock_speed (REAL, not DDR) / 133.(3) - 3 */
190 u16 fsb_frequency; /* in 1.(1)/2 MHz. */
191 u8 is_x16_module[2][2]; /* [CHANNEL][SLOT] */
192 u8 density[2][2]; /* [CHANNEL][SLOT] */
193 u8 populated_ranks[2][2][2]; /* [CHANNEL][SLOT][RANK] */
194 int rank_start[2][2][2];
195 u8 cas_latency;
196 u8 board_lane_delay[9];
197 u8 use_ecc;
198 u8 revision;
199 u8 max_supported_clock_speed_index;
200 u8 uma_enabled;
201 u8 spd[2][2][151]; /* [CHANNEL][SLOT][BYTE] */
202 u8 silicon_revision;
203 u8 populated_ranks_mask[2];
204 u8 max_slots_used_in_channel;
205 u8 mode4030[2];
206 u16 avg4044[2];
207 u16 max4048[2];
208 unsigned total_memory_mb;
209 unsigned interleaved_part_mb;
210 unsigned non_interleaved_part_mb;
211
212 u32 heci_bar;
213 u64 heci_uma_addr;
214 unsigned memory_reserved_for_heci_mb;
215
216 struct ram_training training;
217 u32 last_500_command[2];
218
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100219 u32 delay46_ps[2];
220 u32 delay54_ps[2];
221 u8 revision_flag_1;
222 u8 some_delay_1_cycle_floor;
223 u8 some_delay_2_halfcycles_ceil;
224 u8 some_delay_3_ps_rounded;
225
226 const struct ram_training *cached_training;
227};
228
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200229/* Global allocation of timings_car */
Arthur Heymans33ab29f2018-12-29 13:34:30 +0100230timing_bounds_t timings_car[64];
Matthias Gazzaridfa51252018-05-19 00:44:20 +0200231
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100232static void
233write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
234 int flag);
235
236/* OK */
237static u16
238read_500(struct raminfo *info, int channel, u16 addr, int split)
239{
240 u32 val;
241 info->last_500_command[channel] = 0x80000000;
Felix Held04be2dd2018-07-29 04:53:22 +0200242 MCHBAR32(0x500 + (channel << 10)) = 0;
243 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
244 ;
245 MCHBAR32(0x500 + (channel << 10)) =
246 0x80000000 | (((MCHBAR8(0x246 + (channel << 10)) >> 2) & 3)
247 + 0xb88 - addr);
248 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
249 ;
250 val = MCHBAR32(0x508 + (channel << 10));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100251 return val & ((1 << split) - 1);
252}
253
254/* OK */
255static void
256write_500(struct raminfo *info, int channel, u32 val, u16 addr, int bits,
257 int flag)
258{
259 if (info->last_500_command[channel] == 0x80000000) {
260 info->last_500_command[channel] = 0x40000000;
261 write_500(info, channel, 0, 0xb61, 0, 0);
262 }
Felix Held04be2dd2018-07-29 04:53:22 +0200263 MCHBAR32(0x500 + (channel << 10)) = 0;
264 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
265 ;
266 MCHBAR32(0x504 + (channel << 10)) =
267 (val & ((1 << bits) - 1)) | (2 << bits) | (flag << bits);
268 MCHBAR32(0x500 + (channel << 10)) = 0x40000000 | addr;
Felix Held22ca8cb2018-07-29 05:09:44 +0200269 while (MCHBAR32(0x500 + (channel << 10)) & 0x800000)
Felix Held04be2dd2018-07-29 04:53:22 +0200270 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100271}
272
273static int rw_test(int rank)
274{
275 const u32 mask = 0xf00fc33c;
276 int ok = 0xff;
277 int i;
278 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800279 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100280 sfence();
281 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800282 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100283 sfence();
284 for (i = 0; i < 32; i++) {
285 u32 pat = (((mask >> i) & 1) ? 0xffffffff : 0);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800286 write32p((rank << 28) | (i << 3), pat);
287 write32p((rank << 28) | (i << 3) | 4, pat);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100288 }
289 sfence();
290 for (i = 0; i < 32; i++) {
291 u8 pat = (((mask >> i) & 1) ? 0xff : 0);
292 int j;
293 u32 val;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800294 gav(val = read32p((rank << 28) | (i << 3)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100295 for (j = 0; j < 4; j++)
296 if (((val >> (j * 8)) & 0xff) != pat)
297 ok &= ~(1 << j);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800298 gav(val = read32p((rank << 28) | (i << 3) | 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100299 for (j = 0; j < 4; j++)
300 if (((val >> (j * 8)) & 0xff) != pat)
301 ok &= ~(16 << j);
302 }
303 sfence();
304 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800305 write32p((rank << 28) | (i << 2), 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100306 sfence();
307 for (i = 0; i < 64; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -0800308 gav(read32p((rank << 28) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100309
310 return ok;
311}
312
313static void
314program_timings(struct raminfo *info, u16 base, int channel, int slot, int rank)
315{
316 int lane;
317 for (lane = 0; lane < 8; lane++) {
318 write_500(info, channel,
319 base +
320 info->training.
321 lane_timings[2][channel][slot][rank][lane],
322 get_timing_register_addr(lane, 2, slot, rank), 9, 0);
323 write_500(info, channel,
324 base +
325 info->training.
326 lane_timings[3][channel][slot][rank][lane],
327 get_timing_register_addr(lane, 3, slot, rank), 9, 0);
328 }
329}
330
331static void write_26c(int channel, u16 si)
332{
Felix Held04be2dd2018-07-29 04:53:22 +0200333 MCHBAR32(0x26c + (channel << 10)) = 0x03243f35;
334 MCHBAR32(0x268 + (channel << 10)) = 0xcfc00000 | (si << 9);
335 MCHBAR16(0x2b9 + (channel << 10)) = si;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100336}
337
338static u32 get_580(int channel, u8 addr)
339{
340 u32 ret;
341 gav(read_1d0(0x142, 3));
Felix Held04be2dd2018-07-29 04:53:22 +0200342 MCHBAR8(0x5ff) = 0x0;
343 MCHBAR8(0x5ff) = 0x80;
344 MCHBAR32(0x580 + (channel << 10)) = 0x8493c012 | addr;
345 MCHBAR8_OR(0x580 + (channel << 10), 1);
346 while (!((ret = MCHBAR32(0x580 + (channel << 10))) & 0x10000))
347 ;
348 MCHBAR8_AND(0x580 + (channel << 10), ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100349 return ret;
350}
351
352const int cached_config = 0;
353
354#define NUM_CHANNELS 2
355#define NUM_SLOTS 2
356#define NUM_RANKS 2
357#define RANK_SHIFT 28
358#define CHANNEL_SHIFT 10
359
360#include "raminit_tables.c"
361
362static void seq9(struct raminfo *info, int channel, int slot, int rank)
363{
364 int i, lane;
365
366 for (i = 0; i < 2; i++)
367 for (lane = 0; lane < 8; lane++)
368 write_500(info, channel,
369 info->training.lane_timings[i +
370 1][channel][slot]
371 [rank][lane], get_timing_register_addr(lane,
372 i + 1,
373 slot,
374 rank),
375 9, 0);
376
377 write_1d0(1, 0x103, 6, 1);
378 for (lane = 0; lane < 8; lane++)
379 write_500(info, channel,
380 info->training.
381 lane_timings[0][channel][slot][rank][lane],
382 get_timing_register_addr(lane, 0, slot, rank), 9, 0);
383
384 for (i = 0; i < 2; i++) {
385 for (lane = 0; lane < 8; lane++)
386 write_500(info, channel,
387 info->training.lane_timings[i +
388 1][channel][slot]
389 [rank][lane], get_timing_register_addr(lane,
390 i + 1,
391 slot,
392 rank),
393 9, 0);
394 gav(get_580(channel, ((i + 1) << 2) | (rank << 5)));
395 }
396
397 gav(read_1d0(0x142, 3)); // = 0x10408118
Felix Held04be2dd2018-07-29 04:53:22 +0200398 MCHBAR8(0x5ff) = 0x0;
399 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100400 write_1d0(0x2, 0x142, 3, 1);
401 for (lane = 0; lane < 8; lane++) {
402 // printk (BIOS_ERR, "before: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
403 info->training.lane_timings[2][channel][slot][rank][lane] =
404 read_500(info, channel,
405 get_timing_register_addr(lane, 2, slot, rank), 9);
406 //printk (BIOS_ERR, "after: %x\n", info->training.lane_timings[2][channel][slot][rank][lane]);
407 info->training.lane_timings[3][channel][slot][rank][lane] =
408 info->training.lane_timings[2][channel][slot][rank][lane] +
409 0x20;
410 }
411}
412
413static int count_ranks_in_channel(struct raminfo *info, int channel)
414{
415 int slot, rank;
416 int res = 0;
417 for (slot = 0; slot < NUM_SLOTS; slot++)
418 for (rank = 0; rank < NUM_SLOTS; rank++)
419 res += info->populated_ranks[channel][slot][rank];
420 return res;
421}
422
423static void
424config_rank(struct raminfo *info, int s3resume, int channel, int slot, int rank)
425{
426 int add;
427
428 write_1d0(0, 0x178, 7, 1);
429 seq9(info, channel, slot, rank);
430 program_timings(info, 0x80, channel, slot, rank);
431
432 if (channel == 0)
433 add = count_ranks_in_channel(info, 1);
434 else
435 add = 0;
436 if (!s3resume)
437 gav(rw_test(rank + add));
438 program_timings(info, 0x00, channel, slot, rank);
439 if (!s3resume)
440 gav(rw_test(rank + add));
441 if (!s3resume)
442 gav(rw_test(rank + add));
443 write_1d0(0, 0x142, 3, 1);
444 write_1d0(0, 0x103, 6, 1);
445
446 gav(get_580(channel, 0xc | (rank << 5)));
447 gav(read_1d0(0x142, 3));
448
Felix Held04be2dd2018-07-29 04:53:22 +0200449 MCHBAR8(0x5ff) = 0x0;
450 MCHBAR8(0x5ff) = 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100451}
452
453static void set_4cf(struct raminfo *info, int channel, u8 val)
454{
455 gav(read_500(info, channel, 0x4cf, 4)); // = 0xc2300cf9
456 write_500(info, channel, val, 0x4cf, 4, 1);
457 gav(read_500(info, channel, 0x659, 4)); // = 0x80300839
458 write_500(info, channel, val, 0x659, 4, 1);
459 gav(read_500(info, channel, 0x697, 4)); // = 0x80300839
460 write_500(info, channel, val, 0x697, 4, 1);
461}
462
463static void set_334(int zero)
464{
465 int j, k, channel;
466 const u32 val3[] = { 0x2a2b2a2b, 0x26272627, 0x2e2f2e2f, 0x2a2b };
467 u32 vd8[2][16];
468
469 for (channel = 0; channel < NUM_CHANNELS; channel++) {
470 for (j = 0; j < 4; j++) {
471 u32 a = (j == 1) ? 0x29292929 : 0x31313131;
472 u32 lmask = (j == 3) ? 0xffff : 0xffffffff;
473 u16 c;
474 if ((j == 0 || j == 3) && zero)
475 c = 0;
476 else if (j == 3)
477 c = 0x5f;
478 else
479 c = 0x5f5f;
480
481 for (k = 0; k < 2; k++) {
Felix Held04be2dd2018-07-29 04:53:22 +0200482 MCHBAR32(0x138 + 8 * k) =
483 (channel << 26) | (j << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100484 gav(vd8[1][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200485 MCHBAR32(0x138 + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100486 gav(vd8[0][(channel << 3) | (j << 1) | k] =
Felix Held04be2dd2018-07-29 04:53:22 +0200487 MCHBAR32(0x13c + 8 * k));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100488 }
489
Felix Held22ca8cb2018-07-29 05:09:44 +0200490 MCHBAR32(0x334 + (channel << 10) + (j * 0x44)) =
491 zero ? 0 : val3[j];
Felix Held04be2dd2018-07-29 04:53:22 +0200492 MCHBAR32(0x32c + (channel << 10) + (j * 0x44)) =
493 zero ? 0 : (0x18191819 & lmask);
494 MCHBAR16(0x34a + (channel << 10) + (j * 0x44)) = c;
495 MCHBAR32(0x33c + (channel << 10) + (j * 0x44)) =
496 zero ? 0 : (a & lmask);
497 MCHBAR32(0x344 + (channel << 10) + (j * 0x44)) =
498 zero ? 0 : (a & lmask);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100499 }
500 }
501
Felix Held04be2dd2018-07-29 04:53:22 +0200502 MCHBAR32_OR(0x130, 1);
503 while (MCHBAR8(0x130) & 1)
504 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100505}
506
507static void rmw_1d0(u16 addr, u32 and, u32 or, int split, int flag)
508{
509 u32 v;
510 v = read_1d0(addr, split);
511 write_1d0((v & and) | or, addr, split, flag);
512}
513
514static int find_highest_bit_set(u16 val)
515{
516 int i;
517 for (i = 15; i >= 0; i--)
518 if (val & (1 << i))
519 return i;
520 return -1;
521}
522
523static int find_lowest_bit_set32(u32 val)
524{
525 int i;
526 for (i = 0; i < 32; i++)
527 if (val & (1 << i))
528 return i;
529 return -1;
530}
531
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100532enum {
533 DEVICE_TYPE = 2,
534 MODULE_TYPE = 3,
535 DENSITY = 4,
536 RANKS_AND_DQ = 7,
537 MEMORY_BUS_WIDTH = 8,
538 TIMEBASE_DIVIDEND = 10,
539 TIMEBASE_DIVISOR = 11,
540 CYCLETIME = 12,
541
542 CAS_LATENCIES_LSB = 14,
543 CAS_LATENCIES_MSB = 15,
544 CAS_LATENCY_TIME = 16,
545 THERMAL_AND_REFRESH = 31,
546 REFERENCE_RAW_CARD_USED = 62,
547 RANK1_ADDRESS_MAPPING = 63
548};
549
550static void calculate_timings(struct raminfo *info)
551{
552 unsigned cycletime;
553 unsigned cas_latency_time;
554 unsigned supported_cas_latencies;
555 unsigned channel, slot;
556 unsigned clock_speed_index;
557 unsigned min_cas_latency;
558 unsigned cas_latency;
559 unsigned max_clock_index;
560
561 /* Find common CAS latency */
562 supported_cas_latencies = 0x3fe;
563 for (channel = 0; channel < NUM_CHANNELS; channel++)
564 for (slot = 0; slot < NUM_SLOTS; slot++)
565 if (info->populated_ranks[channel][slot][0])
566 supported_cas_latencies &=
567 2 *
568 (info->
569 spd[channel][slot][CAS_LATENCIES_LSB] |
570 (info->
571 spd[channel][slot][CAS_LATENCIES_MSB] <<
572 8));
573
574 max_clock_index = min(3, info->max_supported_clock_speed_index);
575
576 cycletime = min_cycletime[max_clock_index];
577 cas_latency_time = min_cas_latency_time[max_clock_index];
578
579 for (channel = 0; channel < NUM_CHANNELS; channel++)
580 for (slot = 0; slot < NUM_SLOTS; slot++)
581 if (info->populated_ranks[channel][slot][0]) {
582 unsigned timebase;
583 timebase =
584 1000 *
585 info->
586 spd[channel][slot][TIMEBASE_DIVIDEND] /
587 info->spd[channel][slot][TIMEBASE_DIVISOR];
588 cycletime =
589 max(cycletime,
590 timebase *
591 info->spd[channel][slot][CYCLETIME]);
592 cas_latency_time =
593 max(cas_latency_time,
594 timebase *
595 info->
596 spd[channel][slot][CAS_LATENCY_TIME]);
597 }
598 for (clock_speed_index = 0; clock_speed_index < 3; clock_speed_index++) {
599 if (cycletime == min_cycletime[clock_speed_index])
600 break;
601 if (cycletime > min_cycletime[clock_speed_index]) {
602 clock_speed_index--;
603 cycletime = min_cycletime[clock_speed_index];
604 break;
605 }
606 }
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100607 min_cas_latency = DIV_ROUND_UP(cas_latency_time, cycletime);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100608 cas_latency = 0;
609 while (supported_cas_latencies) {
610 cas_latency = find_highest_bit_set(supported_cas_latencies) + 3;
611 if (cas_latency <= min_cas_latency)
612 break;
613 supported_cas_latencies &=
614 ~(1 << find_highest_bit_set(supported_cas_latencies));
615 }
616
617 if (cas_latency != min_cas_latency && clock_speed_index)
618 clock_speed_index--;
619
620 if (cas_latency * min_cycletime[clock_speed_index] > 20000)
621 die("Couldn't configure DRAM");
622 info->clock_speed_index = clock_speed_index;
623 info->cas_latency = cas_latency;
624}
625
626static void program_base_timings(struct raminfo *info)
627{
628 unsigned channel;
629 unsigned slot, rank, lane;
630 unsigned extended_silicon_revision;
631 int i;
632
633 extended_silicon_revision = info->silicon_revision;
634 if (info->silicon_revision == 0)
635 for (channel = 0; channel < NUM_CHANNELS; channel++)
636 for (slot = 0; slot < NUM_SLOTS; slot++)
637 if ((info->
638 spd[channel][slot][MODULE_TYPE] & 0xF) ==
639 3)
640 extended_silicon_revision = 4;
641
642 for (channel = 0; channel < NUM_CHANNELS; channel++) {
643 for (slot = 0; slot < NUM_SLOTS; slot++)
644 for (rank = 0; rank < NUM_SLOTS; rank++) {
645 int card_timing_2;
646 if (!info->populated_ranks[channel][slot][rank])
647 continue;
648
649 for (lane = 0; lane < 9; lane++) {
650 int tm_reg;
651 int card_timing;
652
653 card_timing = 0;
654 if ((info->
655 spd[channel][slot][MODULE_TYPE] &
656 0xF) == 3) {
657 int reference_card;
658 reference_card =
659 info->
660 spd[channel][slot]
661 [REFERENCE_RAW_CARD_USED] &
662 0x1f;
663 if (reference_card == 3)
664 card_timing =
665 u16_ffd1188[0][lane]
666 [info->
667 clock_speed_index];
668 if (reference_card == 5)
669 card_timing =
670 u16_ffd1188[1][lane]
671 [info->
672 clock_speed_index];
673 }
674
675 info->training.
676 lane_timings[0][channel][slot][rank]
677 [lane] =
678 u8_FFFD1218[info->
679 clock_speed_index];
680 info->training.
681 lane_timings[1][channel][slot][rank]
682 [lane] = 256;
683
684 for (tm_reg = 2; tm_reg < 4; tm_reg++)
685 info->training.
686 lane_timings[tm_reg]
687 [channel][slot][rank][lane]
688 =
689 u8_FFFD1240[channel]
690 [extended_silicon_revision]
691 [lane][2 * slot +
692 rank][info->
693 clock_speed_index]
694 + info->max4048[channel]
695 +
696 u8_FFFD0C78[channel]
697 [extended_silicon_revision]
698 [info->
699 mode4030[channel]][slot]
700 [rank][info->
701 clock_speed_index]
702 + card_timing;
703 for (tm_reg = 0; tm_reg < 4; tm_reg++)
704 write_500(info, channel,
705 info->training.
706 lane_timings[tm_reg]
707 [channel][slot][rank]
708 [lane],
709 get_timing_register_addr
710 (lane, tm_reg, slot,
711 rank), 9, 0);
712 }
713
714 card_timing_2 = 0;
715 if (!(extended_silicon_revision != 4
716 || (info->
717 populated_ranks_mask[channel] & 5) ==
718 5)) {
719 if ((info->
720 spd[channel][slot]
721 [REFERENCE_RAW_CARD_USED] & 0x1F)
722 == 3)
723 card_timing_2 =
724 u16_FFFE0EB8[0][info->
725 clock_speed_index];
726 if ((info->
727 spd[channel][slot]
728 [REFERENCE_RAW_CARD_USED] & 0x1F)
729 == 5)
730 card_timing_2 =
731 u16_FFFE0EB8[1][info->
732 clock_speed_index];
733 }
734
735 for (i = 0; i < 3; i++)
736 write_500(info, channel,
737 (card_timing_2 +
738 info->max4048[channel]
739 +
740 u8_FFFD0EF8[channel]
741 [extended_silicon_revision]
742 [info->
743 mode4030[channel]][info->
744 clock_speed_index]),
745 u16_fffd0c50[i][slot][rank],
746 8, 1);
747 write_500(info, channel,
748 (info->max4048[channel] +
749 u8_FFFD0C78[channel]
750 [extended_silicon_revision][info->
751 mode4030
752 [channel]]
753 [slot][rank][info->
754 clock_speed_index]),
755 u16_fffd0c70[slot][rank], 7, 1);
756 }
757 if (!info->populated_ranks_mask[channel])
758 continue;
759 for (i = 0; i < 3; i++)
760 write_500(info, channel,
761 (info->max4048[channel] +
762 info->avg4044[channel]
763 +
764 u8_FFFD17E0[channel]
765 [extended_silicon_revision][info->
766 mode4030
767 [channel]][info->
768 clock_speed_index]),
769 u16_fffd0c68[i], 8, 1);
770 }
771}
772
773static unsigned int fsbcycle_ps(struct raminfo *info)
774{
775 return 900000 / info->fsb_frequency;
776}
777
778/* The time of DDR transfer in ps. */
779static unsigned int halfcycle_ps(struct raminfo *info)
780{
781 return 3750 / (info->clock_speed_index + 3);
782}
783
784/* The time of clock cycle in ps. */
785static unsigned int cycle_ps(struct raminfo *info)
786{
787 return 2 * halfcycle_ps(info);
788}
789
790/* Frequency in 1.(1)=10/9 MHz units. */
791static unsigned frequency_11(struct raminfo *info)
792{
793 return (info->clock_speed_index + 3) * 120;
794}
795
796/* Frequency in 0.1 MHz units. */
797static unsigned frequency_01(struct raminfo *info)
798{
799 return 100 * frequency_11(info) / 9;
800}
801
802static unsigned ps_to_halfcycles(struct raminfo *info, unsigned int ps)
803{
804 return (frequency_11(info) * 2) * ps / 900000;
805}
806
807static unsigned ns_to_cycles(struct raminfo *info, unsigned int ns)
808{
809 return (frequency_11(info)) * ns / 900;
810}
811
812static void compute_derived_timings(struct raminfo *info)
813{
814 unsigned channel, slot, rank;
815 int extended_silicon_revision;
816 int some_delay_1_ps;
817 int some_delay_2_ps;
818 int some_delay_2_halfcycles_ceil;
819 int some_delay_2_halfcycles_floor;
820 int some_delay_3_ps;
821 int some_delay_3_halfcycles;
822 int some_delay_3_ps_rounded;
823 int some_delay_1_cycle_ceil;
824 int some_delay_1_cycle_floor;
825
826 some_delay_3_halfcycles = 0;
827 some_delay_3_ps_rounded = 0;
828 extended_silicon_revision = info->silicon_revision;
829 if (!info->silicon_revision)
830 for (channel = 0; channel < NUM_CHANNELS; channel++)
831 for (slot = 0; slot < NUM_SLOTS; slot++)
832 if ((info->
833 spd[channel][slot][MODULE_TYPE] & 0xF) ==
834 3)
835 extended_silicon_revision = 4;
836 if (info->board_lane_delay[7] < 5)
837 info->board_lane_delay[7] = 5;
838 info->revision_flag_1 = 2;
839 if (info->silicon_revision == 2 || info->silicon_revision == 3)
840 info->revision_flag_1 = 0;
841 if (info->revision < 16)
842 info->revision_flag_1 = 0;
843
844 if (info->revision < 8)
845 info->revision_flag_1 = 0;
846 if (info->revision >= 8 && (info->silicon_revision == 0
847 || info->silicon_revision == 1))
848 some_delay_2_ps = 735;
849 else
850 some_delay_2_ps = 750;
851
852 if (info->revision >= 0x10 && (info->silicon_revision == 0
853 || info->silicon_revision == 1))
854 some_delay_1_ps = 3929;
855 else
856 some_delay_1_ps = 3490;
857
858 some_delay_1_cycle_floor = some_delay_1_ps / cycle_ps(info);
859 some_delay_1_cycle_ceil = some_delay_1_ps / cycle_ps(info);
860 if (some_delay_1_ps % cycle_ps(info))
861 some_delay_1_cycle_ceil++;
862 else
863 some_delay_1_cycle_floor--;
864 info->some_delay_1_cycle_floor = some_delay_1_cycle_floor;
865 if (info->revision_flag_1)
866 some_delay_2_ps = halfcycle_ps(info) >> 6;
867 some_delay_2_ps +=
868 max(some_delay_1_ps - 30,
869 2 * halfcycle_ps(info) * (some_delay_1_cycle_ceil - 1) + 1000) +
870 375;
871 some_delay_3_ps =
872 halfcycle_ps(info) - some_delay_2_ps % halfcycle_ps(info);
873 if (info->revision_flag_1) {
874 if (some_delay_3_ps < 150)
875 some_delay_3_halfcycles = 0;
876 else
877 some_delay_3_halfcycles =
878 (some_delay_3_ps << 6) / halfcycle_ps(info);
879 some_delay_3_ps_rounded =
880 halfcycle_ps(info) * some_delay_3_halfcycles >> 6;
881 }
882 some_delay_2_halfcycles_ceil =
883 (some_delay_2_ps + halfcycle_ps(info) - 1) / halfcycle_ps(info) -
884 2 * (some_delay_1_cycle_ceil - 1);
885 if (info->revision_flag_1 && some_delay_3_ps < 150)
886 some_delay_2_halfcycles_ceil++;
887 some_delay_2_halfcycles_floor = some_delay_2_halfcycles_ceil;
888 if (info->revision < 0x10)
889 some_delay_2_halfcycles_floor =
890 some_delay_2_halfcycles_ceil - 1;
891 if (!info->revision_flag_1)
892 some_delay_2_halfcycles_floor++;
893 info->some_delay_2_halfcycles_ceil = some_delay_2_halfcycles_ceil;
894 info->some_delay_3_ps_rounded = some_delay_3_ps_rounded;
895 if ((info->populated_ranks[0][0][0] && info->populated_ranks[0][1][0])
896 || (info->populated_ranks[1][0][0]
897 && info->populated_ranks[1][1][0]))
898 info->max_slots_used_in_channel = 2;
899 else
900 info->max_slots_used_in_channel = 1;
901 for (channel = 0; channel < 2; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +0200902 MCHBAR32(0x244 + (channel << 10)) =
903 ((info->revision < 8) ? 1 : 0x200) |
904 ((2 - info->max_slots_used_in_channel) << 17) |
905 (channel << 21) |
906 (info->some_delay_1_cycle_floor << 18) | 0x9510;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100907 if (info->max_slots_used_in_channel == 1) {
908 info->mode4030[0] = (count_ranks_in_channel(info, 0) == 2);
909 info->mode4030[1] = (count_ranks_in_channel(info, 1) == 2);
910 } else {
911 info->mode4030[0] = ((count_ranks_in_channel(info, 0) == 1) || (count_ranks_in_channel(info, 0) == 2)) ? 2 : 3; /* 2 if 1 or 2 ranks */
912 info->mode4030[1] = ((count_ranks_in_channel(info, 1) == 1)
913 || (count_ranks_in_channel(info, 1) ==
914 2)) ? 2 : 3;
915 }
916 for (channel = 0; channel < NUM_CHANNELS; channel++) {
917 int max_of_unk;
918 int min_of_unk_2;
919
920 int i, count;
921 int sum;
922
923 if (!info->populated_ranks_mask[channel])
924 continue;
925
926 max_of_unk = 0;
927 min_of_unk_2 = 32767;
928
929 sum = 0;
930 count = 0;
931 for (i = 0; i < 3; i++) {
932 int unk1;
933 if (info->revision < 8)
934 unk1 =
935 u8_FFFD1891[0][channel][info->
936 clock_speed_index]
937 [i];
938 else if (!
939 (info->revision >= 0x10
940 || info->revision_flag_1))
941 unk1 =
942 u8_FFFD1891[1][channel][info->
943 clock_speed_index]
944 [i];
945 else
946 unk1 = 0;
947 for (slot = 0; slot < NUM_SLOTS; slot++)
948 for (rank = 0; rank < NUM_RANKS; rank++) {
949 int a = 0;
950 int b = 0;
951
952 if (!info->
953 populated_ranks[channel][slot]
954 [rank])
955 continue;
956 if (extended_silicon_revision == 4
957 && (info->
958 populated_ranks_mask[channel] &
959 5) != 5) {
960 if ((info->
961 spd[channel][slot]
962 [REFERENCE_RAW_CARD_USED] &
963 0x1F) == 3) {
964 a = u16_ffd1178[0]
965 [info->
966 clock_speed_index];
967 b = u16_fe0eb8[0][info->
968 clock_speed_index];
969 } else
970 if ((info->
971 spd[channel][slot]
972 [REFERENCE_RAW_CARD_USED]
973 & 0x1F) == 5) {
974 a = u16_ffd1178[1]
975 [info->
976 clock_speed_index];
977 b = u16_fe0eb8[1][info->
978 clock_speed_index];
979 }
980 }
981 min_of_unk_2 = min(min_of_unk_2, a);
982 min_of_unk_2 = min(min_of_unk_2, b);
983 if (rank == 0) {
984 sum += a;
985 count++;
986 }
987 {
988 int t;
989 t = b +
990 u8_FFFD0EF8[channel]
991 [extended_silicon_revision]
992 [info->
993 mode4030[channel]][info->
994 clock_speed_index];
995 if (unk1 >= t)
996 max_of_unk =
997 max(max_of_unk,
998 unk1 - t);
999 }
1000 }
1001 {
1002 int t =
1003 u8_FFFD17E0[channel]
1004 [extended_silicon_revision][info->
1005 mode4030
1006 [channel]]
1007 [info->clock_speed_index] + min_of_unk_2;
1008 if (unk1 >= t)
1009 max_of_unk = max(max_of_unk, unk1 - t);
1010 }
1011 }
1012
Jacob Garber64fb4a32019-06-10 17:29:18 -06001013 if (count == 0)
1014 die("No memory ranks found for channel %u\n", channel);
1015
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001016 info->avg4044[channel] = sum / count;
1017 info->max4048[channel] = max_of_unk;
1018 }
1019}
1020
1021static void jedec_read(struct raminfo *info,
1022 int channel, int slot, int rank,
1023 int total_rank, u8 addr3, unsigned int value)
1024{
1025 /* Handle mirrored mapping. */
1026 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
Felix Held04be2dd2018-07-29 04:53:22 +02001027 addr3 = (addr3 & 0xCF) | ((addr3 & 0x10) << 1) |
1028 ((addr3 >> 1) & 0x10);
1029 MCHBAR8(0x271) = addr3 | (MCHBAR8(0x271) & 0xC1);
1030 MCHBAR8(0x671) = addr3 | (MCHBAR8(0x671) & 0xC1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001031
1032 /* Handle mirrored mapping. */
1033 if ((rank & 1) && (info->spd[channel][slot][RANK1_ADDRESS_MAPPING] & 1))
1034 value =
1035 (value & ~0x1f8) | ((value >> 1) & 0xa8) | ((value & 0xa8)
1036 << 1);
1037
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001038 read32p((value << 3) | (total_rank << 28));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001039
Felix Held04be2dd2018-07-29 04:53:22 +02001040 MCHBAR8(0x271) = (MCHBAR8(0x271) & 0xC3) | 2;
1041 MCHBAR8(0x671) = (MCHBAR8(0x671) & 0xC3) | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001042
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001043 read32p(total_rank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001044}
1045
1046enum {
1047 MR1_RZQ12 = 512,
1048 MR1_RZQ2 = 64,
1049 MR1_RZQ4 = 4,
1050 MR1_ODS34OHM = 2
1051};
1052
1053enum {
1054 MR0_BT_INTERLEAVED = 8,
1055 MR0_DLL_RESET_ON = 256
1056};
1057
1058enum {
1059 MR2_RTT_WR_DISABLED = 0,
1060 MR2_RZQ2 = 1 << 10
1061};
1062
1063static void jedec_init(struct raminfo *info)
1064{
1065 int write_recovery;
1066 int channel, slot, rank;
1067 int total_rank;
1068 int dll_on;
1069 int self_refresh_temperature;
1070 int auto_self_refresh;
1071
1072 auto_self_refresh = 1;
1073 self_refresh_temperature = 1;
1074 if (info->board_lane_delay[3] <= 10) {
1075 if (info->board_lane_delay[3] <= 8)
1076 write_recovery = info->board_lane_delay[3] - 4;
1077 else
1078 write_recovery = 5;
1079 } else {
1080 write_recovery = 6;
1081 }
1082 FOR_POPULATED_RANKS {
1083 auto_self_refresh &=
1084 (info->spd[channel][slot][THERMAL_AND_REFRESH] >> 2) & 1;
1085 self_refresh_temperature &=
1086 info->spd[channel][slot][THERMAL_AND_REFRESH] & 1;
1087 }
1088 if (auto_self_refresh == 1)
1089 self_refresh_temperature = 0;
1090
1091 dll_on = ((info->silicon_revision != 2 && info->silicon_revision != 3)
1092 || (info->populated_ranks[0][0][0]
1093 && info->populated_ranks[0][1][0])
1094 || (info->populated_ranks[1][0][0]
1095 && info->populated_ranks[1][1][0]));
1096
1097 total_rank = 0;
1098
1099 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--) {
1100 int rtt, rtt_wr = MR2_RTT_WR_DISABLED;
1101 int rzq_reg58e;
1102
1103 if (info->silicon_revision == 2 || info->silicon_revision == 3) {
1104 rzq_reg58e = 64;
1105 rtt = MR1_RZQ2;
1106 if (info->clock_speed_index != 0) {
1107 rzq_reg58e = 4;
1108 if (info->populated_ranks_mask[channel] == 3)
1109 rtt = MR1_RZQ4;
1110 }
1111 } else {
1112 if ((info->populated_ranks_mask[channel] & 5) == 5) {
1113 rtt = MR1_RZQ12;
1114 rzq_reg58e = 64;
1115 rtt_wr = MR2_RZQ2;
1116 } else {
1117 rzq_reg58e = 4;
1118 rtt = MR1_RZQ4;
1119 }
1120 }
1121
Felix Held04be2dd2018-07-29 04:53:22 +02001122 MCHBAR16(0x588 + (channel << 10)) = 0x0;
1123 MCHBAR16(0x58a + (channel << 10)) = 0x4;
1124 MCHBAR16(0x58c + (channel << 10)) = rtt | MR1_ODS34OHM;
1125 MCHBAR16(0x58e + (channel << 10)) = rzq_reg58e | 0x82;
1126 MCHBAR16(0x590 + (channel << 10)) = 0x1282;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001127
1128 for (slot = 0; slot < NUM_SLOTS; slot++)
1129 for (rank = 0; rank < NUM_RANKS; rank++)
1130 if (info->populated_ranks[channel][slot][rank]) {
1131 jedec_read(info, channel, slot, rank,
1132 total_rank, 0x28,
1133 rtt_wr | (info->
1134 clock_speed_index
1135 << 3)
1136 | (auto_self_refresh << 6) |
1137 (self_refresh_temperature <<
1138 7));
1139 jedec_read(info, channel, slot, rank,
1140 total_rank, 0x38, 0);
1141 jedec_read(info, channel, slot, rank,
1142 total_rank, 0x18,
1143 rtt | MR1_ODS34OHM);
1144 jedec_read(info, channel, slot, rank,
1145 total_rank, 6,
1146 (dll_on << 12) |
1147 (write_recovery << 9)
1148 | ((info->cas_latency - 4) <<
1149 4) | MR0_BT_INTERLEAVED |
1150 MR0_DLL_RESET_ON);
1151 total_rank++;
1152 }
1153 }
1154}
1155
1156static void program_modules_memory_map(struct raminfo *info, int pre_jedec)
1157{
1158 unsigned channel, slot, rank;
1159 unsigned int total_mb[2] = { 0, 0 }; /* total memory per channel in MB */
1160 unsigned int channel_0_non_interleaved;
1161
1162 FOR_ALL_RANKS {
1163 if (info->populated_ranks[channel][slot][rank]) {
1164 total_mb[channel] +=
1165 pre_jedec ? 256 : (256 << info->
1166 density[channel][slot] >> info->
1167 is_x16_module[channel][slot]);
Felix Held04be2dd2018-07-29 04:53:22 +02001168 MCHBAR8(0x208 + rank + 2 * slot + (channel << 10)) =
1169 (pre_jedec ? (1 | ((1 + 1) << 1)) :
1170 (info->is_x16_module[channel][slot] |
1171 ((info->density[channel][slot] + 1) << 1))) |
1172 0x80;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001173 }
Felix Held04be2dd2018-07-29 04:53:22 +02001174 MCHBAR16(0x200 + (channel << 10) + 4 * slot + 2 * rank) =
1175 total_mb[channel] >> 6;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001176 }
1177
1178 info->total_memory_mb = total_mb[0] + total_mb[1];
1179
1180 info->interleaved_part_mb =
1181 pre_jedec ? 0 : 2 * min(total_mb[0], total_mb[1]);
1182 info->non_interleaved_part_mb =
1183 total_mb[0] + total_mb[1] - info->interleaved_part_mb;
1184 channel_0_non_interleaved = total_mb[0] - info->interleaved_part_mb / 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001185 MCHBAR32(0x100) = channel_0_non_interleaved |
1186 (info->non_interleaved_part_mb << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001187 if (!pre_jedec)
Felix Held04be2dd2018-07-29 04:53:22 +02001188 MCHBAR16(0x104) = info->interleaved_part_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001189}
1190
1191static void program_board_delay(struct raminfo *info)
1192{
1193 int cas_latency_shift;
1194 int some_delay_ns;
1195 int some_delay_3_half_cycles;
1196
1197 unsigned channel, i;
1198 int high_multiplier;
1199 int lane_3_delay;
1200 int cas_latency_derived;
1201
1202 high_multiplier = 0;
1203 some_delay_ns = 200;
1204 some_delay_3_half_cycles = 4;
1205 cas_latency_shift = info->silicon_revision == 0
1206 || info->silicon_revision == 1 ? 1 : 0;
1207 if (info->revision < 8) {
1208 some_delay_ns = 600;
1209 cas_latency_shift = 0;
1210 }
1211 {
1212 int speed_bit;
1213 speed_bit =
1214 ((info->clock_speed_index > 1
1215 || (info->silicon_revision != 2
1216 && info->silicon_revision != 3))) ^ (info->revision >=
1217 0x10);
1218 write_500(info, 0, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1219 3, 1);
1220 write_500(info, 1, speed_bit | ((!info->use_ecc) << 1), 0x60e,
1221 3, 1);
1222 if (info->revision >= 0x10 && info->clock_speed_index <= 1
1223 && (info->silicon_revision == 2
1224 || info->silicon_revision == 3))
1225 rmw_1d0(0x116, 5, 2, 4, 1);
1226 }
Felix Held04be2dd2018-07-29 04:53:22 +02001227 MCHBAR32(0x120) = (1 << (info->max_slots_used_in_channel + 28)) |
1228 0x188e7f9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001229
Felix Held04be2dd2018-07-29 04:53:22 +02001230 MCHBAR8(0x124) = info->board_lane_delay[4] +
1231 ((frequency_01(info) + 999) / 1000);
1232 MCHBAR16(0x125) = 0x1360;
1233 MCHBAR8(0x127) = 0x40;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001234 if (info->fsb_frequency < frequency_11(info) / 2) {
1235 unsigned some_delay_2_half_cycles;
1236 high_multiplier = 1;
1237 some_delay_2_half_cycles = ps_to_halfcycles(info,
1238 ((3 *
1239 fsbcycle_ps(info))
1240 >> 1) +
1241 (halfcycle_ps(info)
1242 *
1243 reg178_min[info->
1244 clock_speed_index]
1245 >> 6)
1246 +
1247 4 *
1248 halfcycle_ps(info)
1249 + 2230);
1250 some_delay_3_half_cycles =
1251 min((some_delay_2_half_cycles +
1252 (frequency_11(info) * 2) * (28 -
1253 some_delay_2_half_cycles) /
1254 (frequency_11(info) * 2 -
1255 4 * (info->fsb_frequency))) >> 3, 7);
1256 }
Felix Held22ca8cb2018-07-29 05:09:44 +02001257 if (MCHBAR8(0x2ca9) & 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001258 some_delay_3_half_cycles = 3;
1259 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001260 MCHBAR32_OR(0x220 + (channel << 10), 0x18001117);
1261 MCHBAR32(0x224 + (channel << 10)) =
1262 (info->max_slots_used_in_channel - 1) |
1263 ((info->cas_latency - 5 - info->clock_speed_index)
1264 << 21) | ((info->max_slots_used_in_channel +
1265 info->cas_latency - cas_latency_shift - 4) << 16) |
1266 ((info->cas_latency - cas_latency_shift - 4) << 26) |
1267 ((info->cas_latency - info->clock_speed_index +
1268 info->max_slots_used_in_channel - 6) << 8);
1269 MCHBAR32(0x228 + (channel << 10)) =
1270 info->max_slots_used_in_channel;
1271 MCHBAR8(0x239 + (channel << 10)) = 32;
1272 MCHBAR32(0x248 + (channel << 10)) = (high_multiplier << 24) |
1273 (some_delay_3_half_cycles << 25) | 0x840000;
1274 MCHBAR32(0x278 + (channel << 10)) = 0xc362042;
1275 MCHBAR32(0x27c + (channel << 10)) = 0x8b000062;
1276 MCHBAR32(0x24c + (channel << 10)) =
1277 ((!!info->clock_speed_index) << 17) |
1278 (((2 + info->clock_speed_index -
1279 (!!info->clock_speed_index))) << 12) | 0x10200;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001280
Felix Held04be2dd2018-07-29 04:53:22 +02001281 MCHBAR8(0x267 + (channel << 10)) = 0x4;
1282 MCHBAR16(0x272 + (channel << 10)) = 0x155;
1283 MCHBAR32_AND_OR(0x2bc + (channel << 10), 0xFF000000, 0x707070);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001284
1285 write_500(info, channel,
1286 ((!info->populated_ranks[channel][1][1])
1287 | (!info->populated_ranks[channel][1][0] << 1)
1288 | (!info->populated_ranks[channel][0][1] << 2)
1289 | (!info->populated_ranks[channel][0][0] << 3)),
1290 0x4c9, 4, 1);
1291 }
1292
Felix Held22ca8cb2018-07-29 05:09:44 +02001293 MCHBAR8(0x2c4) = ((1 + (info->clock_speed_index != 0)) << 6) | 0xC;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001294 {
1295 u8 freq_divisor = 2;
1296 if (info->fsb_frequency == frequency_11(info))
1297 freq_divisor = 3;
1298 else if (2 * info->fsb_frequency < 3 * (frequency_11(info) / 2))
1299 freq_divisor = 1;
1300 else
1301 freq_divisor = 2;
Felix Held04be2dd2018-07-29 04:53:22 +02001302 MCHBAR32(0x2c0) = (freq_divisor << 11) | 0x6009c400;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001303 }
1304
1305 if (info->board_lane_delay[3] <= 10) {
1306 if (info->board_lane_delay[3] <= 8)
1307 lane_3_delay = info->board_lane_delay[3];
1308 else
1309 lane_3_delay = 10;
1310 } else {
1311 lane_3_delay = 12;
1312 }
1313 cas_latency_derived = info->cas_latency - info->clock_speed_index + 2;
1314 if (info->clock_speed_index > 1)
1315 cas_latency_derived++;
1316 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02001317 MCHBAR32(0x240 + (channel << 10)) =
1318 ((info->clock_speed_index == 0) * 0x11000) |
1319 0x1002100 | ((2 + info->clock_speed_index) << 4) |
1320 (info->cas_latency - 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001321 write_500(info, channel, (info->clock_speed_index << 1) | 1,
1322 0x609, 6, 1);
1323 write_500(info, channel,
1324 info->clock_speed_index + 2 * info->cas_latency - 7,
1325 0x601, 6, 1);
1326
Felix Held04be2dd2018-07-29 04:53:22 +02001327 MCHBAR32(0x250 + (channel << 10)) =
1328 ((lane_3_delay + info->clock_speed_index + 9) << 6) |
1329 (info->board_lane_delay[7] << 2) |
1330 (info->board_lane_delay[4] << 16) |
1331 (info->board_lane_delay[1] << 25) |
1332 (info->board_lane_delay[1] << 29) | 1;
1333 MCHBAR32(0x254 + (channel << 10)) =
1334 (info->board_lane_delay[1] >> 3) |
1335 ((info->board_lane_delay[8] + 4 * info->use_ecc) << 6) |
1336 0x80 | (info->board_lane_delay[6] << 1) |
1337 (info->board_lane_delay[2] << 28) |
1338 (cas_latency_derived << 16) | 0x4700000;
1339 MCHBAR32(0x258 + (channel << 10)) =
1340 ((info->board_lane_delay[5] + info->clock_speed_index +
1341 9) << 12) | ((info->clock_speed_index -
1342 info->cas_latency + 12) << 8) |
1343 (info->board_lane_delay[2] << 17) |
1344 (info->board_lane_delay[4] << 24) | 0x47;
1345 MCHBAR32(0x25c + (channel << 10)) =
1346 (info->board_lane_delay[1] << 1) |
1347 (info->board_lane_delay[0] << 8) | 0x1da50000;
1348 MCHBAR8(0x264 + (channel << 10)) = 0xff;
1349 MCHBAR8(0x5f8 + (channel << 10)) =
1350 (cas_latency_shift << 3) | info->use_ecc;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001351 }
1352
1353 program_modules_memory_map(info, 1);
1354
Felix Held04be2dd2018-07-29 04:53:22 +02001355 MCHBAR16(0x610) = (min(ns_to_cycles(info, some_delay_ns) / 2, 127) << 9)
1356 | (MCHBAR16(0x610) & 0x1C3) | 0x3C;
1357 MCHBAR16_OR(0x612, 0x100);
1358 MCHBAR16_OR(0x214, 0x3E00);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001359 for (i = 0; i < 8; i++) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001360 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0x80 + 4 * i,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001361 (info->total_memory_mb - 64) | !i | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001362 pci_write_config32(PCI_DEV (QUICKPATH_BUS, 0, 1), 0xc0 + 4 * i, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001363 }
1364}
1365
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001366#define DEFAULT_PCI_MMIO_SIZE 2048
1367#define HOST_BRIDGE PCI_DEVFN(0, 0)
1368
1369static unsigned int get_mmio_size(void)
1370{
1371 const struct device *dev;
1372 const struct northbridge_intel_nehalem_config *cfg = NULL;
1373
Kyösti Mälkkie7377552018-06-21 16:20:55 +03001374 dev = pcidev_path_on_root(HOST_BRIDGE);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001375 if (dev)
1376 cfg = dev->chip_info;
1377
1378 /* If this is zero, it just means devicetree.cb didn't set it */
1379 if (!cfg || cfg->pci_mmio_size == 0)
1380 return DEFAULT_PCI_MMIO_SIZE;
1381 else
1382 return cfg->pci_mmio_size;
1383}
1384
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001385#define BETTER_MEMORY_MAP 0
1386
1387static void program_total_memory_map(struct raminfo *info)
1388{
1389 unsigned int TOM, TOLUD, TOUUD;
1390 unsigned int quickpath_reserved;
1391 unsigned int REMAPbase;
1392 unsigned int uma_base_igd;
1393 unsigned int uma_base_gtt;
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001394 unsigned int mmio_size;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001395 int memory_remap;
1396 unsigned int memory_map[8];
1397 int i;
1398 unsigned int current_limit;
1399 unsigned int tseg_base;
1400 int uma_size_igd = 0, uma_size_gtt = 0;
1401
1402 memset(memory_map, 0, sizeof(memory_map));
1403
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001404 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001405 u16 t = pci_read_config16(NORTHBRIDGE, D0F0_GGC);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001406 gav(t);
1407 const int uma_sizes_gtt[16] =
1408 { 0, 1, 0, 2, 0, 0, 0, 0, 0, 2, 3, 4, 42, 42, 42, 42 };
1409 /* Igd memory */
1410 const int uma_sizes_igd[16] = {
1411 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352,
1412 256, 512
1413 };
1414
1415 uma_size_igd = uma_sizes_igd[(t >> 4) & 0xF];
1416 uma_size_gtt = uma_sizes_gtt[(t >> 8) & 0xF];
1417 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001418
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001419 mmio_size = get_mmio_size();
1420
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001421 TOM = info->total_memory_mb;
1422 if (TOM == 4096)
1423 TOM = 4032;
1424 TOUUD = ALIGN_DOWN(TOM - info->memory_reserved_for_heci_mb, 64);
Patrick Rudolph266a1f72016-06-09 18:13:34 +02001425 TOLUD = ALIGN_DOWN(min(4096 - mmio_size + ALIGN_UP(uma_size_igd + uma_size_gtt, 64)
Elyes HAOUASa342f392018-10-17 10:56:26 +02001426 , TOUUD), 64);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001427 memory_remap = 0;
1428 if (TOUUD - TOLUD > 64) {
1429 memory_remap = 1;
1430 REMAPbase = max(4096, TOUUD);
1431 TOUUD = TOUUD - TOLUD + 4096;
1432 }
1433 if (TOUUD > 4096)
1434 memory_map[2] = TOUUD | 1;
1435 quickpath_reserved = 0;
1436
1437 {
1438 u32 t;
1439
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001440 gav(t = pci_read_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 0x68));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001441 if (t & 0x800)
1442 quickpath_reserved =
1443 (1 << find_lowest_bit_set32(t >> 20));
1444 }
1445 if (memory_remap)
1446 TOUUD -= quickpath_reserved;
1447
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001448 uma_base_igd = TOLUD - uma_size_igd;
1449 uma_base_gtt = uma_base_igd - uma_size_gtt;
1450 tseg_base = ALIGN_DOWN(uma_base_gtt, 64) - (CONFIG_SMM_TSEG_SIZE >> 20);
1451 if (!memory_remap)
1452 tseg_base -= quickpath_reserved;
1453 tseg_base = ALIGN_DOWN(tseg_base, 8);
1454
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001455 pci_write_config16(NORTHBRIDGE, D0F0_TOLUD, TOLUD << 4);
1456 pci_write_config16(NORTHBRIDGE, D0F0_TOM, TOM >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001457 if (memory_remap) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001458 pci_write_config16(NORTHBRIDGE, D0F0_REMAPBASE, REMAPbase >> 6);
1459 pci_write_config16(NORTHBRIDGE, D0F0_REMAPLIMIT, (TOUUD - 64) >> 6);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001460 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001461 pci_write_config16(NORTHBRIDGE, D0F0_TOUUD, TOUUD);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001462
1463 if (info->uma_enabled) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001464 pci_write_config32(NORTHBRIDGE, D0F0_IGD_BASE, uma_base_igd << 20);
1465 pci_write_config32(NORTHBRIDGE, D0F0_GTT_BASE, uma_base_gtt << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001466 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001467 pci_write_config32(NORTHBRIDGE, TSEG, tseg_base << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001468
1469 current_limit = 0;
1470 memory_map[0] = ALIGN_DOWN(uma_base_gtt, 64) | 1;
1471 memory_map[1] = 4096;
1472 for (i = 0; i < ARRAY_SIZE(memory_map); i++) {
1473 current_limit = max(current_limit, memory_map[i] & ~1);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001474 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0x80,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001475 (memory_map[i] & 1) | ALIGN_DOWN(current_limit -
1476 1, 64) | 2);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001477 pci_write_config32(PCI_DEV(QUICKPATH_BUS, 0, 1), 4 * i + 0xc0, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001478 }
1479}
1480
1481static void collect_system_info(struct raminfo *info)
1482{
1483 u32 capid0[3];
1484 int i;
1485 unsigned channel;
1486
1487 /* Wait for some bit, maybe TXT clear. */
Felix Held04be2dd2018-07-29 04:53:22 +02001488 while (!(read8((u8 *)0xfed40000) & (1 << 7)))
1489 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001490
1491 if (!info->heci_bar)
1492 gav(info->heci_bar =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001493 pci_read_config32(HECIDEV, HECIBAR) & 0xFFFFFFF8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001494 if (!info->memory_reserved_for_heci_mb) {
1495 /* Wait for ME to be ready */
1496 intel_early_me_init();
1497 info->memory_reserved_for_heci_mb = intel_early_me_uma_size();
1498 }
1499
1500 for (i = 0; i < 3; i++)
1501 gav(capid0[i] =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001502 pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 | (i << 2)));
1503 gav(info->revision = pci_read_config8(NORTHBRIDGE, PCI_REVISION_ID));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001504 info->max_supported_clock_speed_index = (~capid0[1] & 7);
1505
1506 if ((capid0[1] >> 11) & 1)
1507 info->uma_enabled = 0;
1508 else
1509 gav(info->uma_enabled =
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001510 pci_read_config8(NORTHBRIDGE, D0F0_DEVEN) & 8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001511 /* Unrecognised: [0000:fffd3d2d] 37f81.37f82 ! CPUID: eax: 00000001; ecx: 00000e00 => 00020655.00010800.029ae3ff.bfebfbff */
1512 info->silicon_revision = 0;
1513
1514 if (capid0[2] & 2) {
1515 info->silicon_revision = 0;
1516 info->max_supported_clock_speed_index = 2;
1517 for (channel = 0; channel < NUM_CHANNELS; channel++)
1518 if (info->populated_ranks[channel][0][0]
1519 && (info->spd[channel][0][MODULE_TYPE] & 0xf) ==
1520 3) {
1521 info->silicon_revision = 2;
1522 info->max_supported_clock_speed_index = 1;
1523 }
1524 } else {
1525 switch (((capid0[2] >> 18) & 1) + 2 * ((capid0[1] >> 3) & 1)) {
1526 case 1:
1527 case 2:
1528 info->silicon_revision = 3;
1529 break;
1530 case 3:
1531 info->silicon_revision = 0;
1532 break;
1533 case 0:
1534 info->silicon_revision = 2;
1535 break;
1536 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001537 switch (pci_read_config16(NORTHBRIDGE, PCI_DEVICE_ID)) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001538 case 0x40:
1539 info->silicon_revision = 0;
1540 break;
1541 case 0x48:
1542 info->silicon_revision = 1;
1543 break;
1544 }
1545 }
1546}
1547
1548static void write_training_data(struct raminfo *info)
1549{
1550 int tm, channel, slot, rank, lane;
1551 if (info->revision < 8)
1552 return;
1553
1554 for (tm = 0; tm < 4; tm++)
1555 for (channel = 0; channel < NUM_CHANNELS; channel++)
1556 for (slot = 0; slot < NUM_SLOTS; slot++)
1557 for (rank = 0; rank < NUM_RANKS; rank++)
1558 for (lane = 0; lane < 9; lane++)
1559 write_500(info, channel,
1560 info->
1561 cached_training->
1562 lane_timings[tm]
1563 [channel][slot][rank]
1564 [lane],
1565 get_timing_register_addr
1566 (lane, tm, slot,
1567 rank), 9, 0);
1568 write_1d0(info->cached_training->reg_178, 0x178, 7, 1);
1569 write_1d0(info->cached_training->reg_10b, 0x10b, 6, 1);
1570}
1571
1572static void dump_timings(struct raminfo *info)
1573{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001574 int channel, slot, rank, lane, i;
Arthur Heymansb3282092019-04-14 17:53:28 +02001575 printk(RAM_DEBUG, "Timings:\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001576 FOR_POPULATED_RANKS {
Arthur Heymansb3282092019-04-14 17:53:28 +02001577 printk(RAM_DEBUG, "channel %d, slot %d, rank %d\n", channel,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001578 slot, rank);
1579 for (lane = 0; lane < 9; lane++) {
Arthur Heymansb3282092019-04-14 17:53:28 +02001580 printk(RAM_DEBUG, "lane %d: ", lane);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001581 for (i = 0; i < 4; i++) {
Arthur Heymansb3282092019-04-14 17:53:28 +02001582 printk(RAM_DEBUG, "%x (%x) ",
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001583 read_500(info, channel,
1584 get_timing_register_addr
1585 (lane, i, slot, rank),
1586 9),
1587 info->training.
1588 lane_timings[i][channel][slot][rank]
1589 [lane]);
1590 }
Arthur Heymansb3282092019-04-14 17:53:28 +02001591 printk(RAM_DEBUG, "\n");
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001592 }
1593 }
Arthur Heymansb3282092019-04-14 17:53:28 +02001594 printk(RAM_DEBUG, "[178] = %x (%x)\n", read_1d0(0x178, 7),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001595 info->training.reg_178);
Arthur Heymansb3282092019-04-14 17:53:28 +02001596 printk(RAM_DEBUG, "[10b] = %x (%x)\n", read_1d0(0x10b, 6),
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001597 info->training.reg_10b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001598}
1599
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001600/* Read timings and other registers that need to be restored verbatim and
1601 put them to CBMEM.
1602 */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001603static void save_timings(struct raminfo *info)
1604{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001605 struct ram_training train;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001606 int channel, slot, rank, lane, i;
1607
1608 train = info->training;
1609 FOR_POPULATED_RANKS for (lane = 0; lane < 9; lane++)
1610 for (i = 0; i < 4; i++)
1611 train.lane_timings[i][channel][slot][rank][lane] =
1612 read_500(info, channel,
1613 get_timing_register_addr(lane, i, slot,
1614 rank), 9);
1615 train.reg_178 = read_1d0(0x178, 7);
1616 train.reg_10b = read_1d0(0x10b, 6);
1617
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001618 for (channel = 0; channel < NUM_CHANNELS; channel++) {
1619 u32 reg32;
Felix Held04be2dd2018-07-29 04:53:22 +02001620 reg32 = MCHBAR32((channel << 10) + 0x274);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001621 train.reg274265[channel][0] = reg32 >> 16;
1622 train.reg274265[channel][1] = reg32 & 0xffff;
Felix Held22ca8cb2018-07-29 05:09:44 +02001623 train.reg274265[channel][2] =
1624 MCHBAR16((channel << 10) + 0x265) >> 8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001625 }
Felix Held04be2dd2018-07-29 04:53:22 +02001626 train.reg2ca9_bit0 = MCHBAR8(0x2ca9) & 1;
1627 train.reg_6dc = MCHBAR32(0x6dc);
1628 train.reg_6e8 = MCHBAR32(0x6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001629
Arthur Heymansb3282092019-04-14 17:53:28 +02001630 printk(RAM_SPEW, "[6dc] = %x\n", train.reg_6dc);
1631 printk(RAM_SPEW, "[6e8] = %x\n", train.reg_6e8);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01001632
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001633 /* Save the MRC S3 restore data to cbmem */
Arthur Heymansdc71e252018-01-29 10:14:48 +01001634 mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1635 &train, sizeof(train));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001636}
1637
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001638static const struct ram_training *get_cached_training(void)
1639{
Arthur Heymansdc71e252018-01-29 10:14:48 +01001640 struct region_device rdev;
1641 if (mrc_cache_get_current(MRC_TRAINING_DATA, MRC_CACHE_VERSION,
1642 &rdev))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001643 return 0;
Arthur Heymansdc71e252018-01-29 10:14:48 +01001644 return (void *)rdev_mmap_full(&rdev);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001645}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001646
1647/* FIXME: add timeout. */
1648static void wait_heci_ready(void)
1649{
Felix Held04be2dd2018-07-29 04:53:22 +02001650 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
1651 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001652 write32((DEFAULT_HECIBAR + 0x4),
1653 (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001654}
1655
1656/* FIXME: add timeout. */
1657static void wait_heci_cb_avail(int len)
1658{
1659 union {
1660 struct mei_csr csr;
1661 u32 raw;
1662 } csr;
1663
Felix Held22ca8cb2018-07-29 05:09:44 +02001664 while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
1665 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001666
1667 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001668 csr.raw = read32(DEFAULT_HECIBAR + 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001669 while (len >
1670 csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
Felix Held22ca8cb2018-07-29 05:09:44 +02001671 csr.csr.buffer_read_ptr))
1672 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001673}
1674
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001675static void send_heci_packet(struct mei_header *head, u32 *payload)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001676{
1677 int len = (head->length + 3) / 4;
1678 int i;
1679
1680 wait_heci_cb_avail(len + 1);
1681
1682 /* FIXME: handle leftovers correctly. */
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001683 write32(DEFAULT_HECIBAR + 0, *(u32 *) head);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001684 for (i = 0; i < len - 1; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001685 write32(DEFAULT_HECIBAR + 0, payload[i]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001686
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001687 write32(DEFAULT_HECIBAR + 0, payload[i] & ((1 << (8 * len)) - 1));
1688 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001689}
1690
1691static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001692send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001693{
1694 struct mei_header head;
1695 int maxlen;
1696
1697 wait_heci_ready();
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001698 maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001699
1700 while (len) {
1701 int cur = len;
1702 if (cur > maxlen) {
1703 cur = maxlen;
1704 head.is_complete = 0;
1705 } else
1706 head.is_complete = 1;
1707 head.length = cur;
1708 head.reserved = 0;
1709 head.client_address = clientaddress;
1710 head.host_address = hostaddress;
1711 send_heci_packet(&head, (u32 *) msg);
1712 len -= cur;
1713 msg += cur;
1714 }
1715}
1716
1717/* FIXME: Add timeout. */
1718static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001719recv_heci_packet(struct raminfo *info, struct mei_header *head, u32 *packet,
1720 u32 *packet_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001721{
1722 union {
1723 struct mei_csr csr;
1724 u32 raw;
1725 } csr;
1726 int i = 0;
1727
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001728 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001729 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001730 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001731 }
Felix Held04be2dd2018-07-29 04:53:22 +02001732 while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr)
1733 ;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001734 *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001735 if (!head->length) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001736 write32(DEFAULT_HECIBAR + 0x4,
1737 read32(DEFAULT_HECIBAR + 0x4) | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001738 *packet_size = 0;
1739 return 0;
1740 }
1741 if (head->length + 4 > 4 * csr.csr.buffer_depth
1742 || head->length > *packet_size) {
1743 *packet_size = 0;
1744 return -1;
1745 }
1746
1747 do
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001748 csr.raw = read32(DEFAULT_HECIBAR + 0xc);
Felix Held22ca8cb2018-07-29 05:09:44 +02001749 while (((head->length + 3) >> 2) >
1750 (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr))
1751 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001752
1753 for (i = 0; i < (head->length + 3) >> 2; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001754 packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001755 *packet_size = head->length;
1756 if (!csr.csr.ready)
1757 *packet_size = 0;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001758 write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001759 return 0;
1760}
1761
1762/* FIXME: Add timeout. */
1763static int
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02001764recv_heci_message(struct raminfo *info, u32 *message, u32 *message_size)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001765{
1766 struct mei_header head;
1767 int current_position;
1768
1769 current_position = 0;
1770 while (1) {
1771 u32 current_size;
1772 current_size = *message_size - current_position;
1773 if (recv_heci_packet
1774 (info, &head, message + (current_position >> 2),
1775 &current_size) == -1)
1776 break;
1777 if (!current_size)
1778 break;
1779 current_position += current_size;
1780 if (head.is_complete) {
1781 *message_size = current_position;
1782 return 0;
1783 }
1784
1785 if (current_position >= *message_size)
1786 break;
1787 }
1788 *message_size = 0;
1789 return -1;
1790}
1791
1792static void send_heci_uma_message(struct raminfo *info)
1793{
1794 struct uma_reply {
1795 u8 group_id;
1796 u8 command;
1797 u8 reserved;
1798 u8 result;
1799 u8 field2;
1800 u8 unk3[0x48 - 4 - 1];
Stefan Reinauer6a001132017-07-13 02:20:27 +02001801 } __packed reply;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001802 struct uma_message {
1803 u8 group_id;
1804 u8 cmd;
1805 u8 reserved;
1806 u8 result;
1807 u32 c2;
1808 u64 heci_uma_addr;
1809 u32 memory_reserved_for_heci_mb;
1810 u16 c3;
Stefan Reinauer6a001132017-07-13 02:20:27 +02001811 } __packed msg = {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001812 0, MKHI_SET_UMA, 0, 0,
1813 0x82,
1814 info->heci_uma_addr, info->memory_reserved_for_heci_mb, 0};
1815 u32 reply_size;
1816
1817 send_heci_message((u8 *) & msg, sizeof(msg), 0, 7);
1818
1819 reply_size = sizeof(reply);
1820 if (recv_heci_message(info, (u32 *) & reply, &reply_size) == -1)
1821 return;
1822
1823 if (reply.command != (MKHI_SET_UMA | (1 << 7)))
1824 die("HECI init failed\n");
1825}
1826
1827static void setup_heci_uma(struct raminfo *info)
1828{
1829 u32 reg44;
1830
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001831 reg44 = pci_read_config32(HECIDEV, 0x44); // = 0x80010020
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001832 info->memory_reserved_for_heci_mb = 0;
1833 info->heci_uma_addr = 0;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001834 if (!((reg44 & 0x10000) && !(pci_read_config32(HECIDEV, 0x40) & 0x20)))
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001835 return;
1836
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001837 info->heci_bar = pci_read_config32(HECIDEV, 0x10) & 0xFFFFFFF0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001838 info->memory_reserved_for_heci_mb = reg44 & 0x3f;
1839 info->heci_uma_addr =
1840 ((u64)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001841 ((((u64) pci_read_config16(NORTHBRIDGE, D0F0_TOM)) << 6) -
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001842 info->memory_reserved_for_heci_mb)) << 20;
1843
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001844 pci_read_config32(NORTHBRIDGE, DMIBAR);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001845 if (info->memory_reserved_for_heci_mb) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001846 write32(DEFAULT_DMIBAR + 0x14,
1847 read32(DEFAULT_DMIBAR + 0x14) & ~0x80);
1848 write32(DEFAULT_RCBA + 0x14,
1849 read32(DEFAULT_RCBA + 0x14) & ~0x80);
1850 write32(DEFAULT_DMIBAR + 0x20,
1851 read32(DEFAULT_DMIBAR + 0x20) & ~0x80);
1852 write32(DEFAULT_RCBA + 0x20,
1853 read32(DEFAULT_RCBA + 0x20) & ~0x80);
1854 write32(DEFAULT_DMIBAR + 0x2c,
1855 read32(DEFAULT_DMIBAR + 0x2c) & ~0x80);
1856 write32(DEFAULT_RCBA + 0x30,
1857 read32(DEFAULT_RCBA + 0x30) & ~0x80);
1858 write32(DEFAULT_DMIBAR + 0x38,
1859 read32(DEFAULT_DMIBAR + 0x38) & ~0x80);
1860 write32(DEFAULT_RCBA + 0x40,
1861 read32(DEFAULT_RCBA + 0x40) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001862
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001863 write32(DEFAULT_RCBA + 0x40, 0x87000080); // OK
1864 write32(DEFAULT_DMIBAR + 0x38, 0x87000080); // OK
Felix Held04be2dd2018-07-29 04:53:22 +02001865 while ((read16(DEFAULT_RCBA + 0x46) & 2) &&
1866 read16(DEFAULT_DMIBAR + 0x3e) & 2)
1867 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001868 }
1869
Felix Held04be2dd2018-07-29 04:53:22 +02001870 MCHBAR32(0x24) = 0x10000 + info->memory_reserved_for_heci_mb;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001871
1872 send_heci_uma_message(info);
1873
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001874 pci_write_config32(HECIDEV, 0x10, 0x0);
1875 pci_write_config8(HECIDEV, 0x4, 0x0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001876
1877}
1878
1879static int have_match_ranks(struct raminfo *info, int channel, int ranks)
1880{
1881 int ranks_in_channel;
1882 ranks_in_channel = info->populated_ranks[channel][0][0]
1883 + info->populated_ranks[channel][0][1]
1884 + info->populated_ranks[channel][1][0]
1885 + info->populated_ranks[channel][1][1];
1886
1887 /* empty channel */
1888 if (ranks_in_channel == 0)
1889 return 1;
1890
1891 if (ranks_in_channel != ranks)
1892 return 0;
1893 /* single slot */
1894 if (info->populated_ranks[channel][0][0] !=
1895 info->populated_ranks[channel][1][0])
1896 return 1;
1897 if (info->populated_ranks[channel][0][1] !=
1898 info->populated_ranks[channel][1][1])
1899 return 1;
1900 if (info->is_x16_module[channel][0] != info->is_x16_module[channel][1])
1901 return 0;
1902 if (info->density[channel][0] != info->density[channel][1])
1903 return 0;
1904 return 1;
1905}
1906
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001907static void read_4090(struct raminfo *info)
1908{
1909 int i, channel, slot, rank, lane;
1910 for (i = 0; i < 2; i++)
1911 for (slot = 0; slot < NUM_SLOTS; slot++)
1912 for (rank = 0; rank < NUM_RANKS; rank++)
1913 for (lane = 0; lane < 9; lane++)
1914 info->training.
1915 lane_timings[0][i][slot][rank][lane]
1916 = 32;
1917
1918 for (i = 1; i < 4; i++)
1919 for (channel = 0; channel < NUM_CHANNELS; channel++)
1920 for (slot = 0; slot < NUM_SLOTS; slot++)
1921 for (rank = 0; rank < NUM_RANKS; rank++)
1922 for (lane = 0; lane < 9; lane++) {
1923 info->training.
1924 lane_timings[i][channel]
1925 [slot][rank][lane] =
1926 read_500(info, channel,
1927 get_timing_register_addr
1928 (lane, i, slot,
1929 rank), 9)
1930 + (i == 1) * 11; // !!!!
1931 }
1932
1933}
1934
1935static u32 get_etalon2(int flip, u32 addr)
1936{
1937 const u16 invmask[] = {
1938 0xaaaa, 0x6db6, 0x4924, 0xeeee, 0xcccc, 0x8888, 0x7bde, 0x739c,
1939 0x6318, 0x4210, 0xefbe, 0xcf3c, 0x8e38, 0x0c30, 0x0820
1940 };
1941 u32 ret;
1942 u32 comp4 = addr / 480;
1943 addr %= 480;
1944 u32 comp1 = addr & 0xf;
1945 u32 comp2 = (addr >> 4) & 1;
1946 u32 comp3 = addr >> 5;
1947
1948 if (comp4)
1949 ret = 0x1010101 << (comp4 - 1);
1950 else
1951 ret = 0;
1952 if (flip ^ (((invmask[comp3] >> comp1) ^ comp2) & 1))
1953 ret = ~ret;
1954
1955 return ret;
1956}
1957
1958static void disable_cache(void)
1959{
1960 msr_t msr = {.lo = 0, .hi = 0 };
1961
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001962 wrmsr(MTRR_PHYS_BASE(3), msr);
1963 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001964}
1965
1966static void enable_cache(unsigned int base, unsigned int size)
1967{
1968 msr_t msr;
1969 msr.lo = base | MTRR_TYPE_WRPROT;
1970 msr.hi = 0;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001971 wrmsr(MTRR_PHYS_BASE(3), msr);
1972 msr.lo = ((~(ALIGN_DOWN(size + 4096, 4096) - 1) | MTRR_DEF_TYPE_EN)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001973 & 0xffffffff);
1974 msr.hi = 0x0000000f;
Alexandru Gagniuc86091f92015-09-30 20:23:09 -07001975 wrmsr(MTRR_PHYS_MASK(3), msr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001976}
1977
1978static void flush_cache(u32 start, u32 size)
1979{
1980 u32 end;
1981 u32 addr;
1982
1983 end = start + (ALIGN_DOWN(size + 4096, 4096));
1984 for (addr = start; addr < end; addr += 64)
1985 clflush(addr);
1986}
1987
1988static void clear_errors(void)
1989{
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03001990 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001991}
1992
1993static void write_testing(struct raminfo *info, int totalrank, int flip)
1994{
1995 int nwrites = 0;
1996 /* in 8-byte units. */
1997 u32 offset;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08001998 u8 *base;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01001999
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002000 base = (u8 *)(totalrank << 28);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002001 for (offset = 0; offset < 9 * 480; offset += 2) {
2002 write32(base + offset * 8, get_etalon2(flip, offset));
2003 write32(base + offset * 8 + 4, get_etalon2(flip, offset));
2004 write32(base + offset * 8 + 8, get_etalon2(flip, offset + 1));
2005 write32(base + offset * 8 + 12, get_etalon2(flip, offset + 1));
2006 nwrites += 4;
2007 if (nwrites >= 320) {
2008 clear_errors();
2009 nwrites = 0;
2010 }
2011 }
2012}
2013
2014static u8 check_testing(struct raminfo *info, u8 total_rank, int flip)
2015{
2016 u8 failmask = 0;
2017 int i;
2018 int comp1, comp2, comp3;
2019 u32 failxor[2] = { 0, 0 };
2020
2021 enable_cache((total_rank << 28), 1728 * 5 * 4);
2022
2023 for (comp3 = 0; comp3 < 9 && failmask != 0xff; comp3++) {
2024 for (comp1 = 0; comp1 < 4; comp1++)
2025 for (comp2 = 0; comp2 < 60; comp2++) {
2026 u32 re[4];
2027 u32 curroffset =
2028 comp3 * 8 * 60 + 2 * comp1 + 8 * comp2;
2029 read128((total_rank << 28) | (curroffset << 3),
2030 (u64 *) re);
2031 failxor[0] |=
2032 get_etalon2(flip, curroffset) ^ re[0];
2033 failxor[1] |=
2034 get_etalon2(flip, curroffset) ^ re[1];
2035 failxor[0] |=
2036 get_etalon2(flip, curroffset | 1) ^ re[2];
2037 failxor[1] |=
2038 get_etalon2(flip, curroffset | 1) ^ re[3];
2039 }
2040 for (i = 0; i < 8; i++)
2041 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2042 failmask |= 1 << i;
2043 }
2044 disable_cache();
2045 flush_cache((total_rank << 28), 1728 * 5 * 4);
2046 return failmask;
2047}
2048
2049const u32 seed1[0x18] = {
2050 0x3a9d5ab5, 0x576cb65b, 0x555773b6, 0x2ab772ee,
2051 0x555556ee, 0x3a9d5ab5, 0x576cb65b, 0x555773b6,
2052 0x2ab772ee, 0x555556ee, 0x5155a555, 0x5155a555,
2053 0x5155a555, 0x5155a555, 0x3a9d5ab5, 0x576cb65b,
2054 0x555773b6, 0x2ab772ee, 0x555556ee, 0x55d6b4a5,
2055 0x366d6b3a, 0x2ae5ddbb, 0x3b9ddbb7, 0x55d6b4a5,
2056};
2057
2058static u32 get_seed2(int a, int b)
2059{
2060 const u32 seed2[5] = {
2061 0x55555555, 0x33333333, 0x2e555a55, 0x55555555,
2062 0x5b6db6db,
2063 };
2064 u32 r;
2065 r = seed2[(a + (a >= 10)) / 5];
2066 return b ? ~r : r;
2067}
2068
2069static int make_shift(int comp2, int comp5, int x)
2070{
2071 const u8 seed3[32] = {
2072 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2073 0x00, 0x00, 0x38, 0x1c, 0x3c, 0x18, 0x38, 0x38,
2074 0x38, 0x38, 0x38, 0x38, 0x0f, 0x0f, 0x0f, 0x0f,
2075 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
2076 };
2077
2078 return (comp2 - ((seed3[comp5] >> (x & 7)) & 1)) & 0x1f;
2079}
2080
2081static u32 get_etalon(int flip, u32 addr)
2082{
2083 u32 mask_byte = 0;
2084 int comp1 = (addr >> 1) & 1;
2085 int comp2 = (addr >> 3) & 0x1f;
2086 int comp3 = (addr >> 8) & 0xf;
2087 int comp4 = (addr >> 12) & 0xf;
2088 int comp5 = (addr >> 16) & 0x1f;
2089 u32 mask_bit = ~(0x10001 << comp3);
2090 u32 part1;
2091 u32 part2;
2092 int byte;
2093
2094 part2 =
2095 ((seed1[comp5] >>
2096 make_shift(comp2, comp5,
2097 (comp3 >> 3) | (comp1 << 2) | 2)) & 1) ^ flip;
2098 part1 =
2099 ((seed1[comp5] >>
2100 make_shift(comp2, comp5,
2101 (comp3 >> 3) | (comp1 << 2) | 0)) & 1) ^ flip;
2102
2103 for (byte = 0; byte < 4; byte++)
2104 if ((get_seed2(comp5, comp4) >>
2105 make_shift(comp2, comp5, (byte | (comp1 << 2)))) & 1)
2106 mask_byte |= 0xff << (8 * byte);
2107
2108 return (mask_bit & mask_byte) | (part1 << comp3) | (part2 <<
2109 (comp3 + 16));
2110}
2111
2112static void
2113write_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2114 char flip)
2115{
2116 int i;
2117 for (i = 0; i < 2048; i++)
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002118 write32p((totalrank << 28) | (region << 25) | (block << 16) |
2119 (i << 2), get_etalon(flip, (block << 16) | (i << 2)));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002120}
2121
2122static u8
2123check_testing_type2(struct raminfo *info, u8 totalrank, u8 region, u8 block,
2124 char flip)
2125{
2126 u8 failmask = 0;
2127 u32 failxor[2];
2128 int i;
2129 int comp1, comp2, comp3;
2130
2131 failxor[0] = 0;
2132 failxor[1] = 0;
2133
2134 enable_cache(totalrank << 28, 134217728);
2135 for (comp3 = 0; comp3 < 2 && failmask != 0xff; comp3++) {
2136 for (comp1 = 0; comp1 < 16; comp1++)
2137 for (comp2 = 0; comp2 < 64; comp2++) {
2138 u32 addr =
2139 (totalrank << 28) | (region << 25) | (block
2140 << 16)
2141 | (comp3 << 12) | (comp2 << 6) | (comp1 <<
2142 2);
2143 failxor[comp1 & 1] |=
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08002144 read32p(addr) ^ get_etalon(flip, addr);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002145 }
2146 for (i = 0; i < 8; i++)
2147 if ((0xff << (8 * (i % 4))) & failxor[i / 4])
2148 failmask |= 1 << i;
2149 }
2150 disable_cache();
2151 flush_cache((totalrank << 28) | (region << 25) | (block << 16), 16384);
2152 return failmask;
2153}
2154
2155static int check_bounded(unsigned short *vals, u16 bound)
2156{
2157 int i;
2158
2159 for (i = 0; i < 8; i++)
2160 if (vals[i] < bound)
2161 return 0;
2162 return 1;
2163}
2164
2165enum state {
2166 BEFORE_USABLE = 0, AT_USABLE = 1, AT_MARGIN = 2, COMPLETE = 3
2167};
2168
2169static int validate_state(enum state *in)
2170{
2171 int i;
2172 for (i = 0; i < 8; i++)
2173 if (in[i] != COMPLETE)
2174 return 0;
2175 return 1;
2176}
2177
2178static void
Elyes HAOUASfd051dc2018-07-08 12:39:34 +02002179do_fsm(enum state *state, u16 *counter,
2180 u8 fail_mask, int margin, int uplimit,
2181 u8 *res_low, u8 *res_high, u8 val)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002182{
2183 int lane;
2184
2185 for (lane = 0; lane < 8; lane++) {
2186 int is_fail = (fail_mask >> lane) & 1;
2187 switch (state[lane]) {
2188 case BEFORE_USABLE:
2189 if (!is_fail) {
2190 counter[lane] = 1;
2191 state[lane] = AT_USABLE;
2192 break;
2193 }
2194 counter[lane] = 0;
2195 state[lane] = BEFORE_USABLE;
2196 break;
2197 case AT_USABLE:
2198 if (!is_fail) {
2199 ++counter[lane];
2200 if (counter[lane] >= margin) {
2201 state[lane] = AT_MARGIN;
2202 res_low[lane] = val - margin + 1;
2203 break;
2204 }
2205 state[lane] = 1;
2206 break;
2207 }
2208 counter[lane] = 0;
2209 state[lane] = BEFORE_USABLE;
2210 break;
2211 case AT_MARGIN:
2212 if (is_fail) {
2213 state[lane] = COMPLETE;
2214 res_high[lane] = val - 1;
2215 } else {
2216 counter[lane]++;
2217 state[lane] = AT_MARGIN;
2218 if (val == uplimit) {
2219 state[lane] = COMPLETE;
2220 res_high[lane] = uplimit;
2221 }
2222 }
2223 break;
2224 case COMPLETE:
2225 break;
2226 }
2227 }
2228}
2229
2230static void
2231train_ram_at_178(struct raminfo *info, u8 channel, int slot, int rank,
2232 u8 total_rank, u8 reg_178, int first_run, int niter,
2233 timing_bounds_t * timings)
2234{
2235 int lane;
2236 enum state state[8];
2237 u16 count[8];
2238 u8 lower_usable[8];
2239 u8 upper_usable[8];
Felix Held04be2dd2018-07-29 04:53:22 +02002240 unsigned short num_successfully_checked[8];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002241 u8 reg1b3;
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002242 int i;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002243
Elyes HAOUAS019a2532019-05-25 11:13:43 +02002244 for (i = 0; i < 8; i++)
2245 state[i] = BEFORE_USABLE;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002246
2247 if (!first_run) {
2248 int is_all_ok = 1;
2249 for (lane = 0; lane < 8; lane++)
2250 if (timings[reg_178][channel][slot][rank][lane].
2251 smallest ==
2252 timings[reg_178][channel][slot][rank][lane].
2253 largest) {
2254 timings[reg_178][channel][slot][rank][lane].
2255 smallest = 0;
2256 timings[reg_178][channel][slot][rank][lane].
2257 largest = 0;
2258 is_all_ok = 0;
2259 }
2260 if (is_all_ok) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002261 for (i = 0; i < 8; i++)
2262 state[i] = COMPLETE;
2263 }
2264 }
2265
2266 for (reg1b3 = 0; reg1b3 < 0x30 && !validate_state(state); reg1b3++) {
2267 u8 failmask = 0;
2268 write_1d0(reg1b3 ^ 32, 0x1b3, 6, 1);
2269 write_1d0(reg1b3 ^ 32, 0x1a3, 6, 1);
2270 failmask = check_testing(info, total_rank, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02002271 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002272 do_fsm(state, count, failmask, 5, 47, lower_usable,
2273 upper_usable, reg1b3);
2274 }
2275
2276 if (reg1b3) {
2277 write_1d0(0, 0x1b3, 6, 1);
2278 write_1d0(0, 0x1a3, 6, 1);
2279 for (lane = 0; lane < 8; lane++) {
2280 if (state[lane] == COMPLETE) {
2281 timings[reg_178][channel][slot][rank][lane].
2282 smallest =
2283 lower_usable[lane] +
2284 (info->training.
2285 lane_timings[0][channel][slot][rank][lane]
2286 & 0x3F) - 32;
2287 timings[reg_178][channel][slot][rank][lane].
2288 largest =
2289 upper_usable[lane] +
2290 (info->training.
2291 lane_timings[0][channel][slot][rank][lane]
2292 & 0x3F) - 32;
2293 }
2294 }
2295 }
2296
2297 if (!first_run) {
2298 for (lane = 0; lane < 8; lane++)
2299 if (state[lane] == COMPLETE) {
2300 write_500(info, channel,
2301 timings[reg_178][channel][slot][rank]
2302 [lane].smallest,
2303 get_timing_register_addr(lane, 0,
2304 slot, rank),
2305 9, 1);
2306 write_500(info, channel,
2307 timings[reg_178][channel][slot][rank]
2308 [lane].smallest +
2309 info->training.
2310 lane_timings[1][channel][slot][rank]
2311 [lane]
2312 -
2313 info->training.
2314 lane_timings[0][channel][slot][rank]
2315 [lane], get_timing_register_addr(lane,
2316 1,
2317 slot,
2318 rank),
2319 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002320 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002321 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002322 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002323
2324 do {
2325 u8 failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002326 for (i = 0; i < niter; i++) {
2327 if (failmask == 0xFF)
2328 break;
2329 failmask |=
2330 check_testing_type2(info, total_rank, 2, i,
2331 0);
2332 failmask |=
2333 check_testing_type2(info, total_rank, 3, i,
2334 1);
2335 }
Felix Held04be2dd2018-07-29 04:53:22 +02002336 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002337 for (lane = 0; lane < 8; lane++)
Felix Held04be2dd2018-07-29 04:53:22 +02002338 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002339 if ((1 << lane) & failmask) {
2340 if (timings[reg_178][channel]
2341 [slot][rank][lane].
2342 largest <=
2343 timings[reg_178][channel]
2344 [slot][rank][lane].smallest)
Felix Held04be2dd2018-07-29 04:53:22 +02002345 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002346 [lane] = -1;
2347 else {
Felix Held04be2dd2018-07-29 04:53:22 +02002348 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002349 [lane] = 0;
2350 timings[reg_178]
2351 [channel][slot]
2352 [rank][lane].
2353 smallest++;
2354 write_500(info, channel,
2355 timings
2356 [reg_178]
2357 [channel]
2358 [slot][rank]
2359 [lane].
2360 smallest,
2361 get_timing_register_addr
2362 (lane, 0,
2363 slot, rank),
2364 9, 1);
2365 write_500(info, channel,
2366 timings
2367 [reg_178]
2368 [channel]
2369 [slot][rank]
2370 [lane].
2371 smallest +
2372 info->
2373 training.
2374 lane_timings
2375 [1][channel]
2376 [slot][rank]
2377 [lane]
2378 -
2379 info->
2380 training.
2381 lane_timings
2382 [0][channel]
2383 [slot][rank]
2384 [lane],
2385 get_timing_register_addr
2386 (lane, 1,
2387 slot, rank),
2388 9, 1);
2389 }
2390 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002391 num_successfully_checked[lane]
2392 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002393 }
2394 }
Felix Held04be2dd2018-07-29 04:53:22 +02002395 while (!check_bounded(num_successfully_checked, 2))
2396 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002397
2398 for (lane = 0; lane < 8; lane++)
2399 if (state[lane] == COMPLETE) {
2400 write_500(info, channel,
2401 timings[reg_178][channel][slot][rank]
2402 [lane].largest,
2403 get_timing_register_addr(lane, 0,
2404 slot, rank),
2405 9, 1);
2406 write_500(info, channel,
2407 timings[reg_178][channel][slot][rank]
2408 [lane].largest +
2409 info->training.
2410 lane_timings[1][channel][slot][rank]
2411 [lane]
2412 -
2413 info->training.
2414 lane_timings[0][channel][slot][rank]
2415 [lane], get_timing_register_addr(lane,
2416 1,
2417 slot,
2418 rank),
2419 9, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002420 num_successfully_checked[lane] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002421 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002422 num_successfully_checked[lane] = -1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002423
2424 do {
2425 int failmask = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002426 for (i = 0; i < niter; i++) {
2427 if (failmask == 0xFF)
2428 break;
2429 failmask |=
2430 check_testing_type2(info, total_rank, 2, i,
2431 0);
2432 failmask |=
2433 check_testing_type2(info, total_rank, 3, i,
2434 1);
2435 }
2436
Felix Held04be2dd2018-07-29 04:53:22 +02002437 MCHBAR32_OR(0xfb0, 0x00030000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002438 for (lane = 0; lane < 8; lane++) {
Felix Held04be2dd2018-07-29 04:53:22 +02002439 if (num_successfully_checked[lane] != 0xffff) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002440 if ((1 << lane) & failmask) {
2441 if (timings[reg_178][channel]
2442 [slot][rank][lane].
2443 largest <=
2444 timings[reg_178][channel]
2445 [slot][rank][lane].
2446 smallest) {
Felix Held04be2dd2018-07-29 04:53:22 +02002447 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002448 [lane] = -1;
2449 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02002450 num_successfully_checked
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002451 [lane] = 0;
2452 timings[reg_178]
2453 [channel][slot]
2454 [rank][lane].
2455 largest--;
2456 write_500(info, channel,
2457 timings
2458 [reg_178]
2459 [channel]
2460 [slot][rank]
2461 [lane].
2462 largest,
2463 get_timing_register_addr
2464 (lane, 0,
2465 slot, rank),
2466 9, 1);
2467 write_500(info, channel,
2468 timings
2469 [reg_178]
2470 [channel]
2471 [slot][rank]
2472 [lane].
2473 largest +
2474 info->
2475 training.
2476 lane_timings
2477 [1][channel]
2478 [slot][rank]
2479 [lane]
2480 -
2481 info->
2482 training.
2483 lane_timings
2484 [0][channel]
2485 [slot][rank]
2486 [lane],
2487 get_timing_register_addr
2488 (lane, 1,
2489 slot, rank),
2490 9, 1);
2491 }
2492 } else
Felix Held04be2dd2018-07-29 04:53:22 +02002493 num_successfully_checked[lane]
2494 ++;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002495 }
2496 }
2497 }
Felix Held04be2dd2018-07-29 04:53:22 +02002498 while (!check_bounded(num_successfully_checked, 3))
2499 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002500
2501 for (lane = 0; lane < 8; lane++) {
2502 write_500(info, channel,
2503 info->training.
2504 lane_timings[0][channel][slot][rank][lane],
2505 get_timing_register_addr(lane, 0, slot, rank),
2506 9, 1);
2507 write_500(info, channel,
2508 info->training.
2509 lane_timings[1][channel][slot][rank][lane],
2510 get_timing_register_addr(lane, 1, slot, rank),
2511 9, 1);
2512 if (timings[reg_178][channel][slot][rank][lane].
2513 largest <=
2514 timings[reg_178][channel][slot][rank][lane].
2515 smallest) {
2516 timings[reg_178][channel][slot][rank][lane].
2517 largest = 0;
2518 timings[reg_178][channel][slot][rank][lane].
2519 smallest = 0;
2520 }
2521 }
2522 }
2523}
2524
2525static void set_10b(struct raminfo *info, u8 val)
2526{
2527 int channel;
2528 int slot, rank;
2529 int lane;
2530
2531 if (read_1d0(0x10b, 6) == val)
2532 return;
2533
2534 write_1d0(val, 0x10b, 6, 1);
2535
2536 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 9; lane++) {
2537 u16 reg_500;
2538 reg_500 = read_500(info, channel,
2539 get_timing_register_addr(lane, 0, slot,
2540 rank), 9);
2541 if (val == 1) {
2542 if (lut16[info->clock_speed_index] <= reg_500)
2543 reg_500 -= lut16[info->clock_speed_index];
2544 else
2545 reg_500 = 0;
2546 } else {
2547 reg_500 += lut16[info->clock_speed_index];
2548 }
2549 write_500(info, channel, reg_500,
2550 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
2551 }
2552}
2553
2554static void set_ecc(int onoff)
2555{
2556 int channel;
2557 for (channel = 0; channel < NUM_CHANNELS; channel++) {
2558 u8 t;
Felix Held04be2dd2018-07-29 04:53:22 +02002559 t = MCHBAR8((channel << 10) + 0x5f8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002560 if (onoff)
2561 t |= 1;
2562 else
2563 t &= ~1;
Felix Held04be2dd2018-07-29 04:53:22 +02002564 MCHBAR8((channel << 10) + 0x5f8) = t;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002565 }
2566}
2567
2568static void set_178(u8 val)
2569{
2570 if (val >= 31)
2571 val = val - 31;
2572 else
2573 val = 63 - val;
2574
2575 write_1d0(2 * val, 0x178, 7, 1);
2576}
2577
2578static void
2579write_500_timings_type(struct raminfo *info, int channel, int slot, int rank,
2580 int type)
2581{
2582 int lane;
2583
2584 for (lane = 0; lane < 8; lane++)
2585 write_500(info, channel,
2586 info->training.
2587 lane_timings[type][channel][slot][rank][lane],
2588 get_timing_register_addr(lane, type, slot, rank), 9,
2589 0);
2590}
2591
2592static void
2593try_timing_offsets(struct raminfo *info, int channel,
2594 int slot, int rank, int totalrank)
2595{
2596 u16 count[8];
2597 enum state state[8];
2598 u8 lower_usable[8], upper_usable[8];
2599 int lane;
2600 int i;
2601 int flip = 1;
2602 int timing_offset;
2603
2604 for (i = 0; i < 8; i++)
2605 state[i] = BEFORE_USABLE;
2606
2607 memset(count, 0, sizeof(count));
2608
2609 for (lane = 0; lane < 8; lane++)
2610 write_500(info, channel,
2611 info->training.
2612 lane_timings[2][channel][slot][rank][lane] + 32,
2613 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2614
2615 for (timing_offset = 0; !validate_state(state) && timing_offset < 64;
2616 timing_offset++) {
2617 u8 failmask;
2618 write_1d0(timing_offset ^ 32, 0x1bb, 6, 1);
2619 failmask = 0;
2620 for (i = 0; i < 2 && failmask != 0xff; i++) {
2621 flip = !flip;
2622 write_testing(info, totalrank, flip);
2623 failmask |= check_testing(info, totalrank, flip);
2624 }
2625 do_fsm(state, count, failmask, 10, 63, lower_usable,
2626 upper_usable, timing_offset);
2627 }
2628 write_1d0(0, 0x1bb, 6, 1);
2629 dump_timings(info);
2630 if (!validate_state(state))
2631 die("Couldn't discover DRAM timings (1)\n");
2632
2633 for (lane = 0; lane < 8; lane++) {
2634 u8 bias = 0;
2635
2636 if (info->silicon_revision) {
2637 int usable_length;
2638
2639 usable_length = upper_usable[lane] - lower_usable[lane];
2640 if (usable_length >= 20) {
2641 bias = usable_length / 2 - 10;
2642 if (bias >= 2)
2643 bias = 2;
2644 }
2645 }
2646 write_500(info, channel,
2647 info->training.
2648 lane_timings[2][channel][slot][rank][lane] +
2649 (upper_usable[lane] + lower_usable[lane]) / 2 - bias,
2650 get_timing_register_addr(lane, 3, slot, rank), 9, 1);
2651 info->training.timing2_bounds[channel][slot][rank][lane][0] =
2652 info->training.lane_timings[2][channel][slot][rank][lane] +
2653 lower_usable[lane];
2654 info->training.timing2_bounds[channel][slot][rank][lane][1] =
2655 info->training.lane_timings[2][channel][slot][rank][lane] +
2656 upper_usable[lane];
2657 info->training.timing2_offset[channel][slot][rank][lane] =
2658 info->training.lane_timings[2][channel][slot][rank][lane];
2659 }
2660}
2661
2662static u8
2663choose_training(struct raminfo *info, int channel, int slot, int rank,
2664 int lane, timing_bounds_t * timings, u8 center_178)
2665{
2666 u16 central_weight;
2667 u16 side_weight;
2668 unsigned int sum = 0, count = 0;
2669 u8 span;
2670 u8 lower_margin, upper_margin;
2671 u8 reg_178;
2672 u8 result;
2673
2674 span = 12;
2675 central_weight = 20;
2676 side_weight = 20;
2677 if (info->silicon_revision == 1 && channel == 1) {
2678 central_weight = 5;
2679 side_weight = 20;
2680 if ((info->
2681 populated_ranks_mask[1] ^ (info->
2682 populated_ranks_mask[1] >> 2)) &
2683 1)
2684 span = 18;
2685 }
2686 if ((info->populated_ranks_mask[0] & 5) == 5) {
2687 central_weight = 20;
2688 side_weight = 20;
2689 }
2690 if (info->clock_speed_index >= 2
2691 && (info->populated_ranks_mask[0] & 5) == 5 && slot == 1) {
2692 if (info->silicon_revision == 1) {
2693 switch (channel) {
2694 case 0:
2695 if (lane == 1) {
2696 central_weight = 10;
2697 side_weight = 20;
2698 }
2699 break;
2700 case 1:
2701 if (lane == 6) {
2702 side_weight = 5;
2703 central_weight = 20;
2704 }
2705 break;
2706 }
2707 }
2708 if (info->silicon_revision == 0 && channel == 0 && lane == 0) {
2709 side_weight = 5;
2710 central_weight = 20;
2711 }
2712 }
2713 for (reg_178 = center_178 - span; reg_178 <= center_178 + span;
2714 reg_178 += span) {
2715 u8 smallest;
2716 u8 largest;
2717 largest = timings[reg_178][channel][slot][rank][lane].largest;
2718 smallest = timings[reg_178][channel][slot][rank][lane].smallest;
2719 if (largest - smallest + 1 >= 5) {
2720 unsigned int weight;
2721 if (reg_178 == center_178)
2722 weight = central_weight;
2723 else
2724 weight = side_weight;
2725 sum += weight * (largest + smallest);
2726 count += weight;
2727 }
2728 }
2729 dump_timings(info);
2730 if (count == 0)
2731 die("Couldn't discover DRAM timings (2)\n");
2732 result = sum / (2 * count);
2733 lower_margin =
2734 result - timings[center_178][channel][slot][rank][lane].smallest;
2735 upper_margin =
2736 timings[center_178][channel][slot][rank][lane].largest - result;
2737 if (upper_margin < 10 && lower_margin > 10)
2738 result -= min(lower_margin - 10, 10 - upper_margin);
2739 if (upper_margin > 10 && lower_margin < 10)
2740 result += min(upper_margin - 10, 10 - lower_margin);
2741 return result;
2742}
2743
2744#define STANDARD_MIN_MARGIN 5
2745
2746static u8 choose_reg178(struct raminfo *info, timing_bounds_t * timings)
2747{
2748 u16 margin[64];
2749 int lane, rank, slot, channel;
2750 u8 reg178;
2751 int count = 0, sum = 0;
2752
2753 for (reg178 = reg178_min[info->clock_speed_index];
2754 reg178 < reg178_max[info->clock_speed_index];
2755 reg178 += reg178_step[info->clock_speed_index]) {
2756 margin[reg178] = -1;
2757 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
2758 int curmargin =
2759 timings[reg178][channel][slot][rank][lane].largest -
2760 timings[reg178][channel][slot][rank][lane].
2761 smallest + 1;
2762 if (curmargin < margin[reg178])
2763 margin[reg178] = curmargin;
2764 }
2765 if (margin[reg178] >= STANDARD_MIN_MARGIN) {
2766 u16 weight;
2767 weight = margin[reg178] - STANDARD_MIN_MARGIN;
2768 sum += weight * reg178;
2769 count += weight;
2770 }
2771 }
2772 dump_timings(info);
2773 if (count == 0)
2774 die("Couldn't discover DRAM timings (3)\n");
2775
2776 u8 threshold;
2777
2778 for (threshold = 30; threshold >= 5; threshold--) {
2779 int usable_length = 0;
2780 int smallest_fount = 0;
2781 for (reg178 = reg178_min[info->clock_speed_index];
2782 reg178 < reg178_max[info->clock_speed_index];
2783 reg178 += reg178_step[info->clock_speed_index])
2784 if (margin[reg178] >= threshold) {
2785 usable_length +=
2786 reg178_step[info->clock_speed_index];
2787 info->training.reg178_largest =
2788 reg178 -
2789 2 * reg178_step[info->clock_speed_index];
2790
2791 if (!smallest_fount) {
2792 smallest_fount = 1;
2793 info->training.reg178_smallest =
2794 reg178 +
2795 reg178_step[info->
2796 clock_speed_index];
2797 }
2798 }
2799 if (usable_length >= 0x21)
2800 break;
2801 }
2802
2803 return sum / count;
2804}
2805
2806static int check_cached_sanity(struct raminfo *info)
2807{
2808 int lane;
2809 int slot, rank;
2810 int channel;
2811
2812 if (!info->cached_training)
2813 return 0;
2814
2815 for (channel = 0; channel < NUM_CHANNELS; channel++)
2816 for (slot = 0; slot < NUM_SLOTS; slot++)
2817 for (rank = 0; rank < NUM_RANKS; rank++)
2818 for (lane = 0; lane < 8 + info->use_ecc; lane++) {
2819 u16 cached_value, estimation_value;
2820 cached_value =
2821 info->cached_training->
2822 lane_timings[1][channel][slot][rank]
2823 [lane];
2824 if (cached_value >= 0x18
2825 && cached_value <= 0x1E7) {
2826 estimation_value =
2827 info->training.
2828 lane_timings[1][channel]
2829 [slot][rank][lane];
2830 if (estimation_value <
2831 cached_value - 24)
2832 return 0;
2833 if (estimation_value >
2834 cached_value + 24)
2835 return 0;
2836 }
2837 }
2838 return 1;
2839}
2840
2841static int try_cached_training(struct raminfo *info)
2842{
2843 u8 saved_243[2];
2844 u8 tm;
2845
2846 int channel, slot, rank, lane;
2847 int flip = 1;
2848 int i, j;
2849
2850 if (!check_cached_sanity(info))
2851 return 0;
2852
2853 info->training.reg178_center = info->cached_training->reg178_center;
2854 info->training.reg178_smallest = info->cached_training->reg178_smallest;
2855 info->training.reg178_largest = info->cached_training->reg178_largest;
2856 memcpy(&info->training.timing_bounds,
2857 &info->cached_training->timing_bounds,
2858 sizeof(info->training.timing_bounds));
2859 memcpy(&info->training.timing_offset,
2860 &info->cached_training->timing_offset,
2861 sizeof(info->training.timing_offset));
2862
2863 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002864 saved_243[0] = MCHBAR8(0x243);
2865 saved_243[1] = MCHBAR8(0x643);
2866 MCHBAR8(0x243) = saved_243[0] | 2;
2867 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002868 set_ecc(0);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03002869 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002870 if (read_1d0(0x10b, 6) & 1)
2871 set_10b(info, 0);
2872 for (tm = 0; tm < 2; tm++) {
2873 int totalrank;
2874
2875 set_178(tm ? info->cached_training->reg178_largest : info->
2876 cached_training->reg178_smallest);
2877
2878 totalrank = 0;
2879 /* Check timing ranges. With i == 0 we check smallest one and with
2880 i == 1 the largest bound. With j == 0 we check that on the bound
2881 it still works whereas with j == 1 we check that just outside of
2882 bound we fail.
2883 */
2884 FOR_POPULATED_RANKS_BACKWARDS {
2885 for (i = 0; i < 2; i++) {
2886 for (lane = 0; lane < 8; lane++) {
2887 write_500(info, channel,
2888 info->cached_training->
2889 timing2_bounds[channel][slot]
2890 [rank][lane][i],
2891 get_timing_register_addr(lane,
2892 3,
2893 slot,
2894 rank),
2895 9, 1);
2896
2897 if (!i)
2898 write_500(info, channel,
2899 info->
2900 cached_training->
2901 timing2_offset
2902 [channel][slot][rank]
2903 [lane],
2904 get_timing_register_addr
2905 (lane, 2, slot, rank),
2906 9, 1);
2907 write_500(info, channel,
2908 i ? info->cached_training->
2909 timing_bounds[tm][channel]
2910 [slot][rank][lane].
2911 largest : info->
2912 cached_training->
2913 timing_bounds[tm][channel]
2914 [slot][rank][lane].smallest,
2915 get_timing_register_addr(lane,
2916 0,
2917 slot,
2918 rank),
2919 9, 1);
2920 write_500(info, channel,
2921 info->cached_training->
2922 timing_offset[channel][slot]
2923 [rank][lane] +
2924 (i ? info->cached_training->
2925 timing_bounds[tm][channel]
2926 [slot][rank][lane].
2927 largest : info->
2928 cached_training->
2929 timing_bounds[tm][channel]
2930 [slot][rank][lane].
2931 smallest) - 64,
2932 get_timing_register_addr(lane,
2933 1,
2934 slot,
2935 rank),
2936 9, 1);
2937 }
2938 for (j = 0; j < 2; j++) {
2939 u8 failmask;
2940 u8 expected_failmask;
2941 char reg1b3;
2942
2943 reg1b3 = (j == 1) + 4;
2944 reg1b3 =
2945 j == i ? reg1b3 : (-reg1b3) & 0x3f;
2946 write_1d0(reg1b3, 0x1bb, 6, 1);
2947 write_1d0(reg1b3, 0x1b3, 6, 1);
2948 write_1d0(reg1b3, 0x1a3, 6, 1);
2949
2950 flip = !flip;
2951 write_testing(info, totalrank, flip);
2952 failmask =
2953 check_testing(info, totalrank,
2954 flip);
2955 expected_failmask =
2956 j == 0 ? 0x00 : 0xff;
2957 if (failmask != expected_failmask)
2958 goto fail;
2959 }
2960 }
2961 totalrank++;
2962 }
2963 }
2964
2965 set_178(info->cached_training->reg178_center);
2966 if (info->use_ecc)
2967 set_ecc(1);
2968 write_training_data(info);
2969 write_1d0(0, 322, 3, 1);
2970 info->training = *info->cached_training;
2971
2972 write_1d0(0, 0x1bb, 6, 1);
2973 write_1d0(0, 0x1b3, 6, 1);
2974 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002975 MCHBAR8(0x243) = saved_243[0];
2976 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002977
2978 return 1;
2979
2980fail:
2981 FOR_POPULATED_RANKS {
2982 write_500_timings_type(info, channel, slot, rank, 1);
2983 write_500_timings_type(info, channel, slot, rank, 2);
2984 write_500_timings_type(info, channel, slot, rank, 3);
2985 }
2986
2987 write_1d0(0, 0x1bb, 6, 1);
2988 write_1d0(0, 0x1b3, 6, 1);
2989 write_1d0(0, 0x1a3, 6, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02002990 MCHBAR8(0x243) = saved_243[0];
2991 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01002992
2993 return 0;
2994}
2995
2996static void do_ram_training(struct raminfo *info)
2997{
2998 u8 saved_243[2];
2999 int totalrank = 0;
3000 u8 reg_178;
3001 int niter;
3002
Matthias Gazzaridfa51252018-05-19 00:44:20 +02003003 timing_bounds_t *timings = timings_car;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003004 int lane, rank, slot, channel;
3005 u8 reg178_center;
3006
3007 write_1d0(2, 0x142, 3, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003008 saved_243[0] = MCHBAR8(0x243);
3009 saved_243[1] = MCHBAR8(0x643);
3010 MCHBAR8(0x243) = saved_243[0] | 2;
3011 MCHBAR8(0x643) = saved_243[1] | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003012 switch (info->clock_speed_index) {
3013 case 0:
3014 niter = 5;
3015 break;
3016 case 1:
3017 niter = 10;
3018 break;
3019 default:
3020 niter = 19;
3021 break;
3022 }
3023 set_ecc(0);
3024
3025 FOR_POPULATED_RANKS_BACKWARDS {
3026 int i;
3027
3028 write_500_timings_type(info, channel, slot, rank, 0);
3029
3030 write_testing(info, totalrank, 0);
3031 for (i = 0; i < niter; i++) {
3032 write_testing_type2(info, totalrank, 2, i, 0);
3033 write_testing_type2(info, totalrank, 3, i, 1);
3034 }
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003035 pci_write_config8(NORTHBRIDGE, 0xc0, 0x01);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003036 totalrank++;
3037 }
3038
3039 if (reg178_min[info->clock_speed_index] <
3040 reg178_max[info->clock_speed_index])
3041 memset(timings[reg178_min[info->clock_speed_index]], 0,
3042 sizeof(timings[0]) *
3043 (reg178_max[info->clock_speed_index] -
3044 reg178_min[info->clock_speed_index]));
3045 for (reg_178 = reg178_min[info->clock_speed_index];
3046 reg_178 < reg178_max[info->clock_speed_index];
3047 reg_178 += reg178_step[info->clock_speed_index]) {
3048 totalrank = 0;
3049 set_178(reg_178);
3050 for (channel = NUM_CHANNELS - 1; channel >= 0; channel--)
3051 for (slot = 0; slot < NUM_SLOTS; slot++)
3052 for (rank = 0; rank < NUM_RANKS; rank++) {
3053 memset(&timings[reg_178][channel][slot]
3054 [rank][0].smallest, 0, 16);
3055 if (info->
3056 populated_ranks[channel][slot]
3057 [rank]) {
3058 train_ram_at_178(info, channel,
3059 slot, rank,
3060 totalrank,
3061 reg_178, 1,
3062 niter,
3063 timings);
3064 totalrank++;
3065 }
3066 }
3067 }
3068
3069 reg178_center = choose_reg178(info, timings);
3070
3071 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3072 info->training.timing_bounds[0][channel][slot][rank][lane].
3073 smallest =
3074 timings[info->training.
3075 reg178_smallest][channel][slot][rank][lane].
3076 smallest;
3077 info->training.timing_bounds[0][channel][slot][rank][lane].
3078 largest =
3079 timings[info->training.
3080 reg178_smallest][channel][slot][rank][lane].largest;
3081 info->training.timing_bounds[1][channel][slot][rank][lane].
3082 smallest =
3083 timings[info->training.
3084 reg178_largest][channel][slot][rank][lane].smallest;
3085 info->training.timing_bounds[1][channel][slot][rank][lane].
3086 largest =
3087 timings[info->training.
3088 reg178_largest][channel][slot][rank][lane].largest;
3089 info->training.timing_offset[channel][slot][rank][lane] =
3090 info->training.lane_timings[1][channel][slot][rank][lane]
3091 -
3092 info->training.lane_timings[0][channel][slot][rank][lane] +
3093 64;
3094 }
3095
3096 if (info->silicon_revision == 1
3097 && (info->
3098 populated_ranks_mask[1] ^ (info->
3099 populated_ranks_mask[1] >> 2)) & 1) {
3100 int ranks_after_channel1;
3101
3102 totalrank = 0;
3103 for (reg_178 = reg178_center - 18;
3104 reg_178 <= reg178_center + 18; reg_178 += 18) {
3105 totalrank = 0;
3106 set_178(reg_178);
3107 for (slot = 0; slot < NUM_SLOTS; slot++)
3108 for (rank = 0; rank < NUM_RANKS; rank++) {
3109 if (info->
3110 populated_ranks[1][slot][rank]) {
3111 train_ram_at_178(info, 1, slot,
3112 rank,
3113 totalrank,
3114 reg_178, 0,
3115 niter,
3116 timings);
3117 totalrank++;
3118 }
3119 }
3120 }
3121 ranks_after_channel1 = totalrank;
3122
3123 for (reg_178 = reg178_center - 12;
3124 reg_178 <= reg178_center + 12; reg_178 += 12) {
3125 totalrank = ranks_after_channel1;
3126 set_178(reg_178);
3127 for (slot = 0; slot < NUM_SLOTS; slot++)
3128 for (rank = 0; rank < NUM_RANKS; rank++)
3129 if (info->
3130 populated_ranks[0][slot][rank]) {
3131 train_ram_at_178(info, 0, slot,
3132 rank,
3133 totalrank,
3134 reg_178, 0,
3135 niter,
3136 timings);
3137 totalrank++;
3138 }
3139
3140 }
3141 } else {
3142 for (reg_178 = reg178_center - 12;
3143 reg_178 <= reg178_center + 12; reg_178 += 12) {
3144 totalrank = 0;
3145 set_178(reg_178);
3146 FOR_POPULATED_RANKS_BACKWARDS {
3147 train_ram_at_178(info, channel, slot, rank,
3148 totalrank, reg_178, 0, niter,
3149 timings);
3150 totalrank++;
3151 }
3152 }
3153 }
3154
3155 set_178(reg178_center);
3156 FOR_POPULATED_RANKS_BACKWARDS for (lane = 0; lane < 8; lane++) {
3157 u16 tm0;
3158
3159 tm0 =
3160 choose_training(info, channel, slot, rank, lane, timings,
3161 reg178_center);
3162 write_500(info, channel, tm0,
3163 get_timing_register_addr(lane, 0, slot, rank), 9, 1);
3164 write_500(info, channel,
3165 tm0 +
3166 info->training.
3167 lane_timings[1][channel][slot][rank][lane] -
3168 info->training.
3169 lane_timings[0][channel][slot][rank][lane],
3170 get_timing_register_addr(lane, 1, slot, rank), 9, 1);
3171 }
3172
3173 totalrank = 0;
3174 FOR_POPULATED_RANKS_BACKWARDS {
3175 try_timing_offsets(info, channel, slot, rank, totalrank);
3176 totalrank++;
3177 }
Felix Held04be2dd2018-07-29 04:53:22 +02003178 MCHBAR8(0x243) = saved_243[0];
3179 MCHBAR8(0x643) = saved_243[1];
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003180 write_1d0(0, 0x142, 3, 1);
3181 info->training.reg178_center = reg178_center;
3182}
3183
3184static void ram_training(struct raminfo *info)
3185{
3186 u16 saved_fc4;
3187
Felix Held04be2dd2018-07-29 04:53:22 +02003188 saved_fc4 = MCHBAR16(0xfc4);
3189 MCHBAR16(0xfc4) = 0xffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003190
3191 if (info->revision >= 8)
3192 read_4090(info);
3193
3194 if (!try_cached_training(info))
3195 do_ram_training(info);
3196 if ((info->silicon_revision == 2 || info->silicon_revision == 3)
3197 && info->clock_speed_index < 2)
3198 set_10b(info, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02003199 MCHBAR16(0xfc4) = saved_fc4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003200}
3201
3202static unsigned gcd(unsigned a, unsigned b)
3203{
3204 unsigned t;
3205 if (a > b) {
3206 t = a;
3207 a = b;
3208 b = t;
3209 }
3210 /* invariant a < b. */
3211 while (a) {
3212 t = b % a;
3213 b = a;
3214 a = t;
3215 }
3216 return b;
3217}
3218
3219static inline int div_roundup(int a, int b)
3220{
Elyes HAOUAS6df3b642018-11-26 22:53:49 +01003221 return DIV_ROUND_UP(a, b);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003222}
3223
3224static unsigned lcm(unsigned a, unsigned b)
3225{
3226 return (a * b) / gcd(a, b);
3227}
3228
3229struct stru1 {
3230 u8 freqs_reversed;
3231 u8 freq_diff_reduced;
3232 u8 freq_min_reduced;
3233 u8 divisor_f4_to_fmax;
3234 u8 divisor_f3_to_fmax;
3235 u8 freq4_to_max_remainder;
3236 u8 freq3_to_2_remainder;
3237 u8 freq3_to_2_remaindera;
3238 u8 freq4_to_2_remainder;
3239 int divisor_f3_to_f1, divisor_f4_to_f2;
3240 int common_time_unit_ps;
3241 int freq_max_reduced;
3242};
3243
3244static void
3245compute_frequence_ratios(struct raminfo *info, u16 freq1, u16 freq2,
3246 int num_cycles_2, int num_cycles_1, int round_it,
3247 int add_freqs, struct stru1 *result)
3248{
3249 int g;
3250 int common_time_unit_ps;
3251 int freq1_reduced, freq2_reduced;
3252 int freq_min_reduced;
3253 int freq_max_reduced;
3254 int freq3, freq4;
3255
3256 g = gcd(freq1, freq2);
3257 freq1_reduced = freq1 / g;
3258 freq2_reduced = freq2 / g;
3259 freq_min_reduced = min(freq1_reduced, freq2_reduced);
3260 freq_max_reduced = max(freq1_reduced, freq2_reduced);
3261
3262 common_time_unit_ps = div_roundup(900000, lcm(freq1, freq2));
3263 freq3 = div_roundup(num_cycles_2, common_time_unit_ps) - 1;
3264 freq4 = div_roundup(num_cycles_1, common_time_unit_ps) - 1;
3265 if (add_freqs) {
3266 freq3 += freq2_reduced;
3267 freq4 += freq1_reduced;
3268 }
3269
3270 if (round_it) {
3271 result->freq3_to_2_remainder = 0;
3272 result->freq3_to_2_remaindera = 0;
3273 result->freq4_to_max_remainder = 0;
3274 result->divisor_f4_to_f2 = 0;
3275 result->divisor_f3_to_f1 = 0;
3276 } else {
3277 if (freq2_reduced < freq1_reduced) {
3278 result->freq3_to_2_remainder =
3279 result->freq3_to_2_remaindera =
3280 freq3 % freq1_reduced - freq1_reduced + 1;
3281 result->freq4_to_max_remainder =
3282 -(freq4 % freq1_reduced);
3283 result->divisor_f3_to_f1 = freq3 / freq1_reduced;
3284 result->divisor_f4_to_f2 =
3285 (freq4 -
3286 (freq1_reduced - freq2_reduced)) / freq2_reduced;
3287 result->freq4_to_2_remainder =
3288 -(char)((freq1_reduced - freq2_reduced) +
3289 ((u8) freq4 -
3290 (freq1_reduced -
3291 freq2_reduced)) % (u8) freq2_reduced);
3292 } else {
3293 if (freq2_reduced > freq1_reduced) {
3294 result->freq4_to_max_remainder =
3295 (freq4 % freq2_reduced) - freq2_reduced + 1;
3296 result->freq4_to_2_remainder =
3297 freq4 % freq_max_reduced -
3298 freq_max_reduced + 1;
3299 } else {
3300 result->freq4_to_max_remainder =
3301 -(freq4 % freq2_reduced);
3302 result->freq4_to_2_remainder =
3303 -(char)(freq4 % freq_max_reduced);
3304 }
3305 result->divisor_f4_to_f2 = freq4 / freq2_reduced;
3306 result->divisor_f3_to_f1 =
3307 (freq3 -
3308 (freq2_reduced - freq1_reduced)) / freq1_reduced;
3309 result->freq3_to_2_remainder = -(freq3 % freq2_reduced);
3310 result->freq3_to_2_remaindera =
3311 -(char)((freq_max_reduced - freq_min_reduced) +
3312 (freq3 -
3313 (freq_max_reduced -
3314 freq_min_reduced)) % freq1_reduced);
3315 }
3316 }
3317 result->divisor_f3_to_fmax = freq3 / freq_max_reduced;
3318 result->divisor_f4_to_fmax = freq4 / freq_max_reduced;
3319 if (round_it) {
3320 if (freq2_reduced > freq1_reduced) {
3321 if (freq3 % freq_max_reduced)
3322 result->divisor_f3_to_fmax++;
3323 }
3324 if (freq2_reduced < freq1_reduced) {
3325 if (freq4 % freq_max_reduced)
3326 result->divisor_f4_to_fmax++;
3327 }
3328 }
3329 result->freqs_reversed = (freq2_reduced < freq1_reduced);
3330 result->freq_diff_reduced = freq_max_reduced - freq_min_reduced;
3331 result->freq_min_reduced = freq_min_reduced;
3332 result->common_time_unit_ps = common_time_unit_ps;
3333 result->freq_max_reduced = freq_max_reduced;
3334}
3335
3336static void
3337set_2d5x_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3338 int num_cycles_2, int num_cycles_1, int num_cycles_3,
3339 int num_cycles_4, int reverse)
3340{
3341 struct stru1 vv;
3342 char multiplier;
3343
3344 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3345 0, 1, &vv);
3346
3347 multiplier =
3348 div_roundup(max
3349 (div_roundup(num_cycles_2, vv.common_time_unit_ps) +
3350 div_roundup(num_cycles_3, vv.common_time_unit_ps),
3351 div_roundup(num_cycles_1,
3352 vv.common_time_unit_ps) +
3353 div_roundup(num_cycles_4, vv.common_time_unit_ps))
3354 + vv.freq_min_reduced - 1, vv.freq_max_reduced) - 1;
3355
3356 u32 y =
3357 (u8) ((vv.freq_max_reduced - vv.freq_min_reduced) +
3358 vv.freq_max_reduced * multiplier)
3359 | (vv.
3360 freqs_reversed << 8) | ((u8) (vv.freq_min_reduced *
3361 multiplier) << 16) | ((u8) (vv.
3362 freq_min_reduced
3363 *
3364 multiplier)
3365 << 24);
3366 u32 x =
3367 vv.freq3_to_2_remaindera | (vv.freq4_to_2_remainder << 8) | (vv.
3368 divisor_f3_to_f1
3369 << 16)
3370 | (vv.divisor_f4_to_f2 << 20) | (vv.freq_min_reduced << 24);
3371 if (reverse) {
Felix Held04be2dd2018-07-29 04:53:22 +02003372 MCHBAR32(reg) = y;
3373 MCHBAR32(reg + 4) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003374 } else {
Felix Held04be2dd2018-07-29 04:53:22 +02003375 MCHBAR32(reg + 4) = y;
3376 MCHBAR32(reg) = x;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003377 }
3378}
3379
3380static void
3381set_6d_reg(struct raminfo *info, u16 reg, u16 freq1, u16 freq2,
3382 int num_cycles_1, int num_cycles_2, int num_cycles_3,
3383 int num_cycles_4)
3384{
3385 struct stru1 ratios1;
3386 struct stru1 ratios2;
3387
3388 compute_frequence_ratios(info, freq1, freq2, num_cycles_1, num_cycles_2,
3389 0, 1, &ratios2);
3390 compute_frequence_ratios(info, freq1, freq2, num_cycles_3, num_cycles_4,
3391 0, 1, &ratios1);
Arthur Heymansb3282092019-04-14 17:53:28 +02003392 printk(RAM_SPEW, "[%x] <= %x\n", reg,
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003393 ratios1.freq4_to_max_remainder | (ratios2.
3394 freq4_to_max_remainder
3395 << 8)
3396 | (ratios1.divisor_f4_to_fmax << 16) | (ratios2.
3397 divisor_f4_to_fmax
3398 << 20));
Felix Held04be2dd2018-07-29 04:53:22 +02003399 MCHBAR32(reg) = ratios1.freq4_to_max_remainder |
3400 (ratios2.freq4_to_max_remainder << 8) |
3401 (ratios1.divisor_f4_to_fmax << 16) |
3402 (ratios2.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003403}
3404
3405static void
3406set_2dx8_reg(struct raminfo *info, u16 reg, u8 mode, u16 freq1, u16 freq2,
3407 int num_cycles_2, int num_cycles_1, int round_it, int add_freqs)
3408{
3409 struct stru1 ratios;
3410
3411 compute_frequence_ratios(info, freq1, freq2, num_cycles_2, num_cycles_1,
3412 round_it, add_freqs, &ratios);
3413 switch (mode) {
3414 case 0:
Felix Held04be2dd2018-07-29 04:53:22 +02003415 MCHBAR32(reg + 4) = ratios.freq_diff_reduced |
3416 (ratios.freqs_reversed << 8);
3417 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3418 (ratios.freq4_to_max_remainder << 8) |
3419 (ratios.divisor_f3_to_fmax << 16) |
3420 (ratios.divisor_f4_to_fmax << 20) |
3421 (ratios.freq_min_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003422 break;
3423
3424 case 1:
Felix Held04be2dd2018-07-29 04:53:22 +02003425 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3426 (ratios.divisor_f3_to_fmax << 16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003427 break;
3428
3429 case 2:
Felix Held04be2dd2018-07-29 04:53:22 +02003430 MCHBAR32(reg) = ratios.freq3_to_2_remainder |
3431 (ratios.freq4_to_max_remainder << 8) |
3432 (ratios.divisor_f3_to_fmax << 16) |
3433 (ratios.divisor_f4_to_fmax << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003434 break;
3435
3436 case 4:
Felix Held04be2dd2018-07-29 04:53:22 +02003437 MCHBAR32(reg) = (ratios.divisor_f3_to_fmax << 4) |
3438 (ratios.divisor_f4_to_fmax << 8) |
3439 (ratios.freqs_reversed << 12) |
3440 (ratios.freq_min_reduced << 16) |
3441 (ratios.freq_diff_reduced << 24);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003442 break;
3443 }
3444}
3445
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003446static void set_2dxx_series(struct raminfo *info, int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003447{
3448 set_2dx8_reg(info, 0x2d00, 0, 0x78, frequency_11(info) / 2, 1359, 1005,
3449 0, 1);
3450 set_2dx8_reg(info, 0x2d08, 0, 0x78, 0x78, 3273, 5033, 1, 1);
3451 set_2dx8_reg(info, 0x2d10, 0, 0x78, info->fsb_frequency, 1475, 1131, 0,
3452 1);
3453 set_2dx8_reg(info, 0x2d18, 0, 2 * info->fsb_frequency,
3454 frequency_11(info), 1231, 1524, 0, 1);
3455 set_2dx8_reg(info, 0x2d20, 0, 2 * info->fsb_frequency,
3456 frequency_11(info) / 2, 1278, 2008, 0, 1);
3457 set_2dx8_reg(info, 0x2d28, 0, info->fsb_frequency, frequency_11(info),
3458 1167, 1539, 0, 1);
3459 set_2dx8_reg(info, 0x2d30, 0, info->fsb_frequency,
3460 frequency_11(info) / 2, 1403, 1318, 0, 1);
3461 set_2dx8_reg(info, 0x2d38, 0, info->fsb_frequency, 0x78, 3460, 5363, 1,
3462 1);
3463 set_2dx8_reg(info, 0x2d40, 0, info->fsb_frequency, 0x3c, 2792, 5178, 1,
3464 1);
3465 set_2dx8_reg(info, 0x2d48, 0, 2 * info->fsb_frequency, 0x78, 2738, 4610,
3466 1, 1);
3467 set_2dx8_reg(info, 0x2d50, 0, info->fsb_frequency, 0x78, 2819, 5932, 1,
3468 1);
3469 set_2dx8_reg(info, 0x6d4, 1, info->fsb_frequency,
3470 frequency_11(info) / 2, 4000, 0, 0, 0);
3471 set_2dx8_reg(info, 0x6d8, 2, info->fsb_frequency,
3472 frequency_11(info) / 2, 4000, 4000, 0, 0);
3473
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003474 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003475 printk(RAM_SPEW, "[6dc] <= %x\n",
3476 info->cached_training->reg_6dc);
Felix Held04be2dd2018-07-29 04:53:22 +02003477 MCHBAR32(0x6dc) = info->cached_training->reg_6dc;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003478 } else
3479 set_6d_reg(info, 0x6dc, 2 * info->fsb_frequency, frequency_11(info), 0,
3480 info->delay46_ps[0], 0,
3481 info->delay54_ps[0]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003482 set_2dx8_reg(info, 0x6e0, 1, 2 * info->fsb_frequency,
3483 frequency_11(info), 2500, 0, 0, 0);
3484 set_2dx8_reg(info, 0x6e4, 1, 2 * info->fsb_frequency,
3485 frequency_11(info) / 2, 3500, 0, 0, 0);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003486 if (s3resume) {
Arthur Heymansb3282092019-04-14 17:53:28 +02003487 printk(RAM_SPEW, "[6e8] <= %x\n",
3488 info->cached_training->reg_6e8);
Felix Held04be2dd2018-07-29 04:53:22 +02003489 MCHBAR32(0x6e8) = info->cached_training->reg_6e8;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003490 } else
3491 set_6d_reg(info, 0x6e8, 2 * info->fsb_frequency, frequency_11(info), 0,
3492 info->delay46_ps[1], 0,
3493 info->delay54_ps[1]);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003494 set_2d5x_reg(info, 0x2d58, 0x78, 0x78, 864, 1195, 762, 786, 0);
3495 set_2d5x_reg(info, 0x2d60, 0x195, info->fsb_frequency, 1352, 725, 455,
3496 470, 0);
3497 set_2d5x_reg(info, 0x2d68, 0x195, 0x3c, 2707, 5632, 3277, 2207, 0);
3498 set_2d5x_reg(info, 0x2d70, 0x195, frequency_11(info) / 2, 1276, 758,
3499 454, 459, 0);
3500 set_2d5x_reg(info, 0x2d78, 0x195, 0x78, 1021, 799, 510, 513, 0);
3501 set_2d5x_reg(info, 0x2d80, info->fsb_frequency, 0xe1, 0, 2862, 2579,
3502 2588, 0);
3503 set_2d5x_reg(info, 0x2d88, info->fsb_frequency, 0xe1, 0, 2690, 2405,
3504 2405, 0);
3505 set_2d5x_reg(info, 0x2da0, 0x78, 0xe1, 0, 2560, 2264, 2251, 0);
3506 set_2d5x_reg(info, 0x2da8, 0x195, frequency_11(info), 1060, 775, 484,
3507 480, 0);
3508 set_2d5x_reg(info, 0x2db0, 0x195, 0x78, 4183, 6023, 2217, 2048, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02003509 MCHBAR32(0x2dbc) = ((frequency_11(info) / 2) - 1) | 0xe00000;
3510 MCHBAR32(0x2db8) = ((info->fsb_frequency - 1) << 16) | 0x77;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003511}
3512
3513static u16 get_max_timing(struct raminfo *info, int channel)
3514{
3515 int slot, rank, lane;
3516 u16 ret = 0;
3517
Felix Held04be2dd2018-07-29 04:53:22 +02003518 if ((MCHBAR8(0x2ca8) >> 2) < 1)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003519 return 384;
3520
3521 if (info->revision < 8)
3522 return 256;
3523
3524 for (slot = 0; slot < NUM_SLOTS; slot++)
3525 for (rank = 0; rank < NUM_RANKS; rank++)
3526 if (info->populated_ranks[channel][slot][rank])
3527 for (lane = 0; lane < 8 + info->use_ecc; lane++)
3528 ret = max(ret, read_500(info, channel,
3529 get_timing_register_addr
3530 (lane, 0, slot,
3531 rank), 9));
3532 return ret;
3533}
3534
3535static void set_274265(struct raminfo *info)
3536{
3537 int delay_a_ps, delay_b_ps, delay_c_ps, delay_d_ps;
3538 int delay_e_ps, delay_e_cycles, delay_f_cycles;
3539 int delay_e_over_cycle_ps;
3540 int cycletime_ps;
3541 int channel;
3542
3543 delay_a_ps = 4 * halfcycle_ps(info) + 6 * fsbcycle_ps(info);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003544 info->training.reg2ca9_bit0 = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003545 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3546 cycletime_ps =
3547 900000 / lcm(2 * info->fsb_frequency, frequency_11(info));
3548 delay_d_ps =
3549 (halfcycle_ps(info) * get_max_timing(info, channel) >> 6)
3550 - info->some_delay_3_ps_rounded + 200;
3551 if (!
3552 ((info->silicon_revision == 0
3553 || info->silicon_revision == 1)
3554 && (info->revision >= 8)))
3555 delay_d_ps += halfcycle_ps(info) * 2;
3556 delay_d_ps +=
3557 halfcycle_ps(info) * (!info->revision_flag_1 +
3558 info->some_delay_2_halfcycles_ceil +
3559 2 * info->some_delay_1_cycle_floor +
3560 info->clock_speed_index +
3561 2 * info->cas_latency - 7 + 11);
3562 delay_d_ps += info->revision >= 8 ? 2758 : 4428;
3563
Felix Held04be2dd2018-07-29 04:53:22 +02003564 MCHBAR32_AND_OR(0x140, 0xfaffffff, 0x2000000);
3565 MCHBAR32_AND_OR(0x138, 0xfaffffff, 0x2000000);
3566 if ((MCHBAR8(0x144) & 0x1f) > 0x13)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003567 delay_d_ps += 650;
3568 delay_c_ps = delay_d_ps + 1800;
3569 if (delay_c_ps <= delay_a_ps)
3570 delay_e_ps = 0;
3571 else
3572 delay_e_ps =
3573 cycletime_ps * div_roundup(delay_c_ps - delay_a_ps,
3574 cycletime_ps);
3575
3576 delay_e_over_cycle_ps = delay_e_ps % (2 * halfcycle_ps(info));
3577 delay_e_cycles = delay_e_ps / (2 * halfcycle_ps(info));
3578 delay_f_cycles =
3579 div_roundup(2500 - delay_e_over_cycle_ps,
3580 2 * halfcycle_ps(info));
3581 if (delay_f_cycles > delay_e_cycles) {
3582 info->delay46_ps[channel] = delay_e_ps;
3583 delay_e_cycles = 0;
3584 } else {
3585 info->delay46_ps[channel] =
3586 delay_e_over_cycle_ps +
3587 2 * halfcycle_ps(info) * delay_f_cycles;
3588 delay_e_cycles -= delay_f_cycles;
3589 }
3590
3591 if (info->delay46_ps[channel] < 2500) {
3592 info->delay46_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003593 info->training.reg2ca9_bit0 = 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003594 }
3595 delay_b_ps = halfcycle_ps(info) + delay_c_ps;
3596 if (delay_b_ps <= delay_a_ps)
3597 delay_b_ps = 0;
3598 else
3599 delay_b_ps -= delay_a_ps;
3600 info->delay54_ps[channel] =
3601 cycletime_ps * div_roundup(delay_b_ps,
3602 cycletime_ps) -
3603 2 * halfcycle_ps(info) * delay_e_cycles;
3604 if (info->delay54_ps[channel] < 2500)
3605 info->delay54_ps[channel] = 2500;
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003606 info->training.reg274265[channel][0] = delay_e_cycles;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003607 if (delay_d_ps + 7 * halfcycle_ps(info) <=
3608 24 * halfcycle_ps(info))
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003609 info->training.reg274265[channel][1] = 0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003610 else
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003611 info->training.reg274265[channel][1] =
Felix Held04be2dd2018-07-29 04:53:22 +02003612 div_roundup(delay_d_ps + 7 * halfcycle_ps(info),
3613 4 * halfcycle_ps(info)) - 6;
3614 MCHBAR32((channel << 10) + 0x274) =
3615 info->training.reg274265[channel][1] |
3616 (info->training.reg274265[channel][0] << 16);
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003617 info->training.reg274265[channel][2] =
Felix Held04be2dd2018-07-29 04:53:22 +02003618 div_roundup(delay_c_ps + 3 * fsbcycle_ps(info),
3619 4 * halfcycle_ps(info)) + 1;
3620 MCHBAR16((channel << 10) + 0x265) =
3621 info->training.reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003622 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003623 if (info->training.reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003624 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003625 else
Felix Held04be2dd2018-07-29 04:53:22 +02003626 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003627}
3628
3629static void restore_274265(struct raminfo *info)
3630{
3631 int channel;
3632
3633 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held22ca8cb2018-07-29 05:09:44 +02003634 MCHBAR32((channel << 10) + 0x274) =
3635 (info->cached_training->reg274265[channel][0] << 16) |
3636 info->cached_training->reg274265[channel][1];
3637 MCHBAR16((channel << 10) + 0x265) =
3638 info->cached_training->reg274265[channel][2] << 8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003639 }
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01003640 if (info->cached_training->reg2ca9_bit0)
Felix Held04be2dd2018-07-29 04:53:22 +02003641 MCHBAR8_OR(0x2ca9, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003642 else
Felix Held04be2dd2018-07-29 04:53:22 +02003643 MCHBAR8_AND(0x2ca9, ~1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003644}
3645
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003646static void dmi_setup(void)
3647{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003648 gav(read8(DEFAULT_DMIBAR + 0x254));
3649 write8(DEFAULT_DMIBAR + 0x254, 0x1);
3650 write16(DEFAULT_DMIBAR + 0x1b8, 0x18f2);
Felix Heldf83d80b2018-07-29 05:30:30 +02003651 MCHBAR16_AND_OR(0x48, 0, 0x2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003652
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003653 write32(DEFAULT_DMIBAR + 0xd68, read32(DEFAULT_DMIBAR + 0xd68) | 0x08000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003654
3655 outl((gav(inl(DEFAULT_GPIOBASE | 0x38)) & ~0x140000) | 0x400000,
3656 DEFAULT_GPIOBASE | 0x38);
3657 gav(inb(DEFAULT_GPIOBASE | 0xe)); // = 0xfdcaff6e
3658}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003659
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003660void chipset_init(const int s3resume)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003661{
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003662 u8 x2ca8;
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003663 u16 ggc;
3664 u8 gfxsize;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003665
Felix Held04be2dd2018-07-29 04:53:22 +02003666 x2ca8 = MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003667 if ((x2ca8 & 1) || (x2ca8 == 8 && !s3resume)) {
3668 printk(BIOS_DEBUG, "soft reset detected, rebooting properly\n");
Felix Held04be2dd2018-07-29 04:53:22 +02003669 MCHBAR8(0x2ca8) = 0;
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003670 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003671 }
Felix Held29a9c072018-07-29 01:34:45 +02003672#if 0
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003673 if (!s3resume) {
3674 pre_raminit_3(x2ca8);
3675 }
Vladimir Serbinenkof62669c2014-01-09 10:59:38 +01003676 pre_raminit_4a(x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003677#endif
3678
3679 dmi_setup();
3680
Felix Held04be2dd2018-07-29 04:53:22 +02003681 MCHBAR16(0x1170) = 0xa880;
3682 MCHBAR8(0x11c1) = 0x1;
3683 MCHBAR16(0x1170) = 0xb880;
Felix Heldf83d80b2018-07-29 05:30:30 +02003684 MCHBAR8_AND_OR(0x1210, 0, 0x84);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003685
Vladimir Serbinenko55391c42014-08-03 14:51:00 +02003686 if (get_option(&gfxsize, "gfx_uma_size") != CB_SUCCESS) {
3687 /* 0 for 32MB */
3688 gfxsize = 0;
3689 }
3690
3691 ggc = 0xb00 | ((gfxsize + 5) << 4);
3692
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003693 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc | 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003694
3695 u16 deven;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003696 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN); // = 0x3
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003697
3698 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02003699 MCHBAR8(0x2c30) = 0x20;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003700 pci_read_config8(NORTHBRIDGE, 0x8); // = 0x18
Felix Held04be2dd2018-07-29 04:53:22 +02003701 MCHBAR16_OR(0x2c30, 0x200);
3702 MCHBAR16(0x2c32) = 0x434;
Felix Heldf83d80b2018-07-29 05:30:30 +02003703 MCHBAR32_AND_OR(0x2c44, 0, 0x1053687);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003704 pci_read_config8(GMA, 0x62); // = 0x2
3705 pci_write_config8(GMA, 0x62, 0x2);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003706 read8(DEFAULT_RCBA + 0x2318);
3707 write8(DEFAULT_RCBA + 0x2318, 0x47);
3708 read8(DEFAULT_RCBA + 0x2320);
3709 write8(DEFAULT_RCBA + 0x2320, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003710 }
3711
Felix Heldf83d80b2018-07-29 05:30:30 +02003712 MCHBAR32_AND_OR(0x30, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003713
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003714 pci_write_config16(NORTHBRIDGE, D0F0_GGC, ggc);
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08003715 gav(read32(DEFAULT_RCBA + 0x3428));
3716 write32(DEFAULT_RCBA + 0x3428, 0x1d);
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003717}
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003718
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003719void raminit(const int s3resume, const u8 *spd_addrmap)
3720{
3721 unsigned channel, slot, lane, rank;
3722 int i;
3723 struct raminfo info;
3724 u8 x2ca8;
3725 u16 deven;
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02003726 int cbmem_wasnot_inited;
Vladimir Serbinenko9817a372014-02-19 22:07:12 +01003727
Felix Held04be2dd2018-07-29 04:53:22 +02003728 x2ca8 = MCHBAR8(0x2ca8);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003729 deven = pci_read_config16(NORTHBRIDGE, D0F0_DEVEN);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003730
3731 memset(&info, 0x5a, sizeof(info));
3732
3733 info.last_500_command[0] = 0;
3734 info.last_500_command[1] = 0;
3735
3736 info.fsb_frequency = 135 * 2;
3737 info.board_lane_delay[0] = 0x14;
3738 info.board_lane_delay[1] = 0x07;
3739 info.board_lane_delay[2] = 0x07;
3740 info.board_lane_delay[3] = 0x08;
3741 info.board_lane_delay[4] = 0x56;
3742 info.board_lane_delay[5] = 0x04;
3743 info.board_lane_delay[6] = 0x04;
3744 info.board_lane_delay[7] = 0x05;
3745 info.board_lane_delay[8] = 0x10;
3746
3747 info.training.reg_178 = 0;
3748 info.training.reg_10b = 0;
3749
3750 info.heci_bar = 0;
3751 info.memory_reserved_for_heci_mb = 0;
3752
3753 /* before SPD */
3754 timestamp_add_now(101);
3755
Felix Held29a9c072018-07-29 01:34:45 +02003756 if (!s3resume || 1) { // possible error
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003757 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2); // = 0x80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003758
3759 collect_system_info(&info);
3760
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003761 /* Enable SMBUS. */
3762 enable_smbus();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003763
3764 memset(&info.populated_ranks, 0, sizeof(info.populated_ranks));
3765
3766 info.use_ecc = 1;
3767 for (channel = 0; channel < NUM_CHANNELS; channel++)
Vladimir Serbinenko2ab8ec72014-02-20 14:34:56 +01003768 for (slot = 0; slot < NUM_SLOTS; slot++) {
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003769 int v;
3770 int try;
3771 int addr;
3772 const u8 useful_addresses[] = {
3773 DEVICE_TYPE,
3774 MODULE_TYPE,
3775 DENSITY,
3776 RANKS_AND_DQ,
3777 MEMORY_BUS_WIDTH,
3778 TIMEBASE_DIVIDEND,
3779 TIMEBASE_DIVISOR,
3780 CYCLETIME,
3781 CAS_LATENCIES_LSB,
3782 CAS_LATENCIES_MSB,
3783 CAS_LATENCY_TIME,
3784 0x11, 0x12, 0x13, 0x14, 0x15,
3785 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
3786 0x1c, 0x1d,
3787 THERMAL_AND_REFRESH,
3788 0x20,
3789 REFERENCE_RAW_CARD_USED,
3790 RANK1_ADDRESS_MAPPING,
3791 0x75, 0x76, 0x77, 0x78,
3792 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
3793 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
3794 0x85, 0x86, 0x87, 0x88,
3795 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
3796 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
3797 0x95
3798 };
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003799 if (!spd_addrmap[2 * channel + slot])
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003800 continue;
3801 for (try = 0; try < 5; try++) {
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003802 v = smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003803 DEVICE_TYPE);
3804 if (v >= 0)
3805 break;
3806 }
3807 if (v < 0)
3808 continue;
3809 for (addr = 0;
3810 addr <
3811 sizeof(useful_addresses) /
3812 sizeof(useful_addresses[0]); addr++)
3813 gav(info.
3814 spd[channel][0][useful_addresses
3815 [addr]] =
Vladimir Serbinenko902626c2014-02-16 17:22:26 +01003816 smbus_read_byte(spd_addrmap[2 * channel + slot],
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003817 useful_addresses
3818 [addr]));
3819 if (info.spd[channel][0][DEVICE_TYPE] != 11)
3820 die("Only DDR3 is supported");
3821
3822 v = info.spd[channel][0][RANKS_AND_DQ];
3823 info.populated_ranks[channel][0][0] = 1;
3824 info.populated_ranks[channel][0][1] =
3825 ((v >> 3) & 7);
3826 if (((v >> 3) & 7) > 1)
3827 die("At most 2 ranks are supported");
3828 if ((v & 7) == 0 || (v & 7) > 2)
3829 die("Only x8 and x16 modules are supported");
3830 if ((info.
3831 spd[channel][slot][MODULE_TYPE] & 0xF) != 2
3832 && (info.
3833 spd[channel][slot][MODULE_TYPE] & 0xF)
3834 != 3)
3835 die("Registered memory is not supported");
3836 info.is_x16_module[channel][0] = (v & 7) - 1;
3837 info.density[channel][slot] =
3838 info.spd[channel][slot][DENSITY] & 0xF;
3839 if (!
3840 (info.
3841 spd[channel][slot][MEMORY_BUS_WIDTH] &
3842 0x18))
3843 info.use_ecc = 0;
3844 }
3845
3846 gav(0x55);
3847
3848 for (channel = 0; channel < NUM_CHANNELS; channel++) {
3849 int v = 0;
3850 for (slot = 0; slot < NUM_SLOTS; slot++)
3851 for (rank = 0; rank < NUM_RANKS; rank++)
3852 v |= info.
3853 populated_ranks[channel][slot][rank]
3854 << (2 * slot + rank);
3855 info.populated_ranks_mask[channel] = v;
3856 }
3857
3858 gav(0x55);
3859
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003860 gav(pci_read_config32(NORTHBRIDGE, D0F0_CAPID0 + 4));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003861 }
3862
3863 /* after SPD */
3864 timestamp_add_now(102);
3865
Felix Held04be2dd2018-07-29 04:53:22 +02003866 MCHBAR8_AND(0x2ca8, 0xfc);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003867
3868 collect_system_info(&info);
3869 calculate_timings(&info);
3870
Felix Held29a9c072018-07-29 01:34:45 +02003871#if 0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003872 pci_write_config8(NORTHBRIDGE, 0xdf, 0x82);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003873#endif
3874
3875 if (!s3resume) {
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003876 u8 reg8 = pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003877 if (x2ca8 == 0 && (reg8 & 0x80)) {
3878 /* Don't enable S4-assertion stretch. Makes trouble on roda/rk9.
3879 reg8 = pci_read_config8(PCI_DEV(0, 0x1f, 0), 0xa4);
3880 pci_write_config8(PCI_DEV(0, 0x1f, 0), 0xa4, reg8 | 0x08);
3881 */
3882
3883 /* Clear bit7. */
3884
3885 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3886 (reg8 & ~(1 << 7)));
3887
3888 printk(BIOS_INFO,
3889 "Interrupted RAM init, reset required.\n");
Elyes HAOUASd45f3382019-04-28 18:04:35 +02003890 system_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003891 }
3892 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003893
3894 if (!s3resume && x2ca8 == 0)
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003895 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
3896 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) | 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003897
3898 compute_derived_timings(&info);
3899
3900 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003901 gav(MCHBAR8(0x164));
3902 MCHBAR8(0x164) = 0x26;
3903 MCHBAR16(0x2c20) = 0x10;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003904 }
3905
Felix Held04be2dd2018-07-29 04:53:22 +02003906 MCHBAR32_OR(0x18b4, 0x210000);
3907 MCHBAR32_OR(0x1890, 0x2000000);
3908 MCHBAR32_OR(0x18b4, 0x8000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003909
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003910 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x50)); // !!!!
3911 pci_write_config8(PCI_DEV(0xff, 2, 1), 0x54, 0x12);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003912
Felix Held04be2dd2018-07-29 04:53:22 +02003913 gav(MCHBAR16(0x2c10));
3914 MCHBAR16(0x2c10) = 0x412;
3915 gav(MCHBAR16(0x2c10));
3916 MCHBAR16_OR(0x2c12, 0x100);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003917
Felix Held04be2dd2018-07-29 04:53:22 +02003918 gav(MCHBAR8(0x2ca8)); // !!!!
3919 MCHBAR32_AND_OR(0x1804, 0xfffffffc, 0x8400080);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003920
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003921 pci_read_config32(PCI_DEV(0xff, 2, 1), 0x6c); // !!!!
3922 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x6c, 0x40a0a0);
Felix Held04be2dd2018-07-29 04:53:22 +02003923 gav(MCHBAR32(0x1c04)); // !!!!
3924 gav(MCHBAR32(0x1804)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003925
3926 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003927 MCHBAR8_OR(0x2ca8, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003928 }
3929
Felix Held04be2dd2018-07-29 04:53:22 +02003930 MCHBAR32(0x18d8) = 0x120000;
3931 MCHBAR32(0x18dc) = 0x30a484a;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003932 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x0);
3933 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x9444a);
Felix Held04be2dd2018-07-29 04:53:22 +02003934 MCHBAR32(0x18d8) = 0x40000;
3935 MCHBAR32(0x18dc) = 0xb000000;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003936 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x60000);
3937 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x0);
Felix Held04be2dd2018-07-29 04:53:22 +02003938 MCHBAR32(0x18d8) = 0x180000;
3939 MCHBAR32(0x18dc) = 0xc0000142;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003940 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xe0, 0x20000);
3941 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xf4, 0x142);
Felix Held04be2dd2018-07-29 04:53:22 +02003942 MCHBAR32(0x18d8) = 0x1e0000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003943
Felix Held04be2dd2018-07-29 04:53:22 +02003944 gav(MCHBAR32(0x18dc)); // !!!!
3945 MCHBAR32(0x18dc) = 0x3;
3946 gav(MCHBAR32(0x18dc)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003947
3948 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003949 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003950 }
3951
Felix Held04be2dd2018-07-29 04:53:22 +02003952 MCHBAR32(0x188c) = 0x20bc09;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003953 pci_write_config32(PCI_DEV(0xff, 2, 1), 0xd0, 0x40b0c09);
Felix Held04be2dd2018-07-29 04:53:22 +02003954 MCHBAR32(0x1a10) = 0x4200010e;
3955 MCHBAR32_OR(0x18b8, 0x200);
3956 gav(MCHBAR32(0x1918)); // !!!!
3957 MCHBAR32(0x1918) = 0x332;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003958
Felix Held04be2dd2018-07-29 04:53:22 +02003959 gav(MCHBAR32(0x18b8)); // !!!!
3960 MCHBAR32(0x18b8) = 0xe00;
3961 gav(MCHBAR32(0x182c)); // !!!!
3962 MCHBAR32(0x182c) = 0x10202;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003963 gav(pci_read_config32(PCI_DEV(0xff, 2, 1), 0x94)); // !!!!
3964 pci_write_config32(PCI_DEV(0xff, 2, 1), 0x94, 0x10202);
Felix Held04be2dd2018-07-29 04:53:22 +02003965 MCHBAR32_AND(0x1a1c, 0x8fffffff);
3966 MCHBAR32_OR(0x1a70, 0x100000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003967
Felix Held04be2dd2018-07-29 04:53:22 +02003968 MCHBAR32_AND(0x18b4, 0xffff7fff);
3969 gav(MCHBAR32(0x1a68)); // !!!!
3970 MCHBAR32(0x1a68) = 0x343800;
3971 gav(MCHBAR32(0x1e68)); // !!!!
3972 gav(MCHBAR32(0x1a68)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003973
3974 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003975 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003976 }
3977
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03003978 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x048); // !!!!
3979 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x048, 0x140000);
3980 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3981 pci_write_config32(PCI_DEV(0xff, 2, 0), 0x058, 0x64555);
3982 pci_read_config32(PCI_DEV(0xff, 2, 0), 0x058); // !!!!
3983 pci_read_config32(PCI_DEV (0xff, 0, 0), 0xd0); // !!!!
3984 pci_write_config32(PCI_DEV (0xff, 0, 0), 0xd0, 0x180);
Felix Held04be2dd2018-07-29 04:53:22 +02003985 gav(MCHBAR32(0x1af0)); // !!!!
3986 gav(MCHBAR32(0x1af0)); // !!!!
3987 MCHBAR32(0x1af0) = 0x1f020003;
3988 gav(MCHBAR32(0x1af0)); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003989
Edward O'Callaghan42b716f2014-06-26 21:38:52 +10003990 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02003991 MCHBAR8_OR(0x2ca8, 1); // guess
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003992 }
3993
Felix Held04be2dd2018-07-29 04:53:22 +02003994 gav(MCHBAR32(0x1890)); // !!!!
3995 MCHBAR32(0x1890) = 0x80102;
3996 gav(MCHBAR32(0x18b4)); // !!!!
3997 MCHBAR32(0x18b4) = 0x216000;
3998 MCHBAR32(0x18a4) = 0x22222222;
3999 MCHBAR32(0x18a8) = 0x22222222;
4000 MCHBAR32(0x18ac) = 0x22222;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004001
4002 udelay(1000);
4003
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004004 info.cached_training = get_cached_training();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004005
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004006 if (x2ca8 == 0) {
4007 int j;
4008 if (s3resume && info.cached_training) {
4009 restore_274265(&info);
Arthur Heymansb3282092019-04-14 17:53:28 +02004010 printk(RAM_DEBUG, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004011 info.cached_training->reg2ca9_bit0);
4012 for (i = 0; i < 2; i++)
4013 for (j = 0; j < 3; j++)
Arthur Heymansb3282092019-04-14 17:53:28 +02004014 printk(RAM_DEBUG, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004015 i, j, info.cached_training->reg274265[i][j]);
4016 } else {
4017 set_274265(&info);
Arthur Heymansb3282092019-04-14 17:53:28 +02004018 printk(RAM_DEBUG, "reg2ca9_bit0 = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004019 info.training.reg2ca9_bit0);
4020 for (i = 0; i < 2; i++)
4021 for (j = 0; j < 3; j++)
Arthur Heymansb3282092019-04-14 17:53:28 +02004022 printk(RAM_DEBUG, "reg274265[%d][%d] = %x\n",
Vladimir Serbinenkof7a42de2014-01-09 11:10:04 +01004023 i, j, info.training.reg274265[i][j]);
4024 }
4025
4026 set_2dxx_series(&info, s3resume);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004027
4028 if (!(deven & 8)) {
Felix Heldf83d80b2018-07-29 05:30:30 +02004029 MCHBAR32_AND_OR(0x2cb0, 0, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004030 }
4031
4032 udelay(1000);
4033
4034 if (deven & 8) {
Felix Held04be2dd2018-07-29 04:53:22 +02004035 MCHBAR32_OR(0xff8, 0x1800);
Felix Heldf83d80b2018-07-29 05:30:30 +02004036 MCHBAR32_AND(0x2cb0, 0x00);
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004037 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4038 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4c);
4039 pci_read_config8(PCI_DEV (0, 0x2, 0x0), 0x4e);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004040
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004041 MCHBAR8(0x1150);
4042 MCHBAR8(0x1151);
4043 MCHBAR8(0x1022);
4044 MCHBAR8(0x16d0);
Felix Held04be2dd2018-07-29 04:53:22 +02004045 MCHBAR32(0x1300) = 0x60606060;
4046 MCHBAR32(0x1304) = 0x60606060;
4047 MCHBAR32(0x1308) = 0x78797a7b;
4048 MCHBAR32(0x130c) = 0x7c7d7e7f;
4049 MCHBAR32(0x1310) = 0x60606060;
4050 MCHBAR32(0x1314) = 0x60606060;
4051 MCHBAR32(0x1318) = 0x60606060;
4052 MCHBAR32(0x131c) = 0x60606060;
4053 MCHBAR32(0x1320) = 0x50515253;
4054 MCHBAR32(0x1324) = 0x54555657;
4055 MCHBAR32(0x1328) = 0x58595a5b;
4056 MCHBAR32(0x132c) = 0x5c5d5e5f;
4057 MCHBAR32(0x1330) = 0x40414243;
4058 MCHBAR32(0x1334) = 0x44454647;
4059 MCHBAR32(0x1338) = 0x48494a4b;
4060 MCHBAR32(0x133c) = 0x4c4d4e4f;
4061 MCHBAR32(0x1340) = 0x30313233;
4062 MCHBAR32(0x1344) = 0x34353637;
4063 MCHBAR32(0x1348) = 0x38393a3b;
4064 MCHBAR32(0x134c) = 0x3c3d3e3f;
4065 MCHBAR32(0x1350) = 0x20212223;
4066 MCHBAR32(0x1354) = 0x24252627;
4067 MCHBAR32(0x1358) = 0x28292a2b;
4068 MCHBAR32(0x135c) = 0x2c2d2e2f;
4069 MCHBAR32(0x1360) = 0x10111213;
4070 MCHBAR32(0x1364) = 0x14151617;
4071 MCHBAR32(0x1368) = 0x18191a1b;
4072 MCHBAR32(0x136c) = 0x1c1d1e1f;
4073 MCHBAR32(0x1370) = 0x10203;
4074 MCHBAR32(0x1374) = 0x4050607;
4075 MCHBAR32(0x1378) = 0x8090a0b;
4076 MCHBAR32(0x137c) = 0xc0d0e0f;
4077 MCHBAR8(0x11cc) = 0x4e;
4078 MCHBAR32(0x1110) = 0x73970404;
4079 MCHBAR32(0x1114) = 0x72960404;
4080 MCHBAR32(0x1118) = 0x6f950404;
4081 MCHBAR32(0x111c) = 0x6d940404;
4082 MCHBAR32(0x1120) = 0x6a930404;
4083 MCHBAR32(0x1124) = 0x68a41404;
4084 MCHBAR32(0x1128) = 0x66a21404;
4085 MCHBAR32(0x112c) = 0x63a01404;
4086 MCHBAR32(0x1130) = 0x609e1404;
4087 MCHBAR32(0x1134) = 0x5f9c1404;
4088 MCHBAR32(0x1138) = 0x5c961404;
4089 MCHBAR32(0x113c) = 0x58a02404;
4090 MCHBAR32(0x1140) = 0x54942404;
4091 MCHBAR32(0x1190) = 0x900080a;
4092 MCHBAR16(0x11c0) = 0xc40b;
4093 MCHBAR16(0x11c2) = 0x303;
4094 MCHBAR16(0x11c4) = 0x301;
Felix Heldf83d80b2018-07-29 05:30:30 +02004095 MCHBAR32_AND_OR(0x1190, 0, 0x8900080a);
Felix Held04be2dd2018-07-29 04:53:22 +02004096 MCHBAR32(0x11b8) = 0x70c3000;
4097 MCHBAR8(0x11ec) = 0xa;
4098 MCHBAR16(0x1100) = 0x800;
Felix Heldf83d80b2018-07-29 05:30:30 +02004099 MCHBAR32_AND_OR(0x11bc, 0, 0x1e84800);
Felix Held04be2dd2018-07-29 04:53:22 +02004100 MCHBAR16(0x11ca) = 0xfa;
4101 MCHBAR32(0x11e4) = 0x4e20;
4102 MCHBAR8(0x11bc) = 0xf;
4103 MCHBAR16(0x11da) = 0x19;
4104 MCHBAR16(0x11ba) = 0x470c;
4105 MCHBAR32(0x1680) = 0xe6ffe4ff;
4106 MCHBAR32(0x1684) = 0xdeffdaff;
4107 MCHBAR32(0x1688) = 0xd4ffd0ff;
4108 MCHBAR32(0x168c) = 0xccffc6ff;
4109 MCHBAR32(0x1690) = 0xc0ffbeff;
4110 MCHBAR32(0x1694) = 0xb8ffb0ff;
4111 MCHBAR32(0x1698) = 0xa8ff0000;
4112 MCHBAR32(0x169c) = 0xc00;
4113 MCHBAR32(0x1290) = 0x5000000;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004114 }
4115
Felix Held04be2dd2018-07-29 04:53:22 +02004116 MCHBAR32(0x124c) = 0x15040d00;
4117 MCHBAR32(0x1250) = 0x7f0000;
4118 MCHBAR32(0x1254) = 0x1e220004;
4119 MCHBAR32(0x1258) = 0x4000004;
4120 MCHBAR32(0x1278) = 0x0;
4121 MCHBAR32(0x125c) = 0x0;
4122 MCHBAR32(0x1260) = 0x0;
4123 MCHBAR32(0x1264) = 0x0;
4124 MCHBAR32(0x1268) = 0x0;
4125 MCHBAR32(0x126c) = 0x0;
4126 MCHBAR32(0x1270) = 0x0;
4127 MCHBAR32(0x1274) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004128 }
4129
4130 if ((deven & 8) && x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004131 MCHBAR16(0x1214) = 0x320;
4132 MCHBAR32(0x1600) = 0x40000000;
Felix Heldf83d80b2018-07-29 05:30:30 +02004133 MCHBAR32_AND_OR(0x11f4, 0, 0x10000000);
4134 MCHBAR16_AND_OR(0x1230, 0, 0x8000);
Felix Held04be2dd2018-07-29 04:53:22 +02004135 MCHBAR32(0x1400) = 0x13040020;
4136 MCHBAR32(0x1404) = 0xe090120;
4137 MCHBAR32(0x1408) = 0x5120220;
4138 MCHBAR32(0x140c) = 0x5120330;
4139 MCHBAR32(0x1410) = 0xe090220;
4140 MCHBAR32(0x1414) = 0x1010001;
4141 MCHBAR32(0x1418) = 0x1110000;
4142 MCHBAR32(0x141c) = 0x9020020;
4143 MCHBAR32(0x1420) = 0xd090220;
4144 MCHBAR32(0x1424) = 0x2090220;
4145 MCHBAR32(0x1428) = 0x2090330;
4146 MCHBAR32(0x142c) = 0xd090220;
4147 MCHBAR32(0x1430) = 0x1010001;
4148 MCHBAR32(0x1434) = 0x1110000;
4149 MCHBAR32(0x1438) = 0x11040020;
4150 MCHBAR32(0x143c) = 0x4030220;
4151 MCHBAR32(0x1440) = 0x1060220;
4152 MCHBAR32(0x1444) = 0x1060330;
4153 MCHBAR32(0x1448) = 0x4030220;
4154 MCHBAR32(0x144c) = 0x1010001;
4155 MCHBAR32(0x1450) = 0x1110000;
4156 MCHBAR32(0x1454) = 0x4010020;
4157 MCHBAR32(0x1458) = 0xb090220;
4158 MCHBAR32(0x145c) = 0x1090220;
4159 MCHBAR32(0x1460) = 0x1090330;
4160 MCHBAR32(0x1464) = 0xb090220;
4161 MCHBAR32(0x1468) = 0x1010001;
4162 MCHBAR32(0x146c) = 0x1110000;
4163 MCHBAR32(0x1470) = 0xf040020;
4164 MCHBAR32(0x1474) = 0xa090220;
4165 MCHBAR32(0x1478) = 0x1120220;
4166 MCHBAR32(0x147c) = 0x1120330;
4167 MCHBAR32(0x1480) = 0xa090220;
4168 MCHBAR32(0x1484) = 0x1010001;
4169 MCHBAR32(0x1488) = 0x1110000;
4170 MCHBAR32(0x148c) = 0x7020020;
4171 MCHBAR32(0x1490) = 0x1010220;
4172 MCHBAR32(0x1494) = 0x10210;
4173 MCHBAR32(0x1498) = 0x10320;
4174 MCHBAR32(0x149c) = 0x1010220;
4175 MCHBAR32(0x14a0) = 0x1010001;
4176 MCHBAR32(0x14a4) = 0x1110000;
4177 MCHBAR32(0x14a8) = 0xd040020;
4178 MCHBAR32(0x14ac) = 0x8090220;
4179 MCHBAR32(0x14b0) = 0x1111310;
4180 MCHBAR32(0x14b4) = 0x1111420;
4181 MCHBAR32(0x14b8) = 0x8090220;
4182 MCHBAR32(0x14bc) = 0x1010001;
4183 MCHBAR32(0x14c0) = 0x1110000;
4184 MCHBAR32(0x14c4) = 0x3010020;
4185 MCHBAR32(0x14c8) = 0x7090220;
4186 MCHBAR32(0x14cc) = 0x1081310;
4187 MCHBAR32(0x14d0) = 0x1081420;
4188 MCHBAR32(0x14d4) = 0x7090220;
4189 MCHBAR32(0x14d8) = 0x1010001;
4190 MCHBAR32(0x14dc) = 0x1110000;
4191 MCHBAR32(0x14e0) = 0xb040020;
4192 MCHBAR32(0x14e4) = 0x2030220;
4193 MCHBAR32(0x14e8) = 0x1051310;
4194 MCHBAR32(0x14ec) = 0x1051420;
4195 MCHBAR32(0x14f0) = 0x2030220;
4196 MCHBAR32(0x14f4) = 0x1010001;
4197 MCHBAR32(0x14f8) = 0x1110000;
4198 MCHBAR32(0x14fc) = 0x5020020;
4199 MCHBAR32(0x1500) = 0x5090220;
4200 MCHBAR32(0x1504) = 0x2071310;
4201 MCHBAR32(0x1508) = 0x2071420;
4202 MCHBAR32(0x150c) = 0x5090220;
4203 MCHBAR32(0x1510) = 0x1010001;
4204 MCHBAR32(0x1514) = 0x1110000;
4205 MCHBAR32(0x1518) = 0x7040120;
4206 MCHBAR32(0x151c) = 0x2090220;
4207 MCHBAR32(0x1520) = 0x70b1210;
4208 MCHBAR32(0x1524) = 0x70b1310;
4209 MCHBAR32(0x1528) = 0x2090220;
4210 MCHBAR32(0x152c) = 0x1010001;
4211 MCHBAR32(0x1530) = 0x1110000;
4212 MCHBAR32(0x1534) = 0x1010110;
4213 MCHBAR32(0x1538) = 0x1081310;
4214 MCHBAR32(0x153c) = 0x5041200;
4215 MCHBAR32(0x1540) = 0x5041310;
4216 MCHBAR32(0x1544) = 0x1081310;
4217 MCHBAR32(0x1548) = 0x1010001;
4218 MCHBAR32(0x154c) = 0x1110000;
4219 MCHBAR32(0x1550) = 0x1040120;
4220 MCHBAR32(0x1554) = 0x4051210;
4221 MCHBAR32(0x1558) = 0xd051200;
4222 MCHBAR32(0x155c) = 0xd051200;
4223 MCHBAR32(0x1560) = 0x4051210;
4224 MCHBAR32(0x1564) = 0x1010001;
4225 MCHBAR32(0x1568) = 0x1110000;
4226 MCHBAR16(0x1222) = 0x220a;
4227 MCHBAR16(0x123c) = 0x1fc0;
4228 MCHBAR16(0x1220) = 0x1388;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004229 }
4230
Felix Heldf83d80b2018-07-29 05:30:30 +02004231 MCHBAR32_AND_OR(0x2c80, 0, 0x1053688); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004232 MCHBAR32(0x1c04); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004233 MCHBAR32(0x1804) = 0x406080;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004234
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004235 MCHBAR8(0x2ca8);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004236
4237 if (x2ca8 == 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004238 MCHBAR8_AND(0x2ca8, ~3);
4239 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8) + 4; // "+" or "|"?
4240 MCHBAR32_OR(0x1af0, 0x10);
Patrick Georgi546953c2014-11-29 10:38:17 +01004241 halt();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004242 }
4243
Felix Held04be2dd2018-07-29 04:53:22 +02004244 MCHBAR8(0x2ca8) = MCHBAR8(0x2ca8);
Felix Heldf83d80b2018-07-29 05:30:30 +02004245 MCHBAR32_AND_OR(0x2c80, 0, 0x53688); // !!!!
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004246 pci_write_config32(PCI_DEV (0xff, 0, 0), 0x60, 0x20220);
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004247 MCHBAR16(0x2c20); // !!!!
4248 MCHBAR16(0x2c10); // !!!!
4249 MCHBAR16(0x2c00); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004250 MCHBAR16(0x2c00) = 0x8c0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004251 udelay(1000);
4252 write_1d0(0, 0x33d, 0, 0);
4253 write_500(&info, 0, 0, 0xb61, 0, 0);
4254 write_500(&info, 1, 0, 0xb61, 0, 0);
Felix Held04be2dd2018-07-29 04:53:22 +02004255 MCHBAR32(0x1a30) = 0x0;
4256 MCHBAR32(0x1a34) = 0x0;
4257 MCHBAR16(0x614) = 0xb5b | (info.populated_ranks[1][0][0] * 0x404) |
4258 (info.populated_ranks[0][0][0] * 0xa0);
4259 MCHBAR16(0x616) = 0x26a;
4260 MCHBAR32(0x134) = 0x856000;
4261 MCHBAR32(0x160) = 0x5ffffff;
Felix Heldf83d80b2018-07-29 05:30:30 +02004262 MCHBAR32_AND_OR(0x114, 0, 0xc2024440); // !!!!
4263 MCHBAR32_AND_OR(0x118, 0, 0x4); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004264 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004265 MCHBAR32(0x260 + (channel << 10)) = 0x30809ff |
4266 ((info.populated_ranks_mask[channel] & 3) << 20);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004267 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004268 MCHBAR16(0x31c + (channel << 10)) = 0x101;
Felix Held22ca8cb2018-07-29 05:09:44 +02004269 MCHBAR16(0x360 + (channel << 10)) = 0x909;
4270 MCHBAR16(0x3a4 + (channel << 10)) = 0x101;
Felix Held04be2dd2018-07-29 04:53:22 +02004271 MCHBAR16(0x3e8 + (channel << 10)) = 0x101;
4272 MCHBAR32(0x320 + (channel << 10)) = 0x29002900;
4273 MCHBAR32(0x324 + (channel << 10)) = 0x0;
4274 MCHBAR32(0x368 + (channel << 10)) = 0x32003200;
4275 MCHBAR16(0x352 + (channel << 10)) = 0x505;
4276 MCHBAR16(0x354 + (channel << 10)) = 0x3c3c;
4277 MCHBAR16(0x356 + (channel << 10)) = 0x1040;
4278 MCHBAR16(0x39a + (channel << 10)) = 0x73e4;
4279 MCHBAR16(0x3de + (channel << 10)) = 0x77ed;
4280 MCHBAR16(0x422 + (channel << 10)) = 0x1040;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004281 }
4282
4283 write_1d0(0x4, 0x151, 4, 1);
4284 write_1d0(0, 0x142, 3, 1);
4285 rdmsr(0x1ac); // !!!!
4286 write_500(&info, 1, 1, 0x6b3, 4, 1);
4287 write_500(&info, 1, 1, 0x6cf, 4, 1);
4288
4289 rmw_1d0(0x21c, 0x38, 0, 6, 1);
4290
4291 write_1d0(((!info.populated_ranks[1][0][0]) << 1) | ((!info.
4292 populated_ranks[0]
4293 [0][0]) << 0),
4294 0x1d1, 3, 1);
4295 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004296 MCHBAR16(0x38e + (channel << 10)) = 0x5f5f;
4297 MCHBAR16(0x3d2 + (channel << 10)) = 0x5f5f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004298 }
4299
4300 set_334(0);
4301
4302 program_base_timings(&info);
4303
Felix Held04be2dd2018-07-29 04:53:22 +02004304 MCHBAR8_OR(0x5ff, 0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004305
4306 write_1d0(0x2, 0x1d5, 2, 1);
4307 write_1d0(0x20, 0x166, 7, 1);
4308 write_1d0(0x0, 0xeb, 3, 1);
4309 write_1d0(0x0, 0xf3, 6, 1);
4310
4311 for (channel = 0; channel < NUM_CHANNELS; channel++)
4312 for (lane = 0; lane < 9; lane++) {
4313 u16 addr = 0x125 + get_lane_offset(0, 0, lane);
4314 u8 a;
4315 a = read_500(&info, channel, addr, 6); // = 0x20040080 //!!!!
4316 write_500(&info, channel, a, addr, 6, 1);
4317 }
4318
4319 udelay(1000);
4320
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004321 if (s3resume) {
4322 if (info.cached_training == NULL) {
4323 u32 reg32;
4324 printk(BIOS_ERR,
4325 "Couldn't find training data. Rebooting\n");
4326 reg32 = inl(DEFAULT_PMBASE + 0x04);
4327 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004328 full_reset();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004329 }
4330 int tm;
4331 info.training = *info.cached_training;
4332 for (tm = 0; tm < 4; tm++)
4333 for (channel = 0; channel < NUM_CHANNELS; channel++)
4334 for (slot = 0; slot < NUM_SLOTS; slot++)
4335 for (rank = 0; rank < NUM_RANKS; rank++)
4336 for (lane = 0; lane < 9; lane++)
4337 write_500(&info,
4338 channel,
4339 info.training.
4340 lane_timings
4341 [tm][channel]
4342 [slot][rank]
4343 [lane],
4344 get_timing_register_addr
4345 (lane, tm,
4346 slot, rank),
4347 9, 0);
4348 write_1d0(info.cached_training->reg_178, 0x178, 7, 1);
4349 write_1d0(info.cached_training->reg_10b, 0x10b, 6, 1);
4350 }
4351
Felix Heldf83d80b2018-07-29 05:30:30 +02004352 MCHBAR32_AND_OR(0x1f4, 0, 0x20000); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004353 MCHBAR32(0x1f0) = 0x1d000200;
Felix Heldf83d80b2018-07-29 05:30:30 +02004354 MCHBAR8_AND_OR(0x1f0, 0, 0x1); // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004355 MCHBAR8(0x1f0); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004356
4357 program_board_delay(&info);
4358
Felix Held04be2dd2018-07-29 04:53:22 +02004359 MCHBAR8(0x5ff) = 0x0;
4360 MCHBAR8(0x5ff) = 0x80;
4361 MCHBAR8(0x5f4) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004362
Felix Held04be2dd2018-07-29 04:53:22 +02004363 MCHBAR32_AND(0x130, 0xfffffffd); // | 2 when ?
Felix Held22ca8cb2018-07-29 05:09:44 +02004364 while (MCHBAR32(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004365 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004366 gav(read_1d0(0x14b, 7)); // = 0x81023100
4367 write_1d0(0x30, 0x14b, 7, 1);
4368 read_1d0(0xd6, 6); // = 0xfa008080 // !!!!
4369 write_1d0(7, 0xd6, 6, 1);
4370 read_1d0(0x328, 6); // = 0xfa018080 // !!!!
4371 write_1d0(7, 0x328, 6, 1);
4372
4373 for (channel = 0; channel < NUM_CHANNELS; channel++)
4374 set_4cf(&info, channel,
4375 info.populated_ranks[channel][0][0] ? 8 : 0);
4376
4377 read_1d0(0x116, 4); // = 0x4040432 // !!!!
4378 write_1d0(2, 0x116, 4, 1);
4379 read_1d0(0xae, 6); // = 0xe8088080 // !!!!
4380 write_1d0(0, 0xae, 6, 1);
4381 read_1d0(0x300, 4); // = 0x48088080 // !!!!
4382 write_1d0(0, 0x300, 6, 1);
Felix Heldf83d80b2018-07-29 05:30:30 +02004383 MCHBAR16_AND_OR(0x356, 0, 0x1040); // !!!!
4384 MCHBAR16_AND_OR(0x756, 0, 0x1040); // !!!!
Felix Held04be2dd2018-07-29 04:53:22 +02004385 MCHBAR32_AND(0x140, ~0x07000000);
4386 MCHBAR32_AND(0x138, ~0x07000000);
4387 MCHBAR32(0x130) = 0x31111301;
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004388 /* Wait until REG130b0 is 1. */
Felix Held22ca8cb2018-07-29 05:09:44 +02004389 while (MCHBAR32(0x130) & 1)
Vladimir Serbinenko25fc5322014-12-07 13:05:44 +01004390 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004391
4392 {
4393 u32 t;
4394 u8 val_a1;
4395 val_a1 = read_1d0(0xa1, 6); // = 0x1cf4040 // !!!!
4396 t = read_1d0(0x2f3, 6); // = 0x10a4040 // !!!!
4397 rmw_1d0(0x320, 0x07,
4398 (t & 4) | ((t & 8) >> 2) | ((t & 0x10) >> 4), 6, 1);
4399 rmw_1d0(0x14b, 0x78,
4400 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4401 4), 7,
4402 1);
4403 rmw_1d0(0xce, 0x38,
4404 ((((val_a1 >> 2) & 4) | (val_a1 & 8)) >> 2) | (val_a1 &
4405 4), 6,
4406 1);
4407 }
4408
4409 for (channel = 0; channel < NUM_CHANNELS; channel++)
4410 set_4cf(&info, channel,
4411 info.populated_ranks[channel][0][0] ? 9 : 1);
4412
4413 rmw_1d0(0x116, 0xe, 1, 4, 1); // = 0x4040432 // !!!!
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004414 MCHBAR32(0x144); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004415 write_1d0(2, 0xae, 6, 1);
4416 write_1d0(2, 0x300, 6, 1);
4417 write_1d0(2, 0x121, 3, 1);
4418 read_1d0(0xd6, 6); // = 0xfa00c0c7 // !!!!
4419 write_1d0(4, 0xd6, 6, 1);
4420 read_1d0(0x328, 6); // = 0xfa00c0c7 // !!!!
4421 write_1d0(4, 0x328, 6, 1);
4422
4423 for (channel = 0; channel < NUM_CHANNELS; channel++)
4424 set_4cf(&info, channel,
4425 info.populated_ranks[channel][0][0] ? 9 : 0);
4426
Felix Held04be2dd2018-07-29 04:53:22 +02004427 MCHBAR32(0x130) = 0x11111301 | (info.populated_ranks[1][0][0] << 30) |
4428 (info.populated_ranks[0][0][0] << 29);
Felix Held22ca8cb2018-07-29 05:09:44 +02004429 while (MCHBAR8(0x130) & 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004430 ;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004431 read_1d0(0xa1, 6); // = 0x1cf4054 // !!!!
4432 read_1d0(0x2f3, 6); // = 0x10a4054 // !!!!
4433 read_1d0(0x21c, 6); // = 0xafa00c0 // !!!!
4434 write_1d0(0, 0x21c, 6, 1);
4435 read_1d0(0x14b, 7); // = 0x810231b0 // !!!!
4436 write_1d0(0x35, 0x14b, 7, 1);
4437
4438 for (channel = 0; channel < NUM_CHANNELS; channel++)
4439 set_4cf(&info, channel,
4440 info.populated_ranks[channel][0][0] ? 0xb : 0x2);
4441
4442 set_334(1);
4443
Felix Held04be2dd2018-07-29 04:53:22 +02004444 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004445
4446 for (channel = 0; channel < NUM_CHANNELS; channel++) {
4447 write_500(&info, channel,
4448 0x3 & ~(info.populated_ranks_mask[channel]), 0x6b7, 2,
4449 1);
4450 write_500(&info, channel, 0x3, 0x69b, 2, 1);
4451 }
Felix Held04be2dd2018-07-29 04:53:22 +02004452 MCHBAR32_AND_OR(0x2d0, 0xff2c01ff, 0x200000);
4453 MCHBAR16(0x6c0) = 0x14a0;
4454 MCHBAR32_AND_OR(0x6d0, 0xff0080ff, 0x8000);
4455 MCHBAR16(0x232) = 0x8;
4456 /* 0x40004 or 0 depending on ? */
4457 MCHBAR32_AND_OR(0x234, 0xfffbfffb, 0x40004);
4458 MCHBAR32_AND_OR(0x34, 0xfffffffd, 5);
4459 MCHBAR32(0x128) = 0x2150d05;
4460 MCHBAR8(0x12c) = 0x1f;
4461 MCHBAR8(0x12d) = 0x56;
4462 MCHBAR8(0x12e) = 0x31;
4463 MCHBAR8(0x12f) = 0x0;
4464 MCHBAR8(0x271) = 0x2;
4465 MCHBAR8(0x671) = 0x2;
4466 MCHBAR8(0x1e8) = 0x4;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004467 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held04be2dd2018-07-29 04:53:22 +02004468 MCHBAR32(0x294 + (channel << 10)) =
4469 (info.populated_ranks_mask[channel] & 3) << 16;
4470 MCHBAR32_AND_OR(0x134, 0xfc01ffff, 0x10000);
4471 MCHBAR32_AND_OR(0x134, 0xfc85ffff, 0x850000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004472 for (channel = 0; channel < NUM_CHANNELS; channel++)
Felix Held22ca8cb2018-07-29 05:09:44 +02004473 MCHBAR32_AND_OR(0x260 + (channel << 10), ~0xf00000, 0x8000000 |
4474 ((info.populated_ranks_mask[channel] & 3) << 20));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004475
4476 if (!s3resume)
4477 jedec_init(&info);
4478
4479 int totalrank = 0;
4480 for (channel = 0; channel < NUM_CHANNELS; channel++)
4481 for (slot = 0; slot < NUM_SLOTS; slot++)
4482 for (rank = 0; rank < NUM_RANKS; rank++)
4483 if (info.populated_ranks[channel][slot][rank]) {
4484 jedec_read(&info, channel, slot, rank,
4485 totalrank, 0xa, 0x400);
4486 totalrank++;
4487 }
4488
Felix Held04be2dd2018-07-29 04:53:22 +02004489 MCHBAR8(0x12c) = 0x9f;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004490
Felix Heldf83d80b2018-07-29 05:30:30 +02004491 MCHBAR8_AND_OR(0x271, 0, 0xe); // 2 // !!!!
4492 MCHBAR8_AND_OR(0x671, 0, 0xe); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004493
4494 if (!s3resume) {
4495 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004496 MCHBAR32(0x294 + (channel << 10)) =
4497 (info.populated_ranks_mask[channel] & 3) << 16;
4498 MCHBAR16(0x298 + (channel << 10)) =
4499 info.populated_ranks[channel][0][0] |
4500 (info.populated_ranks[channel][0][1] << 5);
4501 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004502 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004503 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004504
4505 {
4506 u8 a, b;
Felix Held04be2dd2018-07-29 04:53:22 +02004507 a = MCHBAR8(0x243);
4508 b = MCHBAR8(0x643);
4509 MCHBAR8(0x243) = a | 2;
4510 MCHBAR8(0x643) = b | 2;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004511 }
4512
4513 write_1d0(7, 0x19b, 3, 1);
4514 write_1d0(7, 0x1c0, 3, 1);
4515 write_1d0(4, 0x1c6, 4, 1);
4516 write_1d0(4, 0x1cc, 4, 1);
4517 read_1d0(0x151, 4); // = 0x408c6d74 // !!!!
4518 write_1d0(4, 0x151, 4, 1);
Felix Held04be2dd2018-07-29 04:53:22 +02004519 MCHBAR32(0x584) = 0xfffff;
4520 MCHBAR32(0x984) = 0xfffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004521
4522 for (channel = 0; channel < NUM_CHANNELS; channel++)
4523 for (slot = 0; slot < NUM_SLOTS; slot++)
4524 for (rank = 0; rank < NUM_RANKS; rank++)
4525 if (info.
4526 populated_ranks[channel][slot]
4527 [rank])
4528 config_rank(&info, s3resume,
4529 channel, slot,
4530 rank);
4531
Felix Held04be2dd2018-07-29 04:53:22 +02004532 MCHBAR8(0x243) = 0x1;
4533 MCHBAR8(0x643) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004534 }
4535
4536 /* was == 1 but is common */
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004537 pci_write_config16(NORTHBRIDGE, 0xc8, 3);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004538 write_26c(0, 0x820);
4539 write_26c(1, 0x820);
Felix Held04be2dd2018-07-29 04:53:22 +02004540 MCHBAR32_OR(0x130, 2);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004541 /* end */
4542
4543 if (s3resume) {
4544 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004545 MCHBAR32(0x294 + (channel << 10)) =
4546 (info.populated_ranks_mask[channel] & 3) << 16;
4547 MCHBAR16(0x298 + (channel << 10)) =
4548 info.populated_ranks[channel][0][0] |
4549 (info.populated_ranks[channel][0][1] << 5);
4550 MCHBAR32(0x29c + (channel << 10)) = 0x77a;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004551 }
Felix Heldf83d80b2018-07-29 05:30:30 +02004552 MCHBAR32_AND_OR(0x2c0, 0, 0x6009cc00); // !!!!
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004553 }
4554
Felix Held04be2dd2018-07-29 04:53:22 +02004555 MCHBAR32_AND(0xfa4, ~0x01000002);
4556 MCHBAR32(0xfb0) = 0x2000e019;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004557
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004558 /* Before training. */
4559 timestamp_add_now(103);
4560
4561 if (!s3resume)
4562 ram_training(&info);
4563
4564 /* After training. */
Paul Menzel9e817bf2015-05-28 07:32:48 +02004565 timestamp_add_now(104);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004566
4567 dump_timings(&info);
4568
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004569 program_modules_memory_map(&info, 0);
4570 program_total_memory_map(&info);
4571
4572 if (info.non_interleaved_part_mb != 0 && info.interleaved_part_mb != 0)
Felix Held04be2dd2018-07-29 04:53:22 +02004573 MCHBAR8(0x111) = 0x20 | (0 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004574 else if (have_match_ranks(&info, 0, 4) && have_match_ranks(&info, 1, 4))
Felix Held04be2dd2018-07-29 04:53:22 +02004575 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (1 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004576 else if (have_match_ranks(&info, 0, 2) && have_match_ranks(&info, 1, 2))
Felix Held04be2dd2018-07-29 04:53:22 +02004577 MCHBAR8(0x111) = 0x20 | (3 << 2) | (0 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004578 else
Felix Held04be2dd2018-07-29 04:53:22 +02004579 MCHBAR8(0x111) = 0x20 | (3 << 2) | (1 << 6) | (0 << 7);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004580
Felix Held04be2dd2018-07-29 04:53:22 +02004581 MCHBAR32_AND(0xfac, ~0x80000000);
4582 MCHBAR32(0xfb4) = 0x4800;
4583 MCHBAR32(0xfb8) = (info.revision < 8) ? 0x20 : 0x0;
4584 MCHBAR32(0xe94) = 0x7ffff;
4585 MCHBAR32(0xfc0) = 0x80002040;
4586 MCHBAR32(0xfc4) = 0x701246;
4587 MCHBAR8_AND(0xfc8, ~0x70);
4588 MCHBAR32_OR(0xe5c, 0x1000000);
4589 MCHBAR32_AND_OR(0x1a70, ~0x00100000, 0x00200000);
4590 MCHBAR32(0x50) = 0x700b0;
4591 MCHBAR32(0x3c) = 0x10;
4592 MCHBAR8(0x1aa8) = (MCHBAR8(0x1aa8) & ~0x35) | 0xa;
4593 MCHBAR8_OR(0xff4, 0x2);
4594 MCHBAR32_AND_OR(0xff8, ~0xe008, 0x1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004595
Felix Held29a9c072018-07-29 01:34:45 +02004596#if 1
Felix Held04be2dd2018-07-29 04:53:22 +02004597 MCHBAR32(0xd00) = IOMMU_BASE2 | 1;
4598 MCHBAR32(0xd40) = IOMMU_BASE1 | 1;
4599 MCHBAR32(0xdc0) = IOMMU_BASE4 | 1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004600
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004601 write32p(IOMMU_BASE1 | 0xffc, 0x80000000);
4602 write32p(IOMMU_BASE2 | 0xffc, 0xc0000000);
4603 write32p(IOMMU_BASE4 | 0xffc, 0x80000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004604
4605#else
4606 {
4607 u32 eax;
Felix Held04be2dd2018-07-29 04:53:22 +02004608 // = 0xe911714b
4609 eax = read32p(0xffc + (MCHBAR32(0xd00) & ~1)) | 0x08000000;
4610 write32p(0xffc + (MCHBAR32(0xd00) & ~1), eax);
4611 // = 0xe911714b
4612 eax = read32p(0xffc + (MCHBAR32(0xdc0) & ~1)) | 0x40000000;
4613 write32p(0xffc + (MCHBAR32(0xdc0) & ~1), eax);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004614 }
4615#endif
4616
4617 {
4618 u32 eax;
4619
4620 eax = info.fsb_frequency / 9;
Felix Held04be2dd2018-07-29 04:53:22 +02004621 MCHBAR32_AND_OR(0xfcc, 0xfffc0000,
4622 (eax * 0x280) | (eax * 0x5000) | eax | 0x40000);
4623 MCHBAR32(0x20) = 0x33001;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004624 }
4625
4626 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004627 MCHBAR32_AND(0x220 + (channel << 10), ~0x7770);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004628 if (info.max_slots_used_in_channel == 1)
Felix Held04be2dd2018-07-29 04:53:22 +02004629 MCHBAR16_OR(0x237 + (channel << 10), 0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004630 else
Felix Held04be2dd2018-07-29 04:53:22 +02004631 MCHBAR16_AND(0x237 + (channel << 10), ~0x0201);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004632
Felix Held04be2dd2018-07-29 04:53:22 +02004633 MCHBAR8_OR(0x241 + (channel << 10), 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004634
Felix Held04be2dd2018-07-29 04:53:22 +02004635 if (info.clock_speed_index <= 1 && (info.silicon_revision == 2
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004636 || info.silicon_revision == 3))
Felix Held04be2dd2018-07-29 04:53:22 +02004637 MCHBAR32_OR(0x248 + (channel << 10), 0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004638 else
Felix Held04be2dd2018-07-29 04:53:22 +02004639 MCHBAR32_AND(0x248 + (channel << 10), ~0x00102000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004640 }
4641
Felix Held04be2dd2018-07-29 04:53:22 +02004642 MCHBAR32_OR(0x115, 0x1000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004643
4644 {
4645 u8 al;
4646 al = 0xd;
4647 if (!(info.silicon_revision == 0 || info.silicon_revision == 1))
4648 al += 2;
4649 al |= ((1 << (info.max_slots_used_in_channel - 1)) - 1) << 4;
Felix Held04be2dd2018-07-29 04:53:22 +02004650 MCHBAR32(0x210) = (al << 16) | 0x20;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004651 }
4652
4653 for (channel = 0; channel < NUM_CHANNELS; channel++) {
Felix Held04be2dd2018-07-29 04:53:22 +02004654 MCHBAR32(0x288 + (channel << 10)) = 0x70605040;
4655 MCHBAR32(0x28c + (channel << 10)) = 0xfffec080;
4656 MCHBAR32(0x290 + (channel << 10)) = 0x282091c |
4657 ((info.max_slots_used_in_channel - 1) << 0x16);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004658 }
4659 u32 reg1c;
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004660 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004661 reg1c = read32p(DEFAULT_EPBAR | 0x01c); // = 0x8001 // OK
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004662 pci_read_config32(NORTHBRIDGE, 0x40); // = DEFAULT_EPBAR | 0x001 // OK
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -08004663 write32p(DEFAULT_EPBAR | 0x01c, reg1c); // OK
Elyes HAOUAS97642c22019-05-22 20:53:25 +02004664 MCHBAR8(0xe08); // = 0x0
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004665 pci_read_config32(NORTHBRIDGE, 0xe4); // = 0x316126
Felix Held04be2dd2018-07-29 04:53:22 +02004666 MCHBAR8_OR(0x1210, 2);
4667 MCHBAR32(0x1200) = 0x8800440;
4668 MCHBAR32(0x1204) = 0x53ff0453;
4669 MCHBAR32(0x1208) = 0x19002043;
4670 MCHBAR16(0x1214) = 0x320;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004671
4672 if (info.revision == 0x10 || info.revision == 0x11) {
Felix Held04be2dd2018-07-29 04:53:22 +02004673 MCHBAR16(0x1214) = 0x220;
4674 MCHBAR8_OR(0x1210, 0x40);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004675 }
4676
Felix Held04be2dd2018-07-29 04:53:22 +02004677 MCHBAR8_OR(0x1214, 0x4);
4678 MCHBAR8(0x120c) = 0x1;
4679 MCHBAR8(0x1218) = 0x3;
4680 MCHBAR8(0x121a) = 0x3;
4681 MCHBAR8(0x121c) = 0x3;
4682 MCHBAR16(0xc14) = 0x0;
4683 MCHBAR16(0xc20) = 0x0;
4684 MCHBAR32(0x1c) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004685
4686 /* revision dependent here. */
4687
Felix Held04be2dd2018-07-29 04:53:22 +02004688 MCHBAR16_OR(0x1230, 0x1f07);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004689
4690 if (info.uma_enabled)
Felix Held04be2dd2018-07-29 04:53:22 +02004691 MCHBAR32_OR(0x11f4, 0x10000000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004692
Felix Held04be2dd2018-07-29 04:53:22 +02004693 MCHBAR16_OR(0x1230, 0x8000);
4694 MCHBAR8_OR(0x1214, 1);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004695
4696 u8 bl, ebpb;
4697 u16 reg_1020;
4698
Felix Held04be2dd2018-07-29 04:53:22 +02004699 reg_1020 = MCHBAR32(0x1020); // = 0x6c733c // OK
4700 MCHBAR8(0x1070) = 0x1;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004701
Felix Held04be2dd2018-07-29 04:53:22 +02004702 MCHBAR32(0x1000) = 0x100;
4703 MCHBAR8(0x1007) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004704
4705 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004706 MCHBAR16(0x1018) = 0x0;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004707 bl = reg_1020 >> 8;
4708 ebpb = reg_1020 & 0xff;
4709 } else {
4710 ebpb = 0;
4711 bl = 8;
4712 }
4713
4714 rdmsr(0x1a2);
4715
Felix Held04be2dd2018-07-29 04:53:22 +02004716 MCHBAR32(0x1014) = 0xffffffff;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004717
Felix Held04be2dd2018-07-29 04:53:22 +02004718 MCHBAR32(0x1010) = ((((ebpb + 0x7d) << 7) / bl) & 0xff) * (!!reg_1020);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004719
Felix Held04be2dd2018-07-29 04:53:22 +02004720 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004721
Felix Held04be2dd2018-07-29 04:53:22 +02004722 MCHBAR8(0x123e) = (MCHBAR8(0x123e) & 0xf) | 0x60;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004723 if (reg_1020 != 0) {
Felix Held04be2dd2018-07-29 04:53:22 +02004724 MCHBAR32_AND_OR(0x123c, ~0x00900000, 0x600000);
4725 MCHBAR8(0x101c) = 0xb8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004726 }
4727
4728 setup_heci_uma(&info);
4729
4730 if (info.uma_enabled) {
4731 u16 ax;
Felix Held04be2dd2018-07-29 04:53:22 +02004732 MCHBAR32_OR(0x11b0, 0x4000);
4733 MCHBAR32_OR(0x11b4, 0x4000);
4734 MCHBAR16_OR(0x1190, 0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004735
Felix Held04be2dd2018-07-29 04:53:22 +02004736 ax = MCHBAR16(0x1190) & 0xf00; // = 0x480a // OK
4737 MCHBAR16(0x1170) = ax | (MCHBAR16(0x1170) & 0x107f) | 0x4080;
4738 MCHBAR16_OR(0x1170, 0x1000);
4739
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004740 udelay(1000);
Felix Held29a9c072018-07-29 01:34:45 +02004741
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004742 u16 ecx;
Felix Held22ca8cb2018-07-29 05:09:44 +02004743 for (ecx = 0xffff; ecx && (MCHBAR16(0x1170) & 0x1000); ecx--)
Felix Held04be2dd2018-07-29 04:53:22 +02004744 ;
4745 MCHBAR16_AND(0x1190, ~0x4000);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004746 }
4747
Kyösti Mälkkid45114f2013-07-26 08:53:59 +03004748 pci_write_config8(SOUTHBRIDGE, GEN_PMCON_2,
4749 pci_read_config8(SOUTHBRIDGE, GEN_PMCON_2) & ~0x80);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004750 udelay(10000);
Felix Held04be2dd2018-07-29 04:53:22 +02004751 MCHBAR16(0x2ca8) = 0x8;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004752
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004753 udelay(1000);
4754 dump_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004755 cbmem_wasnot_inited = cbmem_recovery(s3resume);
4756
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004757 if (!s3resume)
4758 save_timings(&info);
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004759 if (s3resume && cbmem_wasnot_inited) {
4760 u32 reg32;
4761 printk(BIOS_ERR, "Failed S3 resume.\n");
4762 ram_check(0x100000, 0x200000);
4763
4764 /* Clear SLP_TYPE. */
4765 reg32 = inl(DEFAULT_PMBASE + 0x04);
4766 outl(reg32 & ~(7 << 10), DEFAULT_PMBASE + 0x04);
4767
4768 /* Failed S3 resume, reset to come up cleanly */
Elyes HAOUASd45f3382019-04-28 18:04:35 +02004769 full_reset();
Vladimir Serbinenkob16f0922014-06-07 16:27:27 +02004770 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01004771}